我试图将字典(程序的第一部分生成)写入csv,以便我可以对excel中的数据执行进一步操作。我意识到代码并不高效,但此时我还是喜欢它。我可以稍后加快速度。
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'}
答案 0 :(得分:1)
我相信你的问题在这里:
for key in place_count:
stats.append([{"Location":str(key)},{"Volume":str(place_count[key])}])
这是创建两个词典的列表。第一个只有一个&#34;位置&#34;键,第二个只有一个&#34;卷&#34;键。但是,csv.DictWriter
对象期望每行一个字典,并且字典中包含所有键。将该代码段更改为以下内容,它应该可以正常工作:
for key in place_count:
stats.append({"Location": str(key), "Volume": str(place_count[key])})
这应该照顾你所看到的错误。
现在,至于为什么错误消息抱怨不在字段名中的字段,这完全误导你远离你所遇到的真正问题:writerow()
函数希望得到字典作为其行参数,但您将其传递给列表。结果是混乱:它在for
循环中迭代dict,期望获得dict的键(因为这是你在Python中迭代dict时得到的),以及它将这些键与fieldnames
列表中的值进行比较。它期待看到的是:
"Location"
"Volume"
以任何顺序(因为Python dict不保证它将返回其键的顺序)。他们希望您传入fieldnames
列表的原因是这些字段可以按正确的顺序写入CSV。但是,因为您在两个词典的列表中传递,当它遍历row
参数时,它会得到以下内容:
{'Location': 'SABIN'}
{'Volume': '247'}
现在,字典{'Location': 'SABIN'}
不等于字符串"Location"
,而字典{'Volume': '247'}
不等于字符串"Volume"
,因此writerow()
函数认为它发现你提供的fieldnames
列表中没有dict键,它会引发异常。 真正正在发生的是&#34;当我预期单个dict-with-two-key&#34;时,你传给我一个两个单键的列表,但是这个功能没有写过来检查那个特定的错误。
现在我要提到一些可以加快代码速度的事情。有一点可以帮助我们将代码开头的三个for
循环减少到只有一个。您尝试做的是浏览原始数据,并计算每个邻域出现的次数。首先,我将向您展示一种更好的方法,然后我会向您展示一种更好的方式,以改善我的第一个解决方案。
更好的方法是使用Python在defaultdict
模块中提供的精彩collections
类。 defaultdict
是Python的字典类型的子类,它将在第一次访问时自动创建dict条目。它的构造函数只接受一个参数,这个函数将在没有参数的情况下被调用,并且应该为任何新项返回所需的默认值。如果您已将defaultdict
用于place_count
dict,则此代码为:
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
然而,有一种方法可以进一步改善这一点。来自Counter
模块的collections
对象仅适用于此情况,并具有一些方便的额外功能,例如检索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中详细了解Counter
和defaultdict
。