【问题标题】:Compare csv file data to a dictionary items in Python将 csv 文件数据与 Python 中的字典项进行比较
【发布时间】:2020-03-07 02:52:02
【问题描述】:

我需要将 dict 的 key(DNA_Base) 和 value(number) 与 csv 文件的一些数据进行比较并打印匹配的数据。 问题是 csv 文件有 3 个东西一个人名,一个字符串(DNA_Base)和一个数字它应该打印具有此特定DNA_Base 的特定编号的人的姓名。我想比较的字典是STR_max 应该是这样的

STR_max = {'AATG': 8 , 'TATC': 10 , 'AGATC': 9 , 'AGAG': 13}

所以它应该为这个 csv 文件打印 Alice,如果没有匹配将打印一些文本

名称,AGATC,AATG,TATC 爱丽丝,2,8,3 鲍勃,4,1,5 查理,3,2,5

这是我的代码

import sys
from sys import argv
import csv

#check correct command line argument
if len(sys.argv) != 3:
    print("Usage: python dna.py data.csv sequence.txt")
    exit(1)

#get the file path from the command line argument
csv_path = argv[1]
seq_path = argv[2]


# Opens csv file
with open(csv_path, newline='') as csvfile:
    readcsv = csv.reader(csvfile)

# Gets accsess to STR names
    csv_rows = list(readcsv)
    str_names = csv_rows[0]

# Opens the DNA sequence
seqtxt = open(seq_path, "r")
str_seq = seqtxt.read()

#Dict so store the counting of str
STR_max = {}

#iterate over the STR of the database
for str_name in str_names[1:]:
    maxCount = 0
    actualCount = 0
    str_name_len = len(str_name)
    str_seq_len = len(str_seq)
    i = 0
    found = False

    #iterate over the DNA Seq and count the str_name
    while i < str_seq_len:
        #find the STR in range of str_name[i : i+str_name_len]
        find = str_seq.count(str_names, i, i + str_name_len)

        #if the 1st STR found then start counting from it
        if find > 0 and found == False:
            actualCount = 1
            i = i + str_name_len
            found = True

        #if another STR is found again next to the previous one
        elif find > 0 and found == True:
            actualCount += 1
            i = i + str_name_len

        else:
            i += 1
            found = False

        if actualCount > maxCount:
            maxCount = actualCount


    #adding the STR and its maxCount to a buffer dict
    STR_max[str_name] = maxCount

【问题讨论】:

  • 你的问题是什么?
  • 如何将字典的这些项目与csv文件的数据进行比较,并提取匹配的名称
  • 您具体在哪个部分苦苦挣扎?
  • 该部分未包含在代码中,因为我不知道该怎么做,所以我的问题是如何将字典中的项目与 csv 文件的数据进行比较跨度>

标签: python csv dictionary


【解决方案1】:

您本质上需要的是对于 STR_max 中的每个序列,您要向下查看该列,如果它的值匹配,则返回该行的人的姓名。我确信有一些库可以让这变得更容易,但我只想编写一些帮助函数,让您访问所需的数据。

#for each kmer in STR_max we need to know the csv column it corresponds to
# returns { "AGATC": 1, "AATG": 2,...}
def kmer_to_column_map():
    with open( 'test.csv' ) as csv:
        for line in csv:
            return { kmer: i for i, kmer in enumerate(line.strip().split(",")) }

#Then we need to get the column data from the csv file. Write a helper function that extracts a column from the csv file
#make a function to extract a column of values from the csv file 

#returns the list of values from a column given an index
def get_csv_column( column_index ):
    column = []
    with open( "test.csv" ) as csv:
        for i, line in enumerate(csv):
            if i == 0: continue 
            column.append( line.strip().split(",")[column_index] )
    return column

#now we lets grab what we need to iterate through kmers and print the names 
STR_max = {'AATG': 8 , 'TATC': 10 , 'AGATC': 9 , 'AGAG': 13}
names = get_csv_column(0)

for kmer, value in STR_max.items():
    # don't print if there is no data in csv file with this kmer
    if kmer not in kmer_map: continue 
    
    #get the column number in the csv file for this kmer 
    column_index = kmer_map[kmer]  
    
    #get the column data for this kmer - note that names and values have the same indices.
    values       = get_csv_column( column_index )
    
    #find the column values that are equal to STR_max value - i is the index of the value that matches which will be the index in names of the name that matches
    matches = [ i for i, patientval in enumerate( values ) if value == int(patientval)]

    #print the name of the person for each match - 
    if matches:
        print( kmer )
        for match in matches:
            print( f"-> {names[match]}" )
        print()

