Pandas 应用返回两个新列的函数
Posted
技术标签:
【中文标题】Pandas 应用返回两个新列的函数【英文标题】:Pandas Apply Function That returns two new columns 【发布时间】: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
【问题讨论】:
让它df[['C', 'D']]
你的函数总是需要两列作为输入吗?
@coldspeed,传递的数据帧可能有很多列,但计算只需要两列
Apply pandas function to column to create multiple new columns?的可能重复
【参考方案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
【讨论】:
以上是关于Pandas 应用返回两个新列的函数的主要内容,如果未能解决你的问题,请参考以下文章
将 Pandas 列传递给函数时出现“ValueError:Series 的真值不明确”
如何向 pandas df 添加一个新列,该列从另一个数据帧返回同一组中更大的最小值