我经常需要根据因子变量的条件从数据框中的现有变量计算新变量。
编辑在2分钟内得到4个答案,我意识到我已经过度简化了我的例子。请参阅下文。
简单示例:
df <- data.frame(value=c(1:5),class=letters[1:5])
df
value class
1 a
2 b
3 c
4 d
5 e
我可以使用这样的代码
df %>%
mutate(result=NA) %>%
mutate(result=ifelse(class=="a",value*1,result)) %>%
mutate(result=ifelse(class=="b",value*2,result)) %>%
mutate(result=ifelse(class=="c",value*3,result)) %>%
mutate(result=ifelse(class=="d",value*4,result)) %>%
mutate(result=ifelse(class=="e",value*5,result))
对我的变量执行条件计算,得到
value class result
1 a 1
2 b 4
3 c 9
4 d 16
5 e 25
实际上,类的数量更大,计算更复杂,但是,我更喜欢更清洁的东西,比如
df %>%
mutate(results=switch(levels(class),
"a"=value*1,
"b"=value*2,
"c"=value*3,
"d"=value*4,
"e"=value*5))
显然不起作用
Error in switch(levels(1:5), a = 1:5 * 1, b = 1:5 * 2, c = 1:5 * 3, d = 1:5 * :
EXPR must be a length 1 vector
有没有办法可以用dplyr管道(或其他)更好地做到这一点?
修改 实际上,我有更多的值变量要包含在我的计算中,它们不是简单的连续向量,它们是数千行测量数据。
这是我的第二个随机值变量的简单示例(同样,它在我的实际数据中更多)
df <- data.frame(value1=c(1:5),value2=c(2.3,3.6,7.2,5.6,0),class=letters[1:5])
value1 value2 class
1 2.3 a
2 3.6 b
3 7.2 c
4 5.6 d
5 0.0 e
我的计算方法因各种条件而异。我明白我可以像这样简化
df %>%
mutate(result=NA,
result=ifelse(class=="a",value1*1,result),
result=ifelse(class=="b",value1/value2*4,result),
result=ifelse(class=="c",value2*3.57,result),
result=ifelse(class=="d",value1+value2*2,result),
result=ifelse(class=="e",value2/value1/5,result))
与上述开关示例类似的工作解决方案更加清晰。
答案 0 :(得分:9)
此处无需使用ifelse
,您可以使用merge
:
df <- data.frame(value=c(1:5),class=letters[1:5])
cond <- data.frame(ratio=c(1:5),class=letters[1:5])
transform(merge(df,cond),result=value*ratio)
class value ratio result
1 a 1 1 1
2 b 2 2 4
3 c 3 3 9
4 d 4 4 16
5 e 5 5 25
看起来OP希望为每个类应用不同的函数。 这是一个data.table解决方案。我认为它简单易读。 首先,我为每个因素创建函数:
## here each function takes a data.table as an single argument
fns <- list(
function(x) x[,value1]*1,
function(x) x[,value1]/x[,value2]*4,
function(x) x[,value2]*3.57,
function(x) x[,value1]+x[,value2]*2,
function(x) x[,value2]/x[,value1]/5
)
## create a names list here
## the names here are just the class factors
fns <- setNames(fns,letters[1:5])
按类应用函数很简单。我创建了函数名称,并使用do.call
通过名称
## using data.table here for grouping feature
## .SD is the rest of columns except the grouping variable
## the code can also be written in dplyr or in base-R
library(data.table)
setDT(df)[,value:= fns[[class]](.SD),by=class]
value1 value2 class value
1: 1 2.3 a 1.000000
2: 2 3.6 b 2.222222
3: 3 7.2 c 25.704000
4: 4 5.6 d 15.200000
5: 5 0.0 e 0.000000
6: 1 2.3 a 1.000000
7: 2 3.6 b 2.222222
8: 3 7.2 c 25.704000
9: 4 5.6 d 15.200000
10: 5 0.0 e 0.000000
我用这个df:
df <- data.frame(value1=c(1:5),value2=c(2.3,3.6,7.2,5.6,0),
class=rep(letters[1:5],2))
答案 1 :(得分:3)
正如我在评论中提到的那样,this question或多或少与此相同(你应该在那里阅读答案以了解下面的内容):
library(data.table)
dt = as.data.table(df) # or setDT to convert in place
dt[, class := as.character(class)] # simpler
# create a data.table with *functions* to match each class
fns = data.table(cls = letters[1:5], fn = list(quote(value1*1), quote(value1/value2*4), quote(value2*3.57), quote(value1+value2*2), quote(value2/value1/5)), key = 'cls')
# I have to jump through hoops here, due to a bug or two, see below
setkey(dt, class)
newvals = dt[, eval(fns[class]$fn[[1]], .SD), by = class]$V1
dt[, result := newvals][]
# value1 value2 class result
#1: 1 2.3 a 1.000000
#2: 2 3.6 b 2.222222
#3: 3 7.2 c 25.704000
#4: 4 5.6 d 15.200000
#5: 5 0.0 e 0.000000
由于以下data.table
中的一些错误,直接版本尚未完成:
dt[, result := eval(fns[class]$fn[[1]], .SD), by = class]
# or even better
dt[fns, result := eval(fn[[1]], .SD), by = .EACHI]
已提交错误报告。
我在下面的Frank的评论中添加了这个建议,因为我觉得它非常酷,而且这种方式更有可能被保留在SO中。创建函数表的更易读的方法如下:
quotem <- function(...) as.list(sys.call())[-1]
fnslist <- quotem(a = value1*1,
b = value1/value2*4,
c = value2*3.57,
d = value1+value2*2,
e = value2/value1/5)
fns = data.table(cls=names(fnslist),fn=fnslist,key="cls")
答案 2 :(得分:2)
使用dplyr
和@agstudy示例的相似想法:
library(dplyr)
df %>%
left_join(cond) %>%
mutate(result = value * ratio)
给出了:
# value class ratio result
#1 1 a 1 1
#2 2 b 2 4
#3 3 c 3 9
#4 4 d 4 16
#5 5 e 5 25
答案 3 :(得分:2)
这是@ agstudy答案的rdd2 = rdd1.map (_.modifier(18) )
/ dplyr
实现:
lazyeval