我已经找到了在if
语句中使用向量的效率非常低的方法,但无法弄清楚如何使用ifelse()
或sapply()
或更好的方法
我有以下数据:
yes_codes <- c(1,3,7)
yes_year <- 2011
df2 <- data.frame(yes_codes, yes_flags, yes_year)
codes <- c(1:10)
flag <- 'N'
year <- c(2011,2012,2011,2012,2011,2013,2014,2015,2011,2010)
df <- data.frame(codes, flag, year)
> df
codes flag year
1 1 N 2011
2 2 N 2012
3 3 N 2011
4 4 N 2012
5 5 N 2011
6 6 N 2013
7 7 N 2014
8 8 N 2015
9 9 N 2011
10 10 N 2010
> df2
yes_codes yes_flags yes_year
1 1 Y 2011
2 3 Y 2011
3 7 Y 2011
我需要将df$code
与df$yes_codes
匹配,并在匹配时将df$flag
设置为“Y”。我弄清楚如何做到这一点的唯一方法是非常明显的错误
for(i in 1:nrow(df)) {
for(z in 1:nrow(df2)){
if(df$year[i]==2011 | df$year[i]==2012)
if(as.character(df$code)==as.character(df2$yes_code[z]))
if(df$year[i]==df2$yes_year[z])
df$flag[i] <- 'Y'
}
}
我知道您应该使用ifelse()
来执行向量化if
语句,但这不起作用
ifelse(df$year==2011 | df$year==2012, ifelse(df$code==df2$yes_code,
ifelse(df$year==df2$year, df$flag <- 'Y',
df$flag <- 'N'), df$flag <- 'N'), df$flag <- 'N')
每次迭代都会将每个标志设置为“Y”或“N”,而我得到的是最后设置的内容,通常为“N”。我真的以为我找到了一个完美的例子,说明为什么你将<-
和=
用于不同的事情,但是当我为<-
切换=
时它甚至都不会运行
修改
正如索托斯向我解释的那样,ifelse()
只是返回一个函数,所以我需要在其之外设置我的值。我现在的问题是我实际上有几个ifelse()
条件我需要检查,因为例如我有一个适用于2011和2012的规则,另一个适用于2012和更高版本。编写多个ifelse()
语句时,只需用else
输出覆盖前一个语句的输出,如下所示:
df$flag <- ifelse(df$year==2013 & df$codes==df2$yes_code & df$year==df2$yes_year, 'Y', 'N')
df$flag <- ifelse(df$year >= 2012 & df$codes=='4', 'Y', 'N')
df$flag <- ifelse((df$year==2011 | df$year==2012) & df$code==df2$yes_code & df$year==df2$year, 'Y', 'N')
必须使用else
这使得这么困难,还有其他方法可以使用向量化的if
语句吗?
答案 0 :(得分:1)
df3<-merge(df, df2, by.x='codes', by.y='yes_codes',all.x = TRUE)
df3$flag<-ifelse(df3$yes_flags=="Y", "Y", "N")
df3$flag[is.na(df3$flag)]<-"N"
df<-df3[,!(names(df3) %in% names(df2))]
答案 1 :(得分:1)
以下是data.table
的解决方案:
library("data.table")
dt2 <- data.table(yes_codes=c(1,3,7), yes_flags='Y',yes_year=2011)
dt <- data.table(codes=(1:10), flag='N', year=c(2011,2012,2011,2012,2011,2013,2014,2015,2011,2010))
dt[dt2, on=c(codes="yes_codes", year="yes_year"), in.df2:=i.yes_flags]
dt[year==2013 & in.df2=='Y', flag:='Y']
dt[year>=2012 & codes==4, flag:='Y']
dt[(year==2011 | year==2012) & in.df2=='Y', flag:='Y']
dt
# codes flag year in.df2
# 1: 1 Y 2011 Y
# 2: 2 N 2012 NA
# 3: 3 Y 2011 Y
# 4: 4 Y 2012 NA
# 5: 5 N 2011 NA
# 6: 6 N 2013 NA
# 7: 7 N 2014 NA
# 8: 8 N 2015 NA
# 9: 9 N 2011 NA
# 10: 10 N 2010 NA
或者你可以在一个大的条件下完成:
dt[(year==2013 & in.df2=='Y') | (year>=2012 & codes==4) |
((year==2011 | year==2012) & in.df2=='Y'), flag:='Y']
你可以把第一个和第三个条件放在一起:
dt[((year==2011 | year==2012 | year==2013) & in.df2=='Y') | (year>=2012 & codes==4), flag:='Y']
# and shorten it:
dt[((year %in% 2011:2013) & in.df2=='Y') | (year>=2012 & codes==4), flag:='Y']
答案 2 :(得分:0)
总结我在这个帖子中得到的信息,我第一个问题的答案是'不要试图在ifelse()
内设置值,使用ifelse()
返回一个值并设置它那样。
我在声明的else
部分覆盖以前的语句时遇到的第二个问题,答案非常简单:只返回当前值。以下是
df$flag <- ifelse((df$year==2011 | df$year==2012) & df$code==df2$yes_code &
df$year==df2$year, 'Y', 'N')
变成这个
df$flag <- ifelse((df$year==2011 | df$year==2012) & df$code==df2$yes_code &
df$year==df2$year, 'Y', df$flag)
感谢所有帮助过的人,这是一个非常难以表达的问题。