使用dask数据框将一列分为多行的有效方法是什么?例如,假设我有一个csv文件,我使用dask读取了该文件,以生成以下dask数据帧:
id var1 var2
1 A Z,Y
2 B X
3 C W,U,V
我想将其转换为:
id var1 var2
1 A Z
1 A Y
2 B X
3 C W
3 C U
3 C V
我研究了Split (explode) pandas dataframe string entry to separate rows和pandas: How do I split text in a column into multiple rows?的答案。
我尝试应用https://stackoverflow.com/a/17116976/7275290中给出的答案,但是dask在str.split中似乎没有接受expand关键字。
我也尝试应用https://stackoverflow.com/a/40449726/7275290中建议的向量化方法,但随后发现np.repeat不能在整数数组(https://github.com/dask/dask/issues/2946)的快速实现中实现。
我尝试了大熊猫中的其他几种方法,但是它们确实很慢-快点可能会更快,但是我想首先检查是否有人在任何特定方法上都成功。我正在使用具有超过1000万行和10列(字符串数据)的数据集。分成几行后,它可能会变成约5000万行。
感谢您对此进行调查!我很感激。
答案 0 :(得分:7)
Dask允许您直接将熊猫用于按行操作(例如这样)或可以一次应用于一个分区。请记住,Dask数据框由一组Pandas数据框组成。
对于熊猫案,您将根据链接的问题执行此操作:
df = pd.DataFrame([["A", "Z,Y"], ["B", "X"], ["C", "W,U,V"]],
columns=['var1', 'var2'])
df.drop('var2', axis=1).join(
df.var2.str.split(',', expand=True).stack().reset_index(drop=True, level=1).rename('var2'))
因此对于Dask,您可以通过map_partitions
应用完全相同的方法,因为每一行都独立于所有其他行。如果传递的函数是单独写出的,而不是写成lambda的,这看起来会更干净:
d = dd.from_pandas(df, 2)
d.map_partitions(
lambda df: df.drop('var2', axis=1).join(
df.var2.str.split(',', expand=True).stack().reset_index(drop=True, level=1).rename('var2')))
如果您对此进行了.compute()
,则将获得与上述熊猫案完全相同的结果。您可能不想要像这样一口气计算大量数据帧,而是对其进行进一步处理。
答案 1 :(得分:0)
使用此:
>>> df.join(pd.DataFrame(df.var2.str.split(',', expand=True).stack()
.reset_index(level=1, drop=True),columns=['var2 '])).drop('var2',1)
.rename(columns=str.strip)
id var1 var2
0 1 A Z
0 1 A Y
1 2 B X
2 3 C W
2 3 C U
2 3 C V
>>>
或者如果需要重置索引:
>>> df.join(pd.DataFrame(df.var2.str.split(',', expand=True).stack()
.reset_index(level=1, drop=True),columns=['var2 '])).drop('var2',1)
.rename(columns=str.strip).reset_index(drop=True)
id var1 var2
0 1 A Z
1 1 A Y
2 2 B X
3 3 C W
4 3 C U
5 3 C V
>>>
对于简单的数据框:
from dask import dataframe as dd
sd = dd.from_pandas(df, npartitions=6)
时间(字面上是相同的):
>>> timeit.timeit(lambda: df.join(pd.DataFrame(df.var2.str.split(',', expand=True).stack()
.reset_index(level=1, drop=True),columns=['var2 '])).drop('var2',1)
.rename(columns=str.strip),number=10) # U9-Forward
0.05815268672555618
>>> timeit.timeit(lambda: df.drop('var2', axis=1).join(
df.var2.str.split(',', expand=True).stack().reset_index(drop=True, level=1).rename('var2')),number=10) # mdurant
0.05137591577754108
>>>