没有'ifelse'的矢量化'if'语句

时间:2017-05-16 14:43:26

标签: r if-statement vectorization

我已经找到了在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$codedf$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语句吗?

3 个答案:

答案 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)

感谢所有帮助过的人,这是一个非常难以表达的问题。