Python处理CSV文件的速度非常慢
因此,我试图打开一个CSV文件,读取其字段,并根据该文件修复一些其他字段,然后将数据保存回CSV。我的问题是CSV文件有200万行。加快速度的最佳方法是什么。Python处理CSV文件的速度非常慢,python,pandas,csv,numpy,Python,Pandas,Csv,Numpy,因此,我试图打开一个CSV文件,读取其字段,并根据该文件修复一些其他字段,然后将数据保存回CSV。我的问题是CSV文件有200万行。加快速度的最佳方法是什么。 CSV文件包括 ID; DATE(d/m/y); SPECIAL_ID; DAY; MONTH; YEAR 我正在计算记录中出现日期相同的行的频率,然后根据该数据更新特殊ID 基于我之前的研究,我决定使用熊猫。我将在未来处理更大的数据集(1-2GB)-这一组大约为119MB,因此找到一个好的快速解决方案至关重要 我的代码如下: df =
CSV文件包括
ID; DATE(d/m/y); SPECIAL_ID; DAY; MONTH; YEAR
我正在计算记录中出现日期相同的行的频率,然后根据该数据更新特殊ID
基于我之前的研究,我决定使用熊猫。我将在未来处理更大的数据集(1-2GB)-这一组大约为119MB,因此找到一个好的快速解决方案至关重要
我的代码如下:
df = pd.read_csv(filename, delimiter=';')
df_fixed= pd.DataFrame(columns=stolpci) #when I process the row in df I append it do df_fixed
d = 31
m = 12
y = 100
s = (y,m,d)
list_dates= np.zeros(s) #3 dimensional array.
for index, row in df.iterrows():
# PROCESSING LOGIC GOES HERE
# IT CONSISTS OF FEW IF STATEMENTS
list_dates[row.DAY][row.MONTH][row.YEAR] += 1
row['special_id'] = list_dates[row.DAY][row.MONTH][row.YEAR]
df_fixed = df_fixed.append(row.to_frame().T)
df_fixed .to_csv(filename_fixed, sep=';', encoding='utf-8')
我试着每处理1000行打印一次。一开始,我的脚本需要3秒钟才能运行1000行,但运行的时间越长,速度就越慢。
第43000行需要29秒,以此类推
感谢您以后的帮助:)
编辑:
我正在添加有关CSV和exptected输出的其他信息
ID;SPECIAL_ID;sex;age;zone;key;day;month;year
2;13012016505__-;F;1;1001001;1001001_F_1;13;1;2016
3;25122013505__-;F;4;1001001;1001001_F_4;25;12;2013
4;24022012505__-;F;5;1001001;1001001_F_5;24;2;2012
5;09032012505__-;F;5;1001001;1001001_F_5;9;3;2012
6;21082011505__-;F;6;1001001;1001001_F_6;21;8;2011
7;16082011505__-;F;6;1001001;1001001_F_6;16;8;2011
8;21102011505__-;F;6;1001001;1001001_F_6;16;8;2011
我必须将特殊ID字段中的-替换为正确的数字。
例如,对于具有
ID=2特殊的\u ID将
26022018505001(-被001取代)如果CSV中的其他人在同一天、同一月、同一年共享,则将被002取代,依此类推。。。
因此,上述行的扩展输出将是
ID;SPECIAL_ID;sex;age;zone;key;day;month;year
2;13012016505001;F;1;1001001;1001001_F_1;13;1;2016
3;25122013505001;F;4;1001001;1001001_F_4;25;12;2013
4;24022012505001;F;5;1001001;1001001_F_5;24;2;2012
5;09032012505001;F;5;1001001;1001001_F_5;9;3;2012
6;21082011505001;F;6;1001001;1001001_F_6;21;8;2011
7;16082011505001;F;6;1001001;1001001_F_6;16;8;2011
8;21102011505002;F;6;1001001;1001001_F_6;16;8;2011
编辑:
我把代码改成这样:我用数据填充dict列表,然后将该列表转换为dataframe并另存为csv。这大约需要30分钟才能完成
list_popravljeni = []
df = pd.read_csv(filename, delimiter=';')
df_dates = df.groupby(by=['dan_roj', 'mesec_roj', 'leto_roj']).size().reset_index()
for index, row in df_dates.iterrows():
df_candidates= df.loc[(df['dan_roj'] == dan_roj) & (df['mesec_roj'] == mesec_roj) & (df['leto_roj'] == leto_roj) ]
for index, row in df_candidates.iterrows():
vrstica = {}
vrstica['ID'] = row['identifikator']
vrstica['SPECIAL_ID'] = row['emso'][0:11] + str(index).zfill(2)
vrstica['day'] = row['day']
vrstica['MONTH'] = row['MONTH']
vrstica['YEAR'] = row['YEAR']
list_popravljeni.append(vrstica)
pd.DataFrame(list_popravljeni, columns=list_popravljeni[0].keys())
我认为这会提供你想要的,并避免循环。它可能更有效(我无法找到避免创建
计数的方法)。但是,它应该比您当前的方法快得多
df['counts'] = df.groupby(['year', 'month', 'day'])['SPECIAL_ID'].cumcount() + 1
df['counts'] = df['counts'].astype(str)
df['counts'] = df['counts'].str.zfill(3)
df['SPECIAL_ID'] = df['SPECIAL_ID'].str.slice(0, -3).str.cat(df['counts'])
我在末尾添加了一条假记录,以确认它是否正确递增:
SPECIAL_ID sex age zone key day month year counts
0 13012016505001 F 1 1001001 1001001_F_1 13 1 2016 001
1 25122013505001 F 4 1001001 1001001_F_4 25 12 2013 001
2 24022012505001 F 5 1001001 1001001_F_5 24 2 2012 001
3 09032012505001 F 5 1001001 1001001_F_5 9 3 2012 001
4 21082011505001 F 6 1001001 1001001_F_6 21 8 2011 001
5 16082011505001 F 6 1001001 1001001_F_6 16 8 2011 001
6 21102011505002 F 6 1001001 1001001_F_6 16 8 2011 002
7 21102012505003 F 6 1001001 1001001_F_6 16 8 2011 003
如果您想消除计数
,只需:
df.drop('counts', inplace=True, axis=1)
减少搜索空间的一种方法可能是使用pandas切片来替换IF条件。例如,if value>5可以切片为df。loc[df['value']>5,:]
将数据集裁剪为仅与if条件匹配的行。这假设您正在寻找一个与所有条件匹配的结果。在这种情况下,您能提供一个输入文件和预期输出的小示例吗?数据帧没有针对循环进行优化,也没有被追加数百万次,但是如果没有一个例子来检查,很难正确地可视化矢量化方法。我不确定为什么不能使用类似df=df.groupby(by=['year',month',day'].size().reset_index()
的东西。这将计算特定日期的出现次数。@roganjosh我做了:)检查编辑的postook@roganjosh,我按照您的建议尝试过,groupby工作得很好!我甚至不知道熊猫有什么选择。现在我必须将这些数字分配到实际记录中。首先,感谢您的帮助!是的,计数应该递增。记录#5[SPECIAL_ID]应为16082011505001,记录#6[SPECIAL_ID]应为16082011505002@Kristjan但是它具体地根据ID
列中的顺序递增?因为我认为,groupby
会破坏任何初始订单,所以我们需要一些固定的东西来建立这个基础,否则在这个阶段,哪个得到001
,哪个得到002
都是任意的,不管谁得到哪个号码。我只需要给定一天的所有记录就可以得到1-len(给定一天的记录)我设法加快了速度。我想大概需要30-40分钟才能完成。。。但还是比我以前的方式好。当我有时间的时候,我会发布我的解决方案作为答案。。。如果你认为更快的方法是可能的,我的耳朵open@Kristjan我已经解决了这个问题。我希望我的方法是以秒为单位,而不是以分钟为单位。太好了,我把你的答案整合到了我的代码中,它工作得非常完美而且非常快!我将来会做很多类似上面提到的工作,所以如果你能给我指出一个好的学习资源,那就太好了。