【问题标题】:Pandas Apply Function That returns two new columnsPandas 应用返回两个新列的函数
【发布时间】:2018-06-06 18:36:03
【问题描述】:

我有一个pandas 数据框,我想在其上使用应用函数来根据现有数据生成两个新列。我收到此错误: ValueError: Wrong number of items passed 2, placement implies 1

import pandas as pd
import numpy as np

def myfunc1(row):
    C = row['A'] + 10
    D = row['A'] + 50
    return [C, D]

df = pd.DataFrame(np.random.randint(0,10,size=(2, 2)), columns=list('AB'))

df['C', 'D'] = df.apply(myfunc1 ,axis=1)

开始 DF:

   A  B
0  6  1
1  8  4

所需的 DF:

   A  B  C   D
0  6  1  16  56
1  8  4  18  58

【问题讨论】:

标签: python python-2.7 pandas


【解决方案1】:

查询多列时添加额外的括号。

import pandas as pd
import numpy as np

def myfunc1(row):
    C = row['A'] + 10
    D = row['A'] + 50
    return [C, D]

df = pd.DataFrame(np.random.randint(0,10,size=(2, 2)), columns=list('AB'))

df[['C', 'D']] = df.apply(myfunc1 ,axis=1)

【讨论】:

    【解决方案2】:

    df['C','D'] 被视为 1 列而不是 2 列。因此对于 2 列,您需要一个切片数据框,因此请使用 df[['C','D']]

    df[['C', 'D']] = df.apply(myfunc1 ,axis=1)
    
        A  B   C   D
    0  4  6  14  54
    1  5  1  15  55
    

    或者你可以使用链式分配,即

    df['C'], df['D'] = df.apply(myfunc1 ,axis=1)
    

    【讨论】:

    • 这适用于我的示例数据集(如此赞成),但不适用于我的真实数据集,尽管代码相同。错误:KeyError: "['C' 'D'] not in index"
    • 我需要看看你是如何分配数据的。可能是您的实际代码。
    • 同样,唯一不同的代码是从 CSV 读取数据帧与使用 numpy 生成假数据df[['C', 'D']] = df.apply(myfunc1 ,axis=1)
    • 你的myfunc1和上面的一样吗?
    • @user2242044。您的错误消息显示“C”和“D”之间缺少逗号。
    【解决方案3】:

    根据您的最新错误,您可以通过将新列作为系列返回来避免错误

    def myfunc1(row):
        C = row['A'] + 10
        D = row['A'] + 50
        return pd.Series([C, D])
    
    df[['C', 'D']] = df.apply(myfunc1 ,axis=1)
    

    【讨论】:

    • 请注意所接受答案的巨大内存消耗和低速,下面的替代解决方案
    【解决方案4】:

    请注意已接受答案的巨大内存消耗和低速:https://ys-l.github.io/posts/2015/08/28/how-not-to-use-pandas-apply/

    使用那里提出的建议,正确答案是这样的:

    def run_loopy(df):
        Cs, Ds = [], []
        for _, row in df.iterrows():
            c, d, = myfunc1(row['A'])
            Cs.append(c)
            Ds.append(d)
        return pd.Series({'C': Cs,
                          'D': Ds})
    
    def myfunc1(a):
        c = a + 10
        d = a + 50
        return c, d
    
    df[['C', 'D']] = run_loopy(df)
    

    【讨论】:

    • 我认为您应该将Cs, Ds = [], []run_loopy 的第一行)编辑为v1s, v2s = [], [],反之亦然
    • @codkelden 感谢您的关注!我会把 v1s 和 v2s 改成 Cs 和 Ds,所以谁读了它很快就会明白我们在谈论专栏
    • 这确实快很多
    【解决方案5】:

    它对我有用:

    def myfunc1(row):
        C = row['A'] + 10
        D = row['A'] + 50
        return C, D
    
    df = pd.DataFrame(np.random.randint(0,10,size=(2, 2)), columns=list('AB'))
    
    df[['C', 'D']] = df.apply(myfunc1, axis=1, result_type='expand')
    df
    

    添加:==>> result_type='expand',

    问候!

    【讨论】:

      【解决方案6】:

      我相信在不使用 for 循环的情况下可以达到与@Federico Dorato 回答类似的结果。返回一个列表而不是一个系列,并使用 lambda-apply + to_list() 来扩展结果。

      它的代码更简洁,并且在 10,000,000 行的随机 df 上执行得一样好或更快。

      费德里科的代码

      run_time = []
      
      for i in range(0,25):
          df = pd.DataFrame(np.random.randint(0,10000000,size=(2, 2)), columns=list('AB'))
          def run_loopy(df):
              Cs, Ds = [], []
              for _, row in df.iterrows():
                  c, d, = myfunc1(row['A'])
                  Cs.append(c)
                  Ds.append(d)
              return pd.Series({'C': Cs,
                              'D': Ds})
      
          def myfunc1(a):
              c = a / 10
              d = a + 50
              return c, d
      
          start = time.time()
          df[['C', 'D']] = run_loopy(df)
          end = time.time()
      
          run_time.append(end-start) 
      print(np.average(run_time)) # 0.001240386962890625
      

      使用 lambda 和 to_list

      run_time = []
      
      for i in range(0,25):
          df = pd.DataFrame(np.random.randint(0,10000000,size=(2, 2)), columns=list('AB'))
      
          def myfunc1(a):
              c = a / 10
              d = a + 50
              return [c, d]
      
          start = time.time()
          df[['C', 'D']] = df['A'].apply(lambda x: myfunc1(x)).to_list()
          end = time.time()
      run_time.append(end-start)
      print(np.average(run_time)) #output 0.0009996891021728516
      

      【讨论】:

        猜你喜欢
        • 2021-10-20
        • 1970-01-01
        • 1970-01-01
        • 2018-02-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-07
        • 2021-06-03
        相关资源
        最近更新 更多