有条件地替换data.frame中的值

djq*_*djq 65 r dataframe

我试图了解如何在不使用循环的情况下条件替换数据帧中的值.我的数据框架结构如下:

> df
          a b est
1  11.77000 2   0
2  10.90000 3   0
3  10.32000 2   0
4  10.96000 0   0
5   9.90600 0   0
6  10.70000 0   0
7  11.43000 1   0
8  11.41000 2   0
9  10.48512 4   0
10 11.19000 0   0
Run Code Online (Sandbox Code Playgroud)

dput输出是这样的:

structure(list(a = c(11.77, 10.9, 10.32, 10.96, 9.906, 10.7, 
11.43, 11.41, 10.48512, 11.19), b = c(2, 3, 2, 0, 0, 0, 1, 2, 
4, 0), est = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)), .Names = c("a", 
"b", "est"), row.names = c(NA, -10L), class = "data.frame")
Run Code Online (Sandbox Code Playgroud)

我想做的是检查价值b.如果b为0,我想设置est为一个值a.据我所知,df$est[df$b == 0] <- 23将所有值设置est为23,何时b==0.我不明白的是如何设置est为值a时条件为真.例如:

df$est[df$b == 0] <- (df$a - 5)/2.533 
Run Code Online (Sandbox Code Playgroud)

发出以下警告:

Warning message:
In df$est[df$b == 0] <- (df$a - 5)/2.533 :
  number of items to replace is not a multiple of replacement length
Run Code Online (Sandbox Code Playgroud)

有没有办法可以传递相关的单元格,而不是矢量?

And*_*rie 79

由于您是有条件索引的df$est,因此还需要有条件地索引替换向量df$a:

index <- df$b == 0
df$est[index] <- (df$a[index] - 5)/2.533 
Run Code Online (Sandbox Code Playgroud)

当然,变量index只是暂时的,我使用它来使代码更容易读取.您可以一步编写它:

df$est[df$b == 0] <- (df$a[df$b == 0] - 5)/2.533 
Run Code Online (Sandbox Code Playgroud)

为了更好的可读性,您可以使用within:

df <- within(df, est[b==0] <- (a[b==0]-5)/2.533)
Run Code Online (Sandbox Code Playgroud)

结果,无论您选择哪种方法:

df
          a b      est
1  11.77000 2 0.000000
2  10.90000 3 0.000000
3  10.32000 2 0.000000
4  10.96000 0 2.352941
5   9.90600 0 1.936834
6  10.70000 0 2.250296
7  11.43000 1 0.000000
8  11.41000 2 0.000000
9  10.48512 4 0.000000
10 11.19000 0 2.443743
Run Code Online (Sandbox Code Playgroud)

正如其他人所指出的那样,您的示例中的替代解决方案是使用ifelse.


Mat*_*wle 27

试试data.table:=运算符:

DT = as.data.table(df)
DT[b==0, est := (a-5)/2.533]
Run Code Online (Sandbox Code Playgroud)

它快而短.请参阅有关详细信息,这些链接的问题:=:

为什么定义了data.table :=

我什么时候应该使用:=操作员data.table

如何从a中删除列 data.frame

R自我参考


Ram*_*ath 18

这是一种方法.ifelse是矢量,它会检查所有行的值为零b,并替换est(a - 5)/2.53,如果是这样的话.

df <- transform(df, est = ifelse(b == 0, (a - 5)/2.53, est))
Run Code Online (Sandbox Code Playgroud)


Car*_*oft 6

R-地狱,或基本R-文档将解释为什么使用DF $*是不是最好的方法在这里.在"["的帮助页面中:

"索引由[类似于原子向量并选择指定元素的列表.两者[[和$选择列表中的单个元素.主要区别在于$不允许计算索引,而[[确实如此] .x $ name相当于x [["name",exact = FALSE]].另外,[[可以使用exact参数控制]的部分匹配行为.

我建议改用[row,col]符号.例:

Rgames: foo   
         x    y z  
   [1,] 1e+00 1 0  
   [2,] 2e+00 2 0  
   [3,] 3e+00 1 0  
   [4,] 4e+00 2 0  
   [5,] 5e+00 1 0  
   [6,] 6e+00 2 0  
   [7,] 7e+00 1 0  
   [8,] 8e+00 2 0  
   [9,] 9e+00 1 0  
   [10,] 1e+01 2 0  
Rgames: foo<-as.data.frame(foo)

Rgames: foo[foo$y==2,3]<-foo[foo$y==2,1]
Rgames: foo
       x y     z
1  1e+00 1 0e+00
2  2e+00 2 2e+00
3  3e+00 1 0e+00
4  4e+00 2 4e+00
5  5e+00 1 0e+00
6  6e+00 2 6e+00
7  7e+00 1 0e+00
8  8e+00 2 8e+00
9  9e+00 1 0e+00
10 1e+01 2 1e+01
Run Code Online (Sandbox Code Playgroud)


Hol*_*ndl 5

Another option would be to use case_when

require(dplyr)

transform(df, est = case_when(
    b == 0 ~ (a - 5)/2.53, 
    TRUE   ~ est 
))
Run Code Online (Sandbox Code Playgroud)

This solution becomes even more handy if more than 2 cases need to be distinguished, as it allows to avoid nested if_else constructs.