【问题标题】:Most efficient way of performing creation of new rows in a DataFrame在 DataFrame 中创建新行的最有效方式
【发布时间】:2023-02-23 00:39:52
【问题描述】:

我正在实施一个数据增强脚本,该脚本将 pandas DataFrame 和字符串列表(例如 variations)作为输入。该脚本应为 DataFrame 生成新行,其中每行连接 variations 的一个元素。

例如,有一个 DataFrame:

Compliment | Sentence_ID
Hi         | 1
Hello      | 2
Hola       | 3

和变化["Elvis", "Monica"]

生成的数据框应该是这样的:

Compliment   | Sentence_ID
Hi           | 1
Hi Elvis     | 1
Hi Monica    | 1
Hello        | 2
Hello Elvis  | 2
Hello Monica | 2
Hola         | 3
Hola Elvis   | 3
Hola Monica  | 3

我用pd.iterrows() 做了一些测试,但当数据帧很大时,它似乎非常慢(~5 分钟)。我想知道是否有这样一个更可行的选择。

【问题讨论】:

  • variations在你的实际情况中是大尺寸吗?
  • 是的,你可以考虑它们会很大。
  • 你能给出你真实数据集的大小吗?和变化列表?
  • 这将应用于一些不同的数据集,但您可以考虑数据集可能有 10-30k 行,变体可能有 100-300 个元素。

标签: python pandas numpy performance


【解决方案1】:

pandas.DataFrame.explode

df['Compliment'] = df['Compliment'].apply(lambda x: [x] + [f"{x} {v}" for v in variations])
df = df.explode('Compliment')

     Compliment  Sentence_ID
0            Hi            1
0      Hi Elvis            1
0     Hi Monica            1
1         Hello            2
1   Hello Elvis            2
1  Hello Monica            2
2          Hola            3
2    Hola Elvis            3
2   Hola Monica            3

【讨论】:

  • 我不得不说 explode 比我预期的要快(尽管不如没有后处理的交叉合并那么快)。我添加了一些时间:)
  • @mozway,好的,顺便说一句,关于“numpy 方法”:我最近回答了一些问题并注意到 np.tilenp.repeat 慢:比如 %timeit np.tile([1, 2, 3, 4, 5], 300) vs %timeit np.repeat([[1, 2, 3, 4, 5]], 300, axis=0).ravel()
  • 有意思,我试试!
  • 对您的建议的反馈,它在小列表上确实更快,但在大输入上的时间相同。对于当前情况,没有区别。我猜 tile 是一个更大的开销,因为它比 repeat 具有更多的功能;)
  • @mozway,感谢您的研究
【解决方案2】:

你可以试试merge

out = df.merge(pd.Series(["","Elvis", "Monica"],name='Compliment'),how='cross')
out['Compliment'] = out[['Compliment_x','Compliment_y']].agg(' '.join, axis=1).str.strip()
out = out.drop(['Compliment_x','Compliment_y'],axis=1)
out
Out[96]: 
   Sentence_ID    Compliment
0            1            Hi
1            1      Hi Elvis
2            1     Hi Monica
3            2         Hello
4            2   Hello Elvis
5            2  Hello Monica
6            3          Hola
7            3    Hola Elvis
8            3   Hola Monica

【讨论】:

  • 糟糕,我没有看到你的答案,快速浏览一下我的合并方法(可能更有效),然后如果你愿意,我可以删除 ;)
【解决方案3】:

使用repeat

variations =  ["Elvis", "Monica"]

pd.concat([df,
           df.loc[df.index.repeat(len(variations))]
             .assign(Compliment=lambda d: d['Compliment'].add(' ').add(np.tile(variations, len(df))))
          ]).sort_index(kind='stable', ignore_index=True)

或者用十字 merge:

l = ['']+[f' {s}' for s in variations]

(df.merge(pd.Series(l, name='suffix'), how='cross')
   .assign(Compliment=lambda d: d['Compliment'].add(d.pop('suffix')))
)

输出:

     Compliment  Sentence_ID
0            Hi            1
1      Hi Elvis            1
2     Hi Monica            1
3         Hello            2
4   Hello Elvis            2
5  Hello Monica            2
6          Hola            3
7    Hola Elvis            3
8   Hola Monica            3

时机

N为行数,variation中固定长度为200条

现在,N 是variation 中的项目数,df 有 30K 行:

【讨论】:

    【解决方案4】:

    这是pd.concat()的选项

    l = ['','Elvis','Monica']
    (pd.concat([df]*len(l),keys = l,names = ['name'])
    .reset_index(level=0)
    .assign(Compliment = lambda x: x['Compliment'] + ' ' + x.pop('name'))
    .sort_index(level=0))
    

    输出:

         Compliment  Sentence_ID
    0           Hi             1
    0      Hi Elvis            1
    0     Hi Monica            1
    1        Hello             2
    1   Hello Elvis            2
    1  Hello Monica            2
    2         Hola             3
    2    Hola Elvis            3
    2   Hola Monica            3
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-25
      • 2013-09-05
      • 1970-01-01
      • 2018-07-22
      • 1970-01-01
      • 2021-09-20
      相关资源
      最近更新 更多