【问题标题】:how to create multiple columns at once with apply?如何使用apply一次创建多个列?
【发布时间】:2021-05-21 20:43:46
【问题描述】:

考虑这个例子

import pandas as pd
import numpy as np

df = pd.DataFrame({'var1' : [1,2,3,4],
                   'var2' : ['a','b','c','d']})
df
Out[100]: 
   var1 var2
0     1    a
1     2    b
2     3    c
3     4    d

我有一个函数,它将var1 作为输入并返回三个值,我想将它们存储到三个不同的变量中。以下似乎工作正常

    def myfunc(var):
        return [['small list'], var + 2, ['another list']]
    
    df.var1.apply(lambda x: myfunc(x))
    Out[101]: 
    0    [[small list], 3, [another list]]
    1    [[small list], 4, [another list]]
    2    [[small list], 5, [another list]]
    3    [[small list], 6, [another list]]
    Name: var1, dtype: object

但是,当我尝试创建相应的变量时出现错误

df[['my small list', 'my numeric', 'other list']]  = df.var1.apply(lambda x: myfunc(x))
ValueError: Must have equal len keys and value when setting with an iterable

你怎么看?

我曾经在Return multiple columns from pandas apply() 中使用了很棒的zip 解决方案,但是对于当前的Pandas 1.2,这个解决方案不再起作用了

谢谢!

【问题讨论】:

  • 你可以尝试应用这个答案:stackoverflow.com/questions/35491274/…
  • 顺便说一句,如果你已经有这个函数,你不需要创建一个lambda函数,你可以做df.var1.apply(myfunc)
  • 问题是数据框还包含我需要保留的其他列。这个解决方案在这里似乎不是最优的
  • 我把答案写出来(其他栏也可以保留)

标签: python pandas


【解决方案1】:

返回一个系列可能是最易读的解决方案。

def myfunc(var):
    return pd.Series([['small list'], var + 2, ['another list']])

df[['my small list', 'my numeric', 'other list']]  = df.var1.apply(lambda x: myfunc(x))

但是,对于较大的数据框,您应该更喜欢 zip 或数据框方法。

import pandas as pd # 1.2.2
import perfplot

def setup(n):
    return pd.DataFrame(dict(
        var1=list(range(n))
    ))
 
def with_series(df):
    def myfunc(var):
        return pd.Series([['small list'], var + 2, ['other list']])
    out = pd.DataFrame()
    out[['small list', 'numeric', 'other list']] = df.var1.apply(lambda x: myfunc(x))

def with_zip(df):
    def myfunc(var):
        return [['small list'], var + 2, ['other list']]
    out = pd.DataFrame()
    out['small list'], out['numeric'], out['other list'] = list(zip(*df.var1.apply(lambda x: myfunc(x))))

def with_dataframe(df):
    def myfunc(var):
        return [['small list'], var + 2, ['other list']]
    out = pd.DataFrame()
    out[['small list', 'numeric', 'other list']] = pd.DataFrame(df.var1.apply(myfunc).to_list())


perfplot.show(
    setup=setup,
    kernels=[
        with_series,
        with_zip,
        with_dataframe,
    ],
    labels=["series", "zip", "df"],
    n_range=[2 ** k for k in range(20)],
    xlabel="len(df)",
    equality_check=None,
)

【讨论】:

  • 我觉得这个不错。我想知道性能虽然
  • @ℕʘʘḆḽḘ 添加了不同方法的性能比较
【解决方案2】:

zip 方法似乎仍然可以正常工作:

import pandas as pd
import numpy as np

df = pd.DataFrame({'var1' : [1,2,3,4],
                   'var2' : ['a','b','c','d']})

def myfunc(var):
    return [['small list'], var + 2, ['another list']]

df['my small list'], df['my numeric'], df['other list'] = zip(*df.var1.apply(lambda x: myfunc(x)))

Return multiple columns from pandas apply()

真正奇怪的是内部列表是如何被强制转换为元组的。从实验来看,外部类型是list 类型似乎很重要。

要强制内部列表保留列表,我必须执行以下操作:

df['my small list'], df['my numeric'], df['other list'] = (list(row) for row in zip(*df.var1.apply(lambda x: myfunc(x))))

【讨论】:

  • 奇怪。我有熊猫1.2.0
  • @ℕʘʘḆḽḘ 你还记得 zip 中的星号吗?错误信息是什么?我正在使用 1.2.1,我希望它会像你一样失败。
  • 是的,那曾经与 *.... 一起工作很奇怪。只是一个注释,看起来列表实际上是你打印的元组?
  • 是的。这真的很奇怪吗?我用更多细节更新了答案。原来这取决于外列集合的类型。
【解决方案3】:

使用this stackoverflow question的方法,你只需要将来自df.var1.apply(myfunc)的pandas Series对象拆分成列即可。

我所做的是:

df[['out1','out2','out3']] = pd.DataFrame(df['var1'].apply(myfunc).to_list())

如您所见,这不会覆盖您的 DataFrame,只是将结果列分配给 DataFrame 中的新列。

apply方法后的DataFrame:

   var1 var2          out1  out2            out3
0     1    a  [small_list]     3  [another_list]
1     2    b  [small_list]     4  [another_list]
2     3    c  [small_list]     5  [another_list]
3     4    d  [small_list]     6  [another_list]

【讨论】:

    【解决方案4】:

    您可以使用pandas.DataFrame.apply()result_type 参数

    df[['my small list', 'my numeric', 'other list']]  = df.apply(lambda x: myfunc(x.var1), axis=1, result_type='expand')
    
    # print(df)
    
       var1 var2 my small list  my numeric      other list
    0     1    a  [small list]           3  [another list]
    1     2    b  [small list]           4  [another list]
    2     3    c  [small list]           5  [another list]
    3     4    d  [small list]           6  [another list]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-03
      • 1970-01-01
      • 2017-04-16
      • 1970-01-01
      • 2017-04-17
      相关资源
      最近更新 更多