如何处理修改大型 pandas 数据帧
How to deal with modifying large pandas dataframes
我有一个较大的 pandas 数据帧(磁盘上有 1.5gig .csv)。我可以将它加载到内存中并查询它。我想创建一个新列,它是其他两个列的组合值,我试过这个:
def combined(row):
row['combined'] = row['col1'].join(str(row['col2']))
return row
df = df.apply(combined, axis=1)
这导致我的 python 进程被终止,可能是因为内存问题。
一个更迭代的问题解决方案似乎是:
df['combined'] = ''
col_pos = list(df.columns).index('combined')
crs_pos = list(df.columns).index('col1')
sub_pos = list(df.columns).index('col2')
for row_pos in range(0, len(df) - 1):
df.iloc[row_pos, col_pos] = df.iloc[row_pos, sub_pos].join(str(df.iloc[row_pos, crs_pos]))
这当然看起来很不pandas。而且速度很慢。
理想情况下,我想要像 apply_chunk()
这样的东西,它与 apply 相同,但只适用于数据帧的一部分。我认为 dask
可能是一个选项,但 dask
数据框在我使用时似乎还有其他问题。不过,这一定是一个常见问题,我应该使用一种设计模式来向大型 pandas 数据帧添加列吗?
我会尝试使用列表理解 + itertools
:
df = pd.DataFrame({
'a': ['ab'] * 200,
'b': ['ffff'] * 200
})
import itertools
[a.join(b) for (a, b) in itertools.izip(df.a, df.b)]
可能是 "unpandas",但 pandas 似乎没有 .str
方法可以帮助您,"unpythonic" 也没有。
要创建另一列,只需使用:
df['c'] = [a.join(b) for (a, b) in itertools.izip(df.a, df.b)]
顺便说一下,您还可以使用以下方法进行分块:
[a.join(b) for (a, b) in itertools.izip(df.a[10: 20], df.b[10: 20])]
如果您想尝试并行化。我会首先尝试上面的版本,因为列表推导和 itertools 通常出奇地快,并且并行化需要的开销需要被抵消。
在 pandas
or dask.dataframe
is with the .assign
方法中创建新列的好方法。
In [1]: import pandas as pd
In [2]: df = pd.DataFrame({'x': [1, 2, 3, 4], 'y': ['a', 'b', 'a', 'b']})
In [3]: df
Out[3]:
x y
0 1 a
1 2 b
2 3 a
3 4 b
In [4]: df.assign(z=df.x * df.y)
Out[4]:
x y z
0 1 a a
1 2 b bb
2 3 a aaa
3 4 b bbbb
但是,如果您的操作是高度自定义的(看起来如此)并且 Python 迭代器足够快(看起来如此),那么您可能只想坚持使用它。每当您发现自己在循环中使用 apply
或 iloc
时,很可能 Pandas 的运行速度比最佳速度慢得多。
我有一个较大的 pandas 数据帧(磁盘上有 1.5gig .csv)。我可以将它加载到内存中并查询它。我想创建一个新列,它是其他两个列的组合值,我试过这个:
def combined(row):
row['combined'] = row['col1'].join(str(row['col2']))
return row
df = df.apply(combined, axis=1)
这导致我的 python 进程被终止,可能是因为内存问题。
一个更迭代的问题解决方案似乎是:
df['combined'] = ''
col_pos = list(df.columns).index('combined')
crs_pos = list(df.columns).index('col1')
sub_pos = list(df.columns).index('col2')
for row_pos in range(0, len(df) - 1):
df.iloc[row_pos, col_pos] = df.iloc[row_pos, sub_pos].join(str(df.iloc[row_pos, crs_pos]))
这当然看起来很不pandas。而且速度很慢。
理想情况下,我想要像 apply_chunk()
这样的东西,它与 apply 相同,但只适用于数据帧的一部分。我认为 dask
可能是一个选项,但 dask
数据框在我使用时似乎还有其他问题。不过,这一定是一个常见问题,我应该使用一种设计模式来向大型 pandas 数据帧添加列吗?
我会尝试使用列表理解 + itertools
:
df = pd.DataFrame({
'a': ['ab'] * 200,
'b': ['ffff'] * 200
})
import itertools
[a.join(b) for (a, b) in itertools.izip(df.a, df.b)]
可能是 "unpandas",但 pandas 似乎没有 .str
方法可以帮助您,"unpythonic" 也没有。
要创建另一列,只需使用:
df['c'] = [a.join(b) for (a, b) in itertools.izip(df.a, df.b)]
顺便说一下,您还可以使用以下方法进行分块:
[a.join(b) for (a, b) in itertools.izip(df.a[10: 20], df.b[10: 20])]
如果您想尝试并行化。我会首先尝试上面的版本,因为列表推导和 itertools 通常出奇地快,并且并行化需要的开销需要被抵消。
在 pandas
or dask.dataframe
is with the .assign
方法中创建新列的好方法。
In [1]: import pandas as pd
In [2]: df = pd.DataFrame({'x': [1, 2, 3, 4], 'y': ['a', 'b', 'a', 'b']})
In [3]: df
Out[3]:
x y
0 1 a
1 2 b
2 3 a
3 4 b
In [4]: df.assign(z=df.x * df.y)
Out[4]:
x y z
0 1 a a
1 2 b bb
2 3 a aaa
3 4 b bbbb
但是,如果您的操作是高度自定义的(看起来如此)并且 Python 迭代器足够快(看起来如此),那么您可能只想坚持使用它。每当您发现自己在循环中使用 apply
或 iloc
时,很可能 Pandas 的运行速度比最佳速度慢得多。