请注意,每次需要列时,我都会打开文件。您可以重写它以一次全部上传文件,但我知道序列数据可能很大。通过使用关键字“with”打开文件,文件会以可迭代的形式打开并逐行搜索,而无需加载整个文件。

更新

针对您的问题(抱歉重读,我意识到我的 cmets 有点差)

get_kmer_map 返回kmer_map,它唯一做的就是获取 .csv 文件第一行中的 kmers 并返回一个以列号作为键的字典。对于 csv 文件,它将类似于...

kmer_map = {
    "AGATC": 1,
    "AATG": 2,
    "TATC": 3 
}

一旦我们有了列号,我们就使用get_csv_column 来获取行。例如:

get_csv_column( 2 )
#[8, 1, 2] <- 2nd column from csv file

或等效

get_csv_column( kmer_map['AATG'] )
#[8,1,2]

然后我们遍历 STR_MAX 的键以确定 .csv 文件中是否存在该 kmer 的列。在这种情况下,STR_MAX "AGAG" 的最后一个元素不在 csv 文件中,因此不会与患者有任何匹配,因此行:

if kmer not in kmer_map: continue 

跳过寻找匹配项(并防止索引错误)。

如果 kmer 在 csv 文件中,我们需要知道列号以便获取值。

column_index = kmer_map[kmer] #<-returns column 2 for kmer_map['AATG']

然后我们得到指定kmer的数据列

values       = get_csv_column( column_index )
# get_csv_column(2) = [ 8, 1, 2]

如果有匹配,它将在值中。 我们最不需要的就是名字

names = get_csv_column( names )

#Now we have two list where the index of Alice is the same index for ALices value for that kmer.
#for kmer="AATG"
#values: [ 8, 1, 2 ]
#names:  [ Alice, Bob, Charlie]

最后,我们检查 STR_MAX 的值是否有任何匹配项,如果是,则找到匹配项的索引,并打印 names[index] ,这就是您想要的答案。我使用列表推导将这个逻辑放在一行中。

matches = [ i for i, patientval in enumerate( values ) if value == int(patientval)]

为了清楚起见,可以改写如下

matches = []
for i, patientval in enumerate( values ):
    if patientval == value:
        matches.append( i )

对于“AATG”的情况,STR_MAX 值为 8,它匹配索引 0 处的值 [8,1,2],并且名称中索引 0 处的名称是 Alice。

希望有帮助

【讨论】:

  • 感谢您的努力,我很感激。我会试一试的。
  • 你能解释一下这行if kmer not in kmer_map: continue和这里column_index = kmer_map[kmer] 中的kmer_map是什么
【解决方案2】:

抽出时间先观看有关循环播放的视频,这将为您节省时间并在未来保持理智。 https://www.youtube.com/watch?v=EnSu9hHGq5o

看起来这是一个玩具问题,您应该熟悉称为“trie”的算法,它将帮助您同时在一个 DNA 序列中搜索多个字符串,而不是这种三重嵌套 for 循环。它将在 N^3 时间内运行。

这是一个例子: https://towardsdatascience.com/implementing-a-trie-data-structure-in-python-in-less-than-100-lines-of-code-a877ea23c1a1

【讨论】:

  • 太棒了!谢谢,我会看的,看看我能不能弄清楚。我是编程初学者,对python还不熟悉
【解决方案3】:

使用 Dict.reader

with open(csv_path, newline='') as csvfile:
        readcsv = csv.Dictreader(csvfile)
        for row in dict1:
            Found = False
            for i in range(1,len(readcsv.fieldnames)):
            
                if (row[readcsv.fieldnames[i]]==STR_max[readcsv.fieldnames[i]]):
                   Found = True
              
                else : 
                   Found = False
                   break
            if Found:
               print(row['name'])
               break
        if not Found: print("No match")

这将从第二列开始比较 csvfile(csvreader) 的字段名与 STR_max 字典的值。这是因为 STR_max 的键值与 csv 的字段名相同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-21
    • 1970-01-01
    • 1970-01-01
    • 2017-07-14
    • 1970-01-01
    • 2016-10-18
    • 1970-01-01
    • 2018-09-10
    相关资源
    最近更新 更多