2014-10-10 105 views
2

我试图让字典(程序的第一部分生成)写入到csv,以便我可以对excel中的数据执行进一步的操作。我意识到代码效率不高,但在这一点上,我只是喜欢它的工作。我可以在以后加速处理它。将字典数组写入CSV

import csv 
import pprint 

raw_data = csv.DictReader(open("/Users/David/Desktop/crimestats/crimeincidentdata.csv", "r")) 

neighborhood = [] 
place_count = {} 
stats = [] 

for row in raw_data: 
    neighborhood.append(row["Neighborhood"]) 

for place in set(neighborhood): 
    place_count.update({place:0}) 

for key,value in place_count.items(): 
    for place in neighborhood: 
     if key == place: 
      place_count[key] = place_count[key]+1 

for key in place_count: 
    stats.append([{"Location":str(key)},{"Volume":str(place_count[key])}]) 

pp = pprint.PrettyPrinter(indent=4) 
pp.pprint(stats) 

程序仍在这里很好运行的是由pprint输出

[ [{'Location': 'LINNTON'}, {'Volume': '109'}], 
    [{'Location': 'SUNDERLAND'}, {'Volume': '118'}], 
    [{'Location': 'KENTON'}, {'Volume': '715'}] 

这是错误肯定是发生了明显。该程序将头文件写入csv,然后抛出ValueError。

fieldnames = ['Location', 'Volume'] 
with open('/Users/David/Desktop/crimestats/localdata.csv', 'w', newline='') as output_file: 
    csvwriter = csv.DictWriter(output_file, delimiter=',', fieldnames=fieldnames, dialect='excel') 
    csvwriter.writeheader() 
for row in stats: 
    csvwriter.writerow(row) 
output_file.close() 

我花了相当多的时间来搜索这个问题,但没有一个我试图使用的建议都工作过。我想我必须要失去一些东西,所以我非常感谢任何和所有的帮助。

Traceback (most recent call last): 
    File "/Users/David/Desktop/crimestats/statsreader.py", line 34, in <module> 
    csvwriter.writerow(row) 
    File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/csv.py", line 153, in writerow 
    return self.writer.writerow(self._dict_to_list(rowdict)) 
    File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/csv.py", line 149, in _dict_to_list 
+ ", ".join([repr(x) for x in wrong_fields])) 
ValueError: dict contains fields not in fieldnames: {'Location': 'SABIN'}, {'Volume': '247'} 

回答

1

我相信你的问题是在这里:

for key in place_count: 
    stats.append([{"Location":str(key)},{"Volume":str(place_count[key])}]) 

这是创建的词典列表。第一个只有一个“位置”键,第二个只有一个“音量”键。但是,csv.DictWriter对象期望每行包含单个字典,并包含字典中的所有键。将该代码片段更改为以下内容,它应该可以工作:

for key in place_count: 
    stats.append({"Location": str(key), "Volume": str(place_count[key])}) 

这应该照顾您所看到的错误。

现在,至于为什么错误消息是抱怨字段不在字段名称中,这完全误导了您远离真正的问题:writerow()函数期望获取字典作为其行参数,重新传递一个列表。结果令人困惑:它在for循环中遍历字典,期望获得字典的键(因为这是您在Python中对dict进行迭代时得到的结果),并将这些键与fieldnames列表中的值进行比较。它期望看到的是:

"Location" 
"Volume" 

以任意顺序(因为Python字典不能保证它将返回其键的顺序)。他们希望你通过fieldnames列表的原因是,这些字段可以按照正确的顺序写入CSV。但是,因为,您将在两个库的列表,当它遍历的row参数,它得到了以下内容:

{'Location': 'SABIN'} 
{'Volume': '247'} 

现在,词典{'Location': 'SABIN'}不等于字符串"Location",和字典{'Volume': '247'}不等于字符串"Volume",因此writerow()函数认为它找到的字典键不在您提供的fieldnames列表中,并且它引发该异常。什么是真的发生的事情是“当我期待一个单一的双字键”时,你通过了我的两个一键键单的列表,但是这个函数没有写出来检查这个特定的错误。


现在我会提及一些可以加快代码速度的方法。有一点可以帮助你,在代码开始时将这三个for循环减少到只有一个。你要做的是通过原始数据,并计算每个邻居出现的次数。首先,我会告诉你一个更好的方法来做到这一点,然后我会告诉你一个甚至更​​好方式,改善我的第一个解决方案。

更好的方法是利用Python在collections模块中提供的美妙的defaultdict类。 defaultdict是Python字典类型的一个子类,它会在第一次访问时自动创建字典条目。它的构造函数接受一个参数,这个函数将被调用时不带任何参数,并且应该为任何新项目返回所需的默认值。如果您用过defaultdictplace_count字典,此代码:

place_count = {} 
for place in set(neighborhood): 
    place_count.update({place:0}) 

可以简单地变成:

place_count = defaultdict(int) 

这是怎么回事?那么,int函数(它实际上不是函数,它是int类的构造函数,但这有点超出了这个解释的范围)只是在没有参数调用时返回0。因此,而不是写你自己的功能def returnzero(): return 0,你可以使用现有的int函数(好吧,构造函数)。现在,每当你做place_count["NEW PLACE"]时间,关键NEW PLACE会自动出现在你的字典place_count,以0

现在,你的循环计数也须修改的值:它曾经走过去的place_count钥匙,但现在place_count在第一次访问时自动创建密钥,您需要一个不同的来源。但是您仍然有原始数据的来源:每行的row["Neighborhood"]值。所以,你的for key,value in place_count.items():环路将变成:

for row in raw_data: 
    place = row["Neighborhood"] 
    place_count[place] = place_count[place] + 1 

而现在,您使用的是defaultdict,你甚至都不需要首先循环在所有(即创建neighborhood列表中的一个)!所以我们只把三个循环合而为一。我建议的最终版本如下所示:

from collections import defaultdict 
place_count = defaultdict(int) 
for row in raw_data: 
    place = row["Neighborhood"] 
    place_count[place] = place_count[place] + 1 
    # Or: place_count[place] += 1 

但是,还有一种方法可以提高这一点。 collections模块中的Counter对象仅用于这种情况,并且具有一些便捷的额外功能,例如能够检索N个最常见的项目。那么,我建议的最终最终版本:-)是:

from collections import Counter 
place_count = Counter() 
for row in raw_data: 
    place = row["Neighborhood"] 
    place_count[place] = place_count[place] + 1 
    # Or: place_count[place] += 1 

,如果你需要找回的5个最犯罪猖獗的街区这样的话,你可以叫place_count.most_common(5)

您可以在documentation for the collections module中阅读有关Counterdefaultdict的更多信息。

+0

完美运作。谢谢。我还应该注意到,任何尝试这样做的人都必须编辑最后三行,因为最后的for循环没有正确缩进。 – MobiusCode 2014-10-10 02:07:48

+0

@ DavidKatz-Wigmore - 我刚刚为加速代码添加了一些建议,在标准库中使用了一些Python最有用的函数(和类)。 – rmunn 2014-10-10 02:35:46