r 中带有 paste0() 或 grep() 的 if() 语句
if() statement with paste0() or grep() in r
我制作了可重现的最小示例,但我的真实数据非常庞大
ac_1 <-c(0.1, 0.3, 0.03, 0.03)
ac_2 <-c(0.2, 0.4, 0.1, 0.008)
ac_3 <-c(0.8, 0.043, 0.7, 0.01)
ac_4 <-c(0.2, 0.73, 0.1, 0.1)
c_2<-c(1,2,5,23)
check_1<-c(0.01, 0.902,0.02,0.07)
check_2<-c(0.03, 0.042,0.002,0.00001)
check_3<-c(0.01, 0.02,0.5,0.001)
check_4<-c(0.001, 0.042,0.02,0.2)
id<-1:4
df<-data.frame(id,ac_1, ac_2,ac_3,ac_4,c_2,check_1,check_2,check_3,check_4)
所以,数据框是这样的:
> df
id ac_1 ac_2 ac_3 ac_4 c_2 check_1 check_2 check_3 check_4
1 1 0.10 0.200 0.800 0.20 1 0.010 0.03000 0.010 0.001
2 2 0.30 0.400 0.043 0.73 2 0.902 0.04200 0.020 0.042
3 3 0.03 0.100 0.700 0.10 5 0.020 0.00200 0.500 0.020
4 4 0.03 0.008 0.010 0.10 23 0.070 0.00001 0.001 0.200
而我想做的是,
如果check_1是0.02,我会把对应的ac_1设为缺失数据。
如果check_2是0.02,我会把对应的ac_2设为缺失数据。
我将在每个“检查”和“ac”列中继续这样做
例如,在check_1列中,第3个id的人有0.02。
所以,此人的 ac_1 分数应该是缺失数据——0.03 应该是缺失数据 (NA)
在check_3列中,第2个id的人有0.02。
所以,这个人的ac_3分数应该是缺失数据。
在check_4列中,第3个id的人有0.02
所以,这个人的 ac_4 分数应该是缺失数据。
所以。我所做的如下:
for(i in 1:4){
if(paste0("df$check_",i)==0.02){
paste0("df$ac_",i)==NA
}
}
但是,它没有用...
你真的很接近,但你在一些基础知识上有偏差。
您不能(轻易地)使用字符串来引用对象,因此“df$check_1”将不起作用。您可以使用字符串来引用列名,但不能使用 $
,您需要使用 [
或 [[
,因此 df[["check_1"]]
将起作用。
if
未矢量化,因此它不适用于列中的每个值。使用 ifelse
代替,或者在这种情况下更好,我们可以完全跳过 if
。
由于精度问题,在 non-integer 数字上使用 ==
是有风险的。我们将改用公差。
小问题,paste0("df$ac_",i)==NA
不好,==
用于检查相等性。您需要 =
或 <-
才能在该行上进行分配。
解决所有这些问题:
for(i in 1:4){
df[
## rows to replace
abs(df[[paste0("check_", i)]] - 0.02) < 1e-10,
## column to replace
paste0("ac_", i)
] <- NA
}
df
# id ac_1 ac_2 ac_3 ac_4 c_2 check_1 check_2 check_3 check_4
# 1 1 0.10 0.200 0.80 0.20 1 0.010 0.03000 0.010 0.001
# 2 2 0.30 0.400 NA 0.73 2 0.902 0.04200 0.020 0.042
# 3 3 NA 0.100 0.70 NA 5 0.020 0.00200 0.500 0.020
# 4 4 0.03 0.008 0.01 0.10 23 0.070 0.00001 0.001 0.200
使用长格式数据通常会更好,即使只是暂时的。这是一个这样做的例子,使用 dplyr
和 tidyr
:
pivot_longer(df, -c(id,c_2)) %>%
separate(name,into=c("type", "pos")) %>%
pivot_wider(names_from=type, values_from = value) %>%
mutate(ac=if_else(near(check,0.02), as.double(NA), ac)) %>%
pivot_wider(names_from = pos, values_from = ac:check)
(更新 near()
感谢 Gregor)
输出:
id c_2 ac_1 ac_2 ac_3 ac_4 check_1 check_2 check_3 check_4
<int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 1 0.1 0.2 0.8 0.2 0.01 0.03 0.01 0.001
2 2 2 0.3 0.4 NA 0.73 0.902 0.042 0.02 0.042
3 3 5 NA 0.1 0.7 NA 0.02 0.002 0.5 0.02
4 4 23 0.03 0.008 0.01 0.1 0.07 0.00001 0.001 0.2
我制作了可重现的最小示例,但我的真实数据非常庞大
ac_1 <-c(0.1, 0.3, 0.03, 0.03)
ac_2 <-c(0.2, 0.4, 0.1, 0.008)
ac_3 <-c(0.8, 0.043, 0.7, 0.01)
ac_4 <-c(0.2, 0.73, 0.1, 0.1)
c_2<-c(1,2,5,23)
check_1<-c(0.01, 0.902,0.02,0.07)
check_2<-c(0.03, 0.042,0.002,0.00001)
check_3<-c(0.01, 0.02,0.5,0.001)
check_4<-c(0.001, 0.042,0.02,0.2)
id<-1:4
df<-data.frame(id,ac_1, ac_2,ac_3,ac_4,c_2,check_1,check_2,check_3,check_4)
所以,数据框是这样的:
> df
id ac_1 ac_2 ac_3 ac_4 c_2 check_1 check_2 check_3 check_4
1 1 0.10 0.200 0.800 0.20 1 0.010 0.03000 0.010 0.001
2 2 0.30 0.400 0.043 0.73 2 0.902 0.04200 0.020 0.042
3 3 0.03 0.100 0.700 0.10 5 0.020 0.00200 0.500 0.020
4 4 0.03 0.008 0.010 0.10 23 0.070 0.00001 0.001 0.200
而我想做的是,
如果check_1是0.02,我会把对应的ac_1设为缺失数据。 如果check_2是0.02,我会把对应的ac_2设为缺失数据。 我将在每个“检查”和“ac”列中继续这样做
例如,在check_1列中,第3个id的人有0.02。 所以,此人的 ac_1 分数应该是缺失数据——0.03 应该是缺失数据 (NA)
在check_3列中,第2个id的人有0.02。 所以,这个人的ac_3分数应该是缺失数据。
在check_4列中,第3个id的人有0.02 所以,这个人的 ac_4 分数应该是缺失数据。
所以。我所做的如下:
for(i in 1:4){
if(paste0("df$check_",i)==0.02){
paste0("df$ac_",i)==NA
}
}
但是,它没有用...
你真的很接近,但你在一些基础知识上有偏差。
您不能(轻易地)使用字符串来引用对象,因此“df$check_1”将不起作用。您可以使用字符串来引用列名,但不能使用
$
,您需要使用[
或[[
,因此df[["check_1"]]
将起作用。if
未矢量化,因此它不适用于列中的每个值。使用ifelse
代替,或者在这种情况下更好,我们可以完全跳过if
。
由于精度问题,在 non-integer 数字上使用
==
是有风险的。我们将改用公差。小问题,
paste0("df$ac_",i)==NA
不好,==
用于检查相等性。您需要=
或<-
才能在该行上进行分配。
解决所有这些问题:
for(i in 1:4){
df[
## rows to replace
abs(df[[paste0("check_", i)]] - 0.02) < 1e-10,
## column to replace
paste0("ac_", i)
] <- NA
}
df
# id ac_1 ac_2 ac_3 ac_4 c_2 check_1 check_2 check_3 check_4
# 1 1 0.10 0.200 0.80 0.20 1 0.010 0.03000 0.010 0.001
# 2 2 0.30 0.400 NA 0.73 2 0.902 0.04200 0.020 0.042
# 3 3 NA 0.100 0.70 NA 5 0.020 0.00200 0.500 0.020
# 4 4 0.03 0.008 0.01 0.10 23 0.070 0.00001 0.001 0.200
使用长格式数据通常会更好,即使只是暂时的。这是一个这样做的例子,使用 dplyr
和 tidyr
:
pivot_longer(df, -c(id,c_2)) %>%
separate(name,into=c("type", "pos")) %>%
pivot_wider(names_from=type, values_from = value) %>%
mutate(ac=if_else(near(check,0.02), as.double(NA), ac)) %>%
pivot_wider(names_from = pos, values_from = ac:check)
(更新 near()
感谢 Gregor)
输出:
id c_2 ac_1 ac_2 ac_3 ac_4 check_1 check_2 check_3 check_4
<int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 1 0.1 0.2 0.8 0.2 0.01 0.03 0.01 0.001
2 2 2 0.3 0.4 NA 0.73 0.902 0.042 0.02 0.042
3 3 5 NA 0.1 0.7 NA 0.02 0.002 0.5 0.02
4 4 23 0.03 0.008 0.01 0.1 0.07 0.00001 0.001 0.2