根据条件更改变量值
Changing variable value based on condition
我有数据框:
a<-c(1,2,3,4)
b<-c(1988,1970,1999,2000)
years_practicing<-rep(NA,4)
df<-data.frame("ID"=a, "grad_year"=b, "years_practicing"=years_practicing)
看起来像:
ID grad_year years_practicing
1 1988 NA
2 1970 NA
3 1999 NA
4 2000 NA
现在我想这样做(这是伪代码!):
if (ID=1 || ID=2)
{
years_practicing[corresponding cell]<-2017-grad_year
}
if (ID=3 || ID=4)
{
years_practicing[corresponding cell]<-2018-grad_year
}
实现这个:
ID grad_year years_practicing
1 1988 29
2 1970 47
3 1999 19
4 2000 18
我知道如何以程序方式进行(使用 while
循环和 if
语句),但我想以矢量化方式进行。
我试过这个(和类似的变体):
year_2017_start<-c(1, 2)
year_2018_start<-c(3,4)
df$years_practicing[any(df$ID == year_2017_start)]<- 2017-df$grad_yr
df$years_practicing[any(df$ID == year_2018_start)]<- 2018-df$grad_yr
但是接收错误:
Error in df$years_practicing[any(df$ID == year_2017_start)] <- 2017 - :
replacement has length zero
> df$years_practicing[any(df$ID == year_2018_start)]<- 2018-df$grad_yr
Error in df$years_practicing[any(df$ID == year_2018_start)] <- 2018 - :
replacement has length zero
问题:
如何改进我的代码以使其工作。 (需要回答)
有没有更快的方法来达到类似的结果? (可选)
你可以使用 dplyr
:
library(dplyr)
df %>%
mutate(years_practicing = ifelse(ID == 1 | ID == 2,
2017-grad_year,
2018-grad_year))
如果您要测试两个以上的条件(例如,如果您有三年 - 2017、2018 和 2019),您可以使用 case_when:
df %>%
mutate(years_practicing = case_when(
ID == 1 | ID == 2 ~ 2017-grad_year,
ID == 3 ~ 2018-grad_year,
TRUE ~ 2019-grad_year)
)
编辑:比较给定答案的表现
我很好奇每个解决方案的速度有多快。我比较了截至 2019 年 8 月 29 日建议的解决方案。@Chuan 的回答获胜!那很有趣...
library(microbenchmark)
library(dplyr)
a<-sample(c(1,2,3,4), 20000, replace = TRUE)
b<-sample(c(1988:2015), 20000, replace = TRUE)
years_practicing<-rep(NA, 20000)
df<-data.frame("ID"=a, "grad_year"=b, "years_practicing"=years_practicing)
year_2017_start<-c(1, 2)
year_2018_start<-c(3,4)
v1 = c(`1` = 2017,
`2` = 2017,
`3` = 2018,
`4` = 2018)
mb <- microbenchmark(
df$years_practicing[which(df$ID == year_2017_start)]<- 2017-df$grad_year[which(df$ID == year_2017_start)],
transform(df, years_practicing = 2018 - (ID %in% 1:2) - grad_year),
df %>%
mutate(years_practicing = ifelse(ID == 1 | ID == 2,
2017-grad_year,
2018-grad_year)),
v1[match(df$ID, names(v1))] - df$grad_year,
times=500)
ggplot2::autoplot(mb)
您可以使用命名向量
v1 = c(`1` = 2017,
`2` = 2017,
`3` = 2018,
`4` = 2018)
v1[df$ID] - df$grad_year
# 1 2 3 4
#29 47 19 18
此单行仅使用基数 R。如果 ID 为 1 或 2,则显示的 %in%
表达式的计算结果为 TRUE,否则计算结果为 FALSE。从 2018 中减去时,它们分别转换为 1 和 0,然后我们从中减去 grad_year
。
transform(df, years_practicing = 2018 - (ID %in% 1:2) - grad_year)
给予:
ID grad_year years_practicing
1 1 1988 29
2 2 1970 47
3 3 1999 19
4 4 2000 18
不确定您必须使用矢量化方法更新值的动机;但是一些矢量化函数,例如 ifelse()
在这里可能会有更好的帮助。无论如何,下面是您想要的矢量化解决方案:
df$years_practicing[which(df$ID == year_2017_start)]<- 2017-df$grad_year[which(df$ID == year_2017_start)]
我有数据框:
a<-c(1,2,3,4)
b<-c(1988,1970,1999,2000)
years_practicing<-rep(NA,4)
df<-data.frame("ID"=a, "grad_year"=b, "years_practicing"=years_practicing)
看起来像:
ID grad_year years_practicing
1 1988 NA
2 1970 NA
3 1999 NA
4 2000 NA
现在我想这样做(这是伪代码!):
if (ID=1 || ID=2)
{
years_practicing[corresponding cell]<-2017-grad_year
}
if (ID=3 || ID=4)
{
years_practicing[corresponding cell]<-2018-grad_year
}
实现这个:
ID grad_year years_practicing
1 1988 29
2 1970 47
3 1999 19
4 2000 18
我知道如何以程序方式进行(使用 while
循环和 if
语句),但我想以矢量化方式进行。
我试过这个(和类似的变体):
year_2017_start<-c(1, 2)
year_2018_start<-c(3,4)
df$years_practicing[any(df$ID == year_2017_start)]<- 2017-df$grad_yr
df$years_practicing[any(df$ID == year_2018_start)]<- 2018-df$grad_yr
但是接收错误:
Error in df$years_practicing[any(df$ID == year_2017_start)] <- 2017 - :
replacement has length zero
> df$years_practicing[any(df$ID == year_2018_start)]<- 2018-df$grad_yr
Error in df$years_practicing[any(df$ID == year_2018_start)] <- 2018 - :
replacement has length zero
问题:
如何改进我的代码以使其工作。 (需要回答)
有没有更快的方法来达到类似的结果? (可选)
你可以使用 dplyr
:
library(dplyr)
df %>%
mutate(years_practicing = ifelse(ID == 1 | ID == 2,
2017-grad_year,
2018-grad_year))
如果您要测试两个以上的条件(例如,如果您有三年 - 2017、2018 和 2019),您可以使用 case_when:
df %>%
mutate(years_practicing = case_when(
ID == 1 | ID == 2 ~ 2017-grad_year,
ID == 3 ~ 2018-grad_year,
TRUE ~ 2019-grad_year)
)
编辑:比较给定答案的表现
我很好奇每个解决方案的速度有多快。我比较了截至 2019 年 8 月 29 日建议的解决方案。@Chuan 的回答获胜!那很有趣...
library(microbenchmark)
library(dplyr)
a<-sample(c(1,2,3,4), 20000, replace = TRUE)
b<-sample(c(1988:2015), 20000, replace = TRUE)
years_practicing<-rep(NA, 20000)
df<-data.frame("ID"=a, "grad_year"=b, "years_practicing"=years_practicing)
year_2017_start<-c(1, 2)
year_2018_start<-c(3,4)
v1 = c(`1` = 2017,
`2` = 2017,
`3` = 2018,
`4` = 2018)
mb <- microbenchmark(
df$years_practicing[which(df$ID == year_2017_start)]<- 2017-df$grad_year[which(df$ID == year_2017_start)],
transform(df, years_practicing = 2018 - (ID %in% 1:2) - grad_year),
df %>%
mutate(years_practicing = ifelse(ID == 1 | ID == 2,
2017-grad_year,
2018-grad_year)),
v1[match(df$ID, names(v1))] - df$grad_year,
times=500)
ggplot2::autoplot(mb)
您可以使用命名向量
v1 = c(`1` = 2017,
`2` = 2017,
`3` = 2018,
`4` = 2018)
v1[df$ID] - df$grad_year
# 1 2 3 4
#29 47 19 18
此单行仅使用基数 R。如果 ID 为 1 或 2,则显示的 %in%
表达式的计算结果为 TRUE,否则计算结果为 FALSE。从 2018 中减去时,它们分别转换为 1 和 0,然后我们从中减去 grad_year
。
transform(df, years_practicing = 2018 - (ID %in% 1:2) - grad_year)
给予:
ID grad_year years_practicing
1 1 1988 29
2 2 1970 47
3 3 1999 19
4 4 2000 18
不确定您必须使用矢量化方法更新值的动机;但是一些矢量化函数,例如 ifelse()
在这里可能会有更好的帮助。无论如何,下面是您想要的矢量化解决方案:
df$years_practicing[which(df$ID == year_2017_start)]<- 2017-df$grad_year[which(df$ID == year_2017_start)]