Dask数据框-根据定界符将列拆分为多行

时间:2019-01-19 22:32:27

标签: python pandas performance dask

使用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 rowspandas: 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万行。

感谢您对此进行调查!我很感激。

2 个答案:

答案 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
>>>