提问人:gowerc 提问时间:4/10/2018 最后编辑:gowerc 更新时间:4/10/2018 访问量:152
从多个其他变量创建 pandas 变量的 pythonic 方法是什么
What is the pythonic way of creating a pandas variable from multiple other variables
问:
我是一名 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 的问题是它看起来非常冗长。此外,您需要自行引用回起始数据集,这意味着如果要将多个派生链接在一起,则必须将数据集写出到中间变量,即使您无意保留它。
Attempt2 的语法明显更简洁,但仍然存在中间变量问题。另一个问题是,该函数需要一个数据帧,这使得函数更难进行单元测试,灵活性较低,并且不太清楚输入应该是什么。
就功能而言,Attempt3 对我来说似乎是最好的,因为它为您提供了一个清晰的可测试功能,并且不需要保存中间数据集。主要的缺点是你现在必须有 2 个函数,这感觉像是多余的代码。
任何帮助或建议将不胜感激。
答:
您可以依靠它来完成这项工作,方法是创建一个包含 的列,然后根据 的值将其更改为 。然后,您可以使用该列根据需要执行算术运算。Series.where
10
-10
cls
https://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.where.html
分步(详细)示例:
df['what_to_add'] = 10
df['what_to_add'] = df['what_to_add'].where(df['cls'] == 'a', -10)
df['num'] = df['num'] + df['what_to_add']
假设两个数字相反,另一种可能性是为操作数的符号定义一列:
df['sign'] = 1 - 2 * (df['cls'] == 'a').astype(int)
df['num'] = df['num'] + df['sign'] * 10
第三种方法是使用 ,以便将“a”替换为 10,“b”替换为 -10:replace
df['what_to_add'] = df['cls'].replace(['a', 'b'], [10, -10])
df['num'] = df['num'] + df['what_to_add']
已编辑:
或者,按照JPP(https://stackoverflow.com/a/49748695/4582949)的建议,使用:map
df['num2'] += df['cls'].map({'a': 10, 'b': -10})
评论
df["new_var"] = fun( df["var1"] , df["var2"] , ... )
def (n1 , n2 , c3): if n1 > n2 and c3 in ["a" , "b"]: return n2 + n1 * 2 if n2**3 == n1/2 and c3 not in ["c"] return(n1) else: return(n2 / 2)
.apply
numpy.where(cond, x, y)
x
cond
y
一种有效的方法是使用:pd.Series.map
df['num2'] += df['cls'].map({'a': 10, 'b': -10})
这使用字典将值映射到 10 或 -10。cls
还有许多其他方法(参见 @Guybrush 的答案),但基于字典的方法对于较大的数据帧是可扩展且有效的。在我看来,它也是可读的。
评论
df["new_var"] = fun( df["var1"] , df["var2"] , ... )
def (n1 , n2 , c3): if n1 > n2 and c3 in ["a" , "b"]: return n2 + n1 * 2 if n2**3 == n1/2 and c3 not in ["c"] return(n1) else: return(n2 / 2)
pd.DataFrame.apply
pandas
pandas
上一个:如何在 R 中拟合脆弱生存模型
下一个:如何在会话启动时获取密码
评论
pd.DataFrame.apply