对非常大的 CSV 文件的列表列中的对象进行计数

Count Occurrences for Objects in a Column of Lists for Really Large CSV File

我有一个包含多列的巨大 CSV 文件 (8gb)。其中一列是一列列表,如下所示:

     YEAR              WIN_COUNTRY_ISO3
200  2017         ['BEL', 'FRA', 'ESP']
201  2017                ['BEL', 'LTU']
202  2017                ['POL', 'BEL']
203  2017                       ['BEL']
204  2017  ['GRC', 'DEU', 'FRA', 'LVA']
205  2017                       ['LUX']
206  2017         ['BEL', 'SWE', 'LUX']
207  2017                       ['BEL']
208  2017                            []
209  2017                            []
210  2017                            []
211  2017                       ['BEL']
212  2017                       ['SWE']
213  2017                ['LUX', 'LUX']
214  2018                ['DEU', 'LUX']
215  2018                ['ESP', 'PRT']
216  2018                       ['AUT']
217  2018                ['DEU', 'BEL']
218  2009                       ['ESP']
219  2009                       ['BGR']

每个三字代码代表一个国家。我想为每个国家/地区创建一个频率 table,这样我就可以计算每个国家/地区在整个列中的出现次数。由于文件非常大,我的 PC 无法处理将整个 CSV 作为数据帧加载,我尝试懒惰地读取文件并遍历该行 --> 获取最后一列并将对象添加到 WIN_COUNTRY_ISO3列(恰好是最后一列)到一组字典中。

import sys
from itertools import islice
n=100
i = 0
col_dict={}
with open(r"filepath.csv") as file:
    for nline in iter(lambda: tuple(islice(file, n)), ()):
        row = nline.splitline
        WIN_COUNTRY_ISO3 = row[-1]
        for iso3 in WIN_COUNTRY_ISO3:
            if iso3 in col_dict.keys():
                col_dict[iso3]+=1
            else:
                col_dict[iso3]=1
        i+=1
        sys.stdout.write("\rDoing thing %i" % i)
        sys.stdout.flush()
    print(col_dict)

但是,这个过程需要很长时间。我尝试使用代码

遍历多行
for nline in iter(lambda: tuple(islice(file, n)), ())

Q1:

但是,这似乎不起作用,python 一个一个地处理文件。有没有人知道最多 对于像我这样的非常大的文件,我生成每个国家/地区计数的有效方法?

结果 table 看起来像这样:

Country     Freq
BEL         4543
FRA         4291
ESP         3992
LTU         3769
POL         3720
GRC         3213
DEU         3119
LVA         2992
LUX         2859
SWE         2802
PRT         2584
AUT         2374
BGR         1978
RUS         1770
TUR         1684

如果有人可以帮助我,我还想在每年(在 YEAR 列中)创建频率 table。谢谢。

试试这个:

from collections import defaultdict
import csv
import re

result = defaultdict(int)
f = open(r"filepath.csv")
next(f)
for row in f:
    data = re.sub(r'[\s\d\'\[\]]', '', row)
    if data:
        for x in data.split(','):
            result[x] += 1
print(result)

如果你能处理 awk,这里有一个:

$ cat program.awk
{
    while(match([=10=],/'[A-Z]{3}'/)) {
        a[substr([=10=],RSTART+1,RLENGTH-2)]++
        [=10=]=substr([=10=],RSTART+RLENGTH)
    }
}
END {
    for(i in a)
        print a[i],i
}

执行:

$ awk -f program.awk file

输出:

1 AUT
3 DEU
3 ESP
1 BGR
1 LTU
2 FRA
1 PRT
5 LUX
8 BEL
1 POL
1 GRC
1 LVA
2 SWE

[=13=] 处理整个数据记录(行),因此它可能包括来自记录中其他地方的错误命中。您可以通过适当的字段分隔来增强它,但由于它不可用,我无能为力。参见 gnu awk,FS 和 google 中的 FPAT