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

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

> 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

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")

我想做的是检查 b的值。如果 b为0,我希望将 est设置为来自 a的值。我知道 df$est[df$b == 0] <- 23est的所有值设置为23,当 b==0。我不明白的是如何设置 est的值为 a当该条件为真。例如:

df$est[df$b == 0] <- (df$a - 5)/2.533

发出以下警告:

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

有没有办法让我传递相关的细胞,而不是载体?

248877 次浏览

这里有一个方法。对 ifelse进行向量化,检查所有行的 b值为零,如果是这样,则用 (a - 5)/2.53替换 est

df <- transform(df, est = ifelse(b == 0, (a - 5)/2.53, est))

因为您有条件地索引 df$est,所以您还需要有条件地索引替换向量 df$a:

index <- df$b == 0
df$est[index] <- (df$a[index] - 5)/2.533

当然,变量 index只是临时的,我使用它来使代码更易读一些。你可以一步写出来:

df$est[df$b == 0] <- (df$a[df$b == 0] - 5)/2.533

为了获得更好的可读性,你可以使用 within:

df <- within(df, est[b==0] <- (a[b==0]-5)/2.533)

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

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

正如其他人指出的那样,您的示例中的另一种解决方案是使用 ifelse

地... 地狱或基本的 R 文档将解释为什么使用 df $* 不是最好的方法。来自“[”的帮助页面:

”通过[索引类似于原子向量并选择指定元素的列表。 [和 $都选择列表中的一个元素。主要区别在于 $不允许计算索引,而[[允许。X $name 等价于 x [[“ name”精确 = FALSE ]]。此外,可以使用精确的参数控制[[的部分匹配行为

我建议改用 [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

试试 Data.table:=操作员:

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

这是快速和简短的。看看这些相关的问题,了解更多关于 :=的信息:

为什么 data.table 定义了 :=

什么时候应该在 data.table中使用 :=操作符

如何从 data.frame中删除列

自我引用

另一种选择是使用 例 _ 时

require(dplyr)


mutate(df, est = case_when(
b == 0 ~ (a - 5)/2.53,
TRUE   ~ est
))

如果需要区分2个以上的情况,这种解决方案将变得更加方便,因为它允许避免嵌套的 if_else构造。