我有一个大约5000万行的CSV文件,我试图操纵数据并写入一个新的CSV文件。下面是代码:
import csv
import itertools
def main():
with open("input.csv", "r") as csvfile:
rows = csv.DictReader(csvfile)
sorted_rows = sorted(rows, key=lambda row: row["name"])
grouping = groupby(sorted_rows, lambda row: row["name"])
with open("output.csv", "w") as final_csvfile:
fieldnames = ["name", "number"]
writer = csv.DictWriter(final_csvfile, fieldnames=fieldnames)
for group, items in grouping:
total = sum(int(item["number"]) for item in items)
writer.writerow(
{
"name": group,
"number": str(total),
}
)
if __name__ == "__main__":
main()
这在行数不太多的情况下工作得很好,但是当我运行实际的有5000万行的CSV时,它变得非常慢,程序最终被终止。
现在,sorted_rows = sorted(rows, key=lambda row: row["name"])
行是主要问题,因为它将5000万行加载到内存(一个列表)中,以便对其进行排序。我已经明白sorted()
所做的第一件事是将任何给定的生成器转换为列表,那么我该怎么做呢?指针吗?
@python_user上面方法的问题是,它会不断地向字典中添加内容,在你意识到它之前,字典会变得非常大,并且可能会把内存方面的事情搞砸。
@Bharel在评论中说了一些关于外部排序的事情,我研究了一下,找到了一个方法。
我发现UNIX的排序命令可以对非常大的文件执行外部合并排序,所以我写了一个脚本来对非常大的CSV文件进行排序,然后将排序后的CSV文件传递到问题中的python代码中。这样,不会有太大的内容被写入内存。
代码如下:
sort.sh
echo "sorting CSV"
sort input.csv -o input.csv
echo "Done!"
运行上述脚本后,将排序后的CSV传递到程序中:
import csv
from itertools import groupby
def main():
with open("input.csv", "r") as csvfile:
rows = csv.DictReader(csvfile)
grouping = groupby(rows, lambda row: row["name"])
with open("output.csv", "w") as final_csvfile:
fieldnames = ["name", "number"]
writer = csv.DictWriter(final_csvfile, fieldnames=fieldnames)
for group, items in grouping:
total = sum(int(item["number"]) for item in items)
writer.writerow(
{
"name": group,
"number": str(total),
}
)
if __name__ == "__main__":
main()
注意,问题中使用sorted()的那行不见了。我认为这是一个更有效的解决方案。