我有一个像这样的 DataFrame:
df = pd.DataFrame([['Col1Val', 'Col2Val', '[3, 31.1, -341.4, 54.13]']],
columns=['col1', 'col2','values'])
唯一的区别是我有几百万行和列 values 是每行正好有 200 个 float 的字符串,而不是我的示例中的 4 个。
包含此数据的 csv 文件约为 5 GB。但是,当我将前 2 个字符串列转换为类别后加载到 pandas 时,这会减少。因此,我能够在没有性能问题的情况下执行大多数操作(过滤、切片、索引)。
我需要将字符串的 values 列扩展为单独的 float 列。因此将有 200 列,每列包含一个 float 。我尝试执行此操作,但我总是内存不足。从理论上讲,我认为这应该可以以一种内存有效的方式逐行进行,因为 float 的列应该比字符串中的许多数字占用更少的内存。对此有什么好的算法?
我现有的代码如下,用于拆分 values 列。
df['values'] = df['values'].str.replace('[','').str.replace(']','')
# code runs out of memory in next line!
df_values = pd.DataFrame([x.split(',') for x in df['values'].values.tolist()])
df_values[df_values.columns] = df_values[df_values.columns].apply(pd.to_numeric, errors='coerce')
df_values[df_values.columns] = df_values[df_values.columns].fillna(0.0)
df= df.drop('values', 1).join(df_values)
我的示例的预期结果,上面的代码为少量行正确生成:
df = pd.DataFrame([['Col1Val', 'Col2Val', 3.0, 31.1, -341.4, 54.13]],
columns=['col1', 'col2', 0, 1, 2, 3])
为了解释为什么我希望(希望!)“减少内存”的解决方案,floats 通常应该比 string 占用更少的空间:
from sys import getsizeof
getsizeof('334.34') #55
getsizeof(334.34) #24
getsizeof('-452.35614') #59
getsizeof(-452.35614) #24
请您参考如下方法:
选项 1
使用 ast.literal_eval/pd.eval 解析您的字符串列(这是最简单的第一步)。
import ast
df['values'] = df['values'].apply(ast.literal_eval)
接下来,展平最后一列并concat与剩余的 n - 1 列合并。
i = df.iloc[:, :-1]
j = pd.DataFrame(df.iloc[:, -1].tolist())
pd.concat([i, j], 1)
col1 col2 0 1 2 3
0 Col1Val Col2Val 3 31.1 -341.4 54.13
这是一个提高效率的改进版本。使用 del 就地删除列,并删除所有切片操作(它们创建副本,很浪费)。
j = pd.DataFrame(df['values'].tolist())
del df['values']
pd.concat([df, j], 1)
col1 col2 0 1 2 3
0 Col1Val Col2Val 3 31.1 -341.4 54.13
选项 2
str.extractall(不能保证性能)。
df = df.set_index(['col1', 'col2'])['values']\
.str.extractall('(\d+(?:\.\d*)?)')\
.unstack()
df.columns = df.columns.droplevel(0)
df.reset_index()
match col1 col2 0 1 2 3
0 Col1Val Col2Val 3 31.1 341.4 54.13
