我有以下代码片段,它将CSV读入数据帧,并以符合Redis协议的方式将键值对写入文件,即SET key1 value1
。代码是零碎的,我试图使用多处理,但我不确定它的性能(增益)。
CSV有大约600万行,很快就会被读入数据帧(2分钟以内)。输出文件有1200万行(每行输入文件2行)。这大约需要50分钟才能完成。可以优化/更改我的代码的任何部分以使其运行更快吗?文件完成后,将其加载到Redis只需不到90秒。瓶颈实际上是写入文件。我会写几个这样的文件,每个文件花费50-60分钟真的不太理想。这个特殊的数据集有600万行和10列,主要由带有几个浮点列的字符串组成。 Redis键是字符串,浮点值是键值对中的Redis值。其他数据集的大小也相似,如果不是更大(相对于行和列)。
我正在考虑将我生成的所有字符串加载到数据帧中,然后使用to_csv()函数将其转储到文件中,但我不确定它的性能如何。
filepath = '/path/to/file.csv'
def df_to_file:
df = pd.read_csv(filepath)
f = open('output_file', 'w')
for i in range(len(df.index)):
if df['col1'].iloc[i] != '':
key1 = str(df['col1'].iloc[i])+str(df['col4'].iloc[i])+str(df['col5'].iloc[i])+...+str(df['col_n'].iloc[i])
val1 = df['col_n+1'].iloc[i]
key1a = str(df['col1'].iloc[i])+str(df['col4'].iloc[i])+str(df['col5'].iloc[i])+...+str(df['col_n'].iloc[i])
val1a = df['col_n+2'].iloc[i]
print('SET {0} {1}\nSET {0} {1}'.format(key1, val1, key1a, val1a), file = f)
if df['col2'].iloc[i] != '':
key1 = str(df['col2'].iloc[i])+str(df['col4'].iloc[i])+str(df['col5'].iloc[i])+...+str(df['col_n'].iloc[i])
val1 = df['col_n+1'].iloc[i]
key1a = str(df['col2'].iloc[i])+str(df['col4'].iloc[i])+str(df['col5'].iloc[i])+...+str(df['col_n'].iloc[i])
val1a = df['col_n+2'].iloc[i]
print('SET {0} {1}\nSET {0} {1}'.format(key1, val1, key1a, val1a), file = f)
if df['col3'].iloc[i] != '':
key1 = str(df['col3'].iloc[i])+str(df['col4'].iloc[i])+str(df['col5'].iloc[i])+...+str(df['col_n'].iloc[i])
val1 = df['col_n+1'].iloc[i]
key1a = str(df['col3'].iloc[i])+str(df['col4'].iloc[i])+str(df['col5'].iloc[i])+...+str(df['col_n'].iloc[i])
val1a = df['col_n+2'].iloc[i]
print('SET {0} {1}\nSET {0} {1}'.format(key1, val1, key1a, val1a), file = f)
f.close()
p = Process(target = df_to_file)
p.start()
p.join()
答案 0 :(得分:2)
使用类似df['col1'].loc[...]
的结构来循环各个行的速度会很慢,基于iloc
和loc
的选择器用于在整个数据帧中选择 ,并且做了很多与索引对齐相关的事情,如果对每一行都做了很多,那么这些事情会有很高的开销。相反,只需使用df.itertuples()
迭代行就可以显着更快。
def df_to_file:
df = pd.read_csv(filepath)
f = open('output_file', 'wb') # writing in binary mode should be faster, if it is possible without unicode problems
for row in df.itertuples():
if row.col1:
key1, val1 = string1, string2
key1a, val1a = string1a, string2a
print('SET {0} {1}\nSET {0} {1}'.format(key1, val1, key1a, val1a), file = f)
if row.col2:
key1, val1 = string1, string2
key1a, val1a = string1a, string2a
print('SET {0} {1}\nSET {0} {1}'.format(key1, val1, key1a, val1a), file = f)
if row.col3:
key1, val1 = string1, string2
key1a, val1a = string1a, string2a
print('SET {0} {1}\nSET {0} {1}'.format(key1, val1, key1a, val1a), file = f)
f.close()
这可能是您可以进行的最低限度优化。如果您更详细地描述了您正在做的事情,也许可以找到矢量化解决方案。
此外,请勿将上述内容与multiprocessing
一起使用。
此外,正如所写的那样,'SET {0} {1}\nSET {0} {1}'.format(key1, val1, key1a, val1a)
将永远是相同的。如果这些参数没有改变,那么只需在循环外执行字符串连接一次,然后在循环中重复使用整个字符串。
编辑:似乎你不能这样做但是,给定:
这个特殊的数据集有600万行和10列,主要由带有几个浮点列的字符串组成。 Redis键是字符串,浮点值是键值对中的Redis值。
然后只是key1 = ''.join(row.col1, row.col4, row.col5, ...)
不要使用str
和+
运算符,这非常低效,加倍,因为你暗示这些列已经是字符串了。如果必须在所有这些列上调用str
,请使用map(str, ...)
最后,如果你真的需要挤出性能,请注意row
将是namedtuple
个对象,其中是元组,并且你可以使用基于整数的索引代替基于属性的标签访问,即row[1]
而不是row.col1
(注意,row[0]
将是row.index
,即索引)`它应该更快(并且它将使因为你每次迭代都会将元组索引数十次并进行数百万次迭代,所以会有所不同。)