python - 使用 apply() 两次创建新列会导致覆盖新列
问题描述
我已经编写了一些等效于这个玩具示例的 pandas 代码:
df_test = pd.DataFrame({'product': [0, 0, 1, 1], 'sold_for': [5000, 4500, 10000, 8000]})
def product0_makes_profit(row, product0_cost):
return row['sold_for'] > product0_cost
def product1_makes_profit(row, product1_cost):
return row['sold_for'] > product1_cost
df_test['made_profit'] = df_test[df_test['product']==0].apply(product0_makes_profit, args=[4000], axis=1, result_type="expand")
df_test['made_profit'] = df_test[df_test['product']==1].apply(product1_makes_profit, args=[9000], axis=1, result_type="expand")
df_test
我得到以下结果:
product sold_for made_profit
0 0 5000 NaN
1 0 4500 NaN
2 1 10000 True
3 1 8000 False
我希望第 0 行和第 1 行的“made_profit”列是 True,而不是 NaN,但显然第二个 apply() 会覆盖由第一个 apply() 创建的 made_profit 列。
我怎样才能得到我期望的专栏?我不想用第一个 apply() 创建一个列“product0_made_profit”,用第二个 apply() 创建一个列“product1_made_profit”,所以我可以将两个列合并到我想要的一个“made_profit”列中,因为在我的真实代码中,我在产品列中有很多不同的值(意味着要应用很多不同的功能)。
编辑
我的玩具示例太简单了,实际上我创建了两个新列:
def product0_makes_profit(row, product0_cost):
return [row['sold_for'] > product0_cost, row['sold_for'] - product0_cost]
def product1_makes_profit(row, product1_cost):
return [row['sold_for'] > product1_cost, row['sold_for'] - product1_cost]
使用当前答案,我做了这个:
is_prod0 = (df_test['product']==0)
df_test.loc[is_prod0, ['made_profit', 'profit_amount']] = df_test[is_prod0].apply(product0_makes_profit, args=[4000], axis=1, result_type="expand")
is_prod1 = (df_test['product']==1)
df_test.loc[is_profd1, ['made_profit', 'profit_amount']] = df_test[is_prod1].apply(product1_makes_profit, args=[9000], axis=1, result_type="expand")
print(df_test)
但这给了我以下错误(在第一次使用 .loc 时):
KeyError: "None of [Index(['made_profit', 'profit_amount'], dtype='object')] are in the [columns]"
我可以使用以下代码使其工作:
is_prod0 = (df_test['product']==0)
newdf = df_test[is_prod0].apply(product0_makes_profit, args=[4000], axis=1, result_type="expand")
is_prod1 = (df_test['product']==1)
newerdf = df_test[is_prod1].apply(product1_makes_profit, args=[9000], axis=1, result_type="expand")
newcols = pd.concat([newdf, newerdf])
newcols.columns = ['was_profit_made', 'profit_amount']
df_test.join(newcols)
然而,这涉及 concat() 和 join() 并且如上所述,在实际代码中会变得有点乏味(但通过在所有产品值上构建循环是可行的) - 也许对多列也有一个优雅的解决方案。
解决方案
您需要分配给具有相同条件的过滤行loc
,因此仅在条件为时处理行True
:
m1 = df_test['product']==0
m2 = df_test['product']==1
df_test.loc[m1, 'made_profit'] = df_test[m1].apply(product0_makes_profit, args=[4000], axis=1, result_type="expand")
df_test.loc[m2, 'made_profit'] = df_test[m2].apply(product1_makes_profit, args=[9000], axis=1, result_type="expand")
print (df_test)
product sold_for made_profit
0 0 5000 True
1 0 4500 True
2 1 10000 True
3 1 8000 False
编辑:
function
如果从需要返回多个值Series
并按新列名返回索引,则还需要NaN
在之前创建填充一些默认值(例如)的新列loc
:
cols = ['made_profit', 'profit_amount']
def product0_makes_profit(row, product0_cost):
return pd.Series([row['sold_for'] > product0_cost, row['sold_for'] - product0_cost], index=cols)
def product1_makes_profit(row, product1_cost):
return pd.Series([row['sold_for'] > product1_cost, row['sold_for'] - product1_cost], index=cols)
for c in cols:
df_test[c] = np.nan
is_prod0 = (df_test['product']==0)
df_test.loc[is_prod0, cols] = df_test[is_prod0].apply(product0_makes_profit, args=[4000], axis=1, result_type="expand")
is_prod1 = (df_test['product']==1)
df_test.loc[is_prod1, cols] = df_test[is_prod1].apply(product1_makes_profit, args=[9000], axis=1, result_type="expand")
print(df_test)
product sold_for made_profit profit_amount
0 0 5000 True 1000.0
1 0 4500 True 500.0
2 1 10000 True 1000.0
3 1 8000 False -1000.0
推荐阅读
- java - 在java中使用线程读取和写入文件
- python - Convert string to the list it describes
- python - How to apply some features into a deep learning model?
- projection - How can I set extent when .prj files are identical?
- r - 通过变量迭代计算预测模型结果
- r - 不能从 R 中压缩目录而不包括完整的文件路径
- asp.net - Azure AD 中的 jwt-bearer 代表授权问题
- html - 使用类更改ul li中的字体颜色
- ansible - Make ansible ignore variable in template when checking changed state
- javascript - Javascript - 按钮的 rowIndex 在表格中不起作用