我有一个像这样的DataFrame:
df = pd.DataFrame([['Col1Val', 'Col2Val', '[3, 31.1, -341.4, 54.13]']],
columns=['col1', 'col2','values'])
唯一的区别是我有几百万行,而values
列是每行中200个浮点数的字符串,而不是我的示例中的4个。
包含此数据的csv文件大约为5 GB。但是,在将前2个字符串列转换为类别后加载到pandas中时,这会减少。因此,我能够执行大多数操作(过滤,切片,索引)而没有性能问题。
我需要将values
字符串列扩展为单独的浮点列。因此将有200列,每列包含一个浮点数。我试图执行此操作,但我一直没有记忆。从理论上讲,我认为这应该是以内存有效的方式逐行进行的,因为浮点数列应该比字符串中的许多数字占用更少的内存。什么是一个很好的算法呢?
我的现有代码如下所示,用于拆分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
答案 0 :(得分:3)
选项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
答案 1 :(得分:1)
您可以将pop
用于apply
的提取列,以转换为list
和DataFrame
构造函数:
df1 = df.join(pd.DataFrame(df.pop('values').apply(pd.io.json.loads).values.tolist()))
print (df1)
col1 col2 0 1 2 3
0 Col1Val Col2Val 3 31.1 -341.4 54.13
print (df1.dtypes)
col1 object
col2 object
0 int64
1 float64
2 float64
3 float64
dtype: object
答案 2 :(得分:1)
您也可以试试这个。
df['values'].str[1:-1].str.split(",", expand=True).astype(float)
第一个str[1:-1]
操作会删除括号。
str.split
会将其余值分割为,
并将其展开为数据框(使用expand=True
)
0 1 2 3
0 3.0 31.1 -341.4 54.13
您还可以按[ , ]
df['values'].str.split(r"[\[,\]]", expand=True).astype(float)
但这会产生两个额外的列
0 1 2 3 4 5
0 3 31.1 -341.4 54.13
有人可能会尝试从阅读数据部分修复它。
df = pd.read_csv('test.csv', delimiter=',', quotechar='"')
在这里,我们将引号char更改为"
,以便忽略原始引号char '
。然后我们按,
拆分。然后,我们需要做一些数据预处理来修复错误的部分。
鉴于我的test.csv
正在
c1,c2,v1,v2,v3,v4
'Col1Val', 'Col2Val', '[3, 31.1, -341.4, 54.13]'
'Col1Val', 'Col2Val', '[3, 31.1, -341.4, 54.13]'
'Col1Val', 'Col2Val', '[3, 31.1, -341.4, 54.13]'
read_csv
的结果是
c1 c2 v1 v2 v3 v4
0 'Col1Val' 'Col2Val' '[3 31.1 -341.4 54.13]'
1 'Col1Val' 'Col2Val' '[3 31.1 -341.4 54.13]'
2 'Col1Val' 'Col2Val' '[3 31.1 -341.4 54.13]'
现在,我们可以使用一些str
方法来修复每一列。 注意:如果c1
/ c2
中有逗号,则结果会出错。