在Pandas中将列拆分为多行的快速方法

时间:2015-11-10 03:39:35

标签: python pandas

我有以下数据框:

import pandas as pd
df = pd.DataFrame({ 'gene':["foo",
                            "bar // lal",
                            "qux",
                            "woz"], 'cell1':[5,9,1,7], 'cell2':[12,90,13,87]})
df = df[["gene","cell1","cell2"]]
df

看起来像这样:

Out[6]:
         gene  cell1  cell2
0         foo      5     12
1  bar // lal      9     90
2         qux      1     13
3         woz      7     87

我想要做的是拆分'基因'列,使其结果如下:

         gene  cell1  cell2
         foo      5     12
         bar      9     90
         lal      9     90
         qux      1     13
         woz      7     87

我目前的做法是:

import pandas as pd
import timeit

def create():
    df = pd.DataFrame({ 'gene':["foo",
                            "bar // lal",
                            "qux",
                            "woz"], 'cell1':[5,9,1,7], 'cell2':[12,90,13,87]})
    df = df[["gene","cell1","cell2"]]

    s = df["gene"].str.split(' // ').apply(pd.Series,1).stack()
    s.index = s.index.droplevel(-1)
    s.name = "Genes"
    del df["gene"]
    df.join(s)


if __name__ == '__main__':
    print(timeit.timeit("create()", setup="from __main__ import create", number=100))
    # 0.608163118362

非常慢。实际上我有大约40K线要检查 和过程。

快速实施的是什么?

3 个答案:

答案 0 :(得分:14)

TBH我认为我们需要一种快速内置的方式来规范这样的元素..虽然因为我已经离开了一点所有我知道现在有一个,我只是不知道。 :-)与此同时,我一直在使用这样的方法:

def create(n):
    df = pd.DataFrame({ 'gene':["foo",
                                "bar // lal",
                                "qux",
                                "woz"], 
                        'cell1':[5,9,1,7], 'cell2':[12,90,13,87]})
    df = df[["gene","cell1","cell2"]]
    df = pd.concat([df]*n)
    df = df.reset_index(drop=True)
    return df

def orig(df):
    s = df["gene"].str.split(' // ').apply(pd.Series,1).stack()
    s.index = s.index.droplevel(-1)
    s.name = "Genes"
    del df["gene"]
    return df.join(s)

def faster(df):
    s = df["gene"].str.split(' // ', expand=True).stack()
    i = s.index.get_level_values(0)
    df2 = df.loc[i].copy()
    df2["gene"] = s.values
    return df2

给了我

>>> df = create(1)
>>> df
         gene  cell1  cell2
0         foo      5     12
1  bar // lal      9     90
2         qux      1     13
3         woz      7     87
>>> %time orig(df.copy())
CPU times: user 12 ms, sys: 0 ns, total: 12 ms
Wall time: 10.2 ms
   cell1  cell2 Genes
0      5     12   foo
1      9     90   bar
1      9     90   lal
2      1     13   qux
3      7     87   woz
>>> %time faster(df.copy())
CPU times: user 16 ms, sys: 0 ns, total: 16 ms
Wall time: 12.4 ms
  gene  cell1  cell2
0  foo      5     12
1  bar      9     90
1  lal      9     90
2  qux      1     13
3  woz      7     87

适用于低尺寸的可比速度,

>>> df = create(10000)
>>> %timeit z = orig(df.copy())
1 loops, best of 3: 14.2 s per loop
>>> %timeit z = faster(df.copy())
1 loops, best of 3: 231 ms per loop
在较大的情况下加速60倍。请注意,我在这里使用df.copy()的唯一原因是因为orig具有破坏性。

答案 1 :(得分:1)

我们可以首先拆分列,将其展开,堆叠,然后将其重新连接到原始df,如下所示:

df.drop('gene', axis=1).join(df['gene'].str.split('//', expand=True).stack().reset_index(level=1, drop=True).rename('gene'))

这给了我们这个:

    cell1   cell2   gene
0   5   12  foo
1   9   90  bar
1   9   90  lal
2   1   13  qux
3   7   87  woz

答案 2 :(得分:1)

或使用:

df.join(pd.DataFrame(df.gene.str.split(',', expand=True).stack().reset_index(level=1, drop=True)
                ,columns=['gene '])).drop('gene',1).rename(columns=str.strip).reset_index(drop=True)

输出:

   gene  cell1  cell2
0   foo      5     12
1   bar      9     90
2   lal      9     90
3   qux      1     13
4   woz      7     87