我是一名 R 程序员,目前正在尝试学习 Python/Pandas。目前,我正在努力解决如何从使用多个现有变量的函数中清晰干净地创建新变量的问题。
请注意,我的示例中使用的函数并没有那么复杂,但我试图将其概括为可能更复杂或需要更多变量的任意函数的情况,也就是说 我正在尝试避免针对此特定功能优化的解决方案,并更多地关注如何处理一般情况。
作为引用,这是我如何在 R 中执行此操作的示例。
library(tidyverse)
df <- data_frame(
num = c(15, 52 , 24 , 29),
cls = c("a" , "b" , "b", "a")
)
attempt1 <- function( num , cls){
if ( cls == "a") return( num + 10)
if ( cls == "b") return( num - 10)
}
## Example 1
df %>%
mutate( num2 = map2_dbl( num , cls , attempt1))
## Example 2
df %>%
mutate( num = ifelse( num <= 25 , num + 10 , num)) %>%
mutate( num2 = map2_dbl( num , cls , attempt1))
阅读 pandas 文档以及各种 SO 帖子后,我发现了多种在 python 中实现此目的的方法,但是它们都不适合我。作为引用,我在下面发布了我当前的 3 个解决方案:
import pandas as pd
import numpy as np
df = pd.DataFrame({
"num" : [14, 52 , 24 , 29],
"cls" : ["a" , "b" , "b" ,"a"]
})
### Example 1
def attempt1( num, cls):
if cls == "a":
return num + 10
if cls == "b":
return num - 10
df.assign( num2 = df.apply( lambda x: attempt1(x["num"] , x["cls"]) , axis = 1))
def attempt2( df):
if df["cls"] == "a":
return df["num"] + 10
if df["cls"] == "b":
return df["num"] - 10
df.assign( num2 = df.apply(attempt2, axis=1))
def attempt3(df):
df["num2"] = attempt1(df["num"], df["cls"])
return df
df.apply( attempt3 , axis = 1)
### Example 2
df.assign( num = np.where( df["num"] <= 25 , df["num"] + 10 , df["num"]))\
.apply( attempt3 , axis = 1)
我对尝试 1 的问题是它看起来非常冗长。此外,您需要 self 引用回您的起始数据集,这意味着如果您想将多个推导链接在一起,即使您无意保留它,也必须将您的数据集写出到中间变量。
Attempt2 的语法清晰得多,但仍然存在中间变量问题。另一个问题是该函数需要一个数据框,这使得该函数更难进行单元测试,灵 active 降低,输入应该是什么也不太清楚。
就功能而言,Attempt3 对我来说似乎是最好的,因为它为您提供了清晰的可测试功能,并且不需要保存中间数据集。主要的缺点是你现在必须有 2 个函数,感觉像是冗余代码。
如有任何帮助或建议,我们将不胜感激。
最佳答案
一种有效的方法是使用pd.Series.map
:
df['num2'] += df['cls'].map({'a': 10, 'b': -10})
这使用字典将 cls
的值映射到 10 或 -10。
还有许多其他方法(参见 @Guybrush's answer ),但是基于字典的方法对于更大的数据帧是可扩展且高效的。在我看来,它也是可读的。
相关:Replace values in a pandas series via dictionary efficiently
关于python - 从多个其他变量创建一个 pandas 变量的 pythonic 方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49748498/