R - 功能中的动态条件

时间:2015-12-15 14:30:46

标签: r

我写了一个函数来计算在某些条件下两年之间某些值的差异。因子水平必须完全匹配才能减去这些值。

虚拟数据:

df <- data.frame(year=rep(2001:2003,each=4),
                 country=rep(c("A","B"),6),
                 categorie=rep(letters[3:6],3),
                 animal=rep(LETTERS[7:10],3),
                 value=sample(1:10,12,replace=T))

df
year country categorie animal value
1  2001       A         c      G     9
2  2001       B         d      H     2
3  2001       A         e      I     8
4  2001       B         f      J     7
5  2002       A         c      G     4
6  2002       B         d      H     3
7  2002       A         e      I     4
8  2002       B         f      J     4
9  2003       A         c      G    10
10 2003       B         d      H     1
11 2003       A         e      I     4
12 2003       B         f      J    10

第5行中的值应该从第1行中的值中减去,因为它是后一年并具有相同的属性(categoriesie = A,categorie = c,animal = G)。

以下功能正常。

calc.change <- function(df, cols){
  for(i in cols){
    p <- vector(mode="numeric", length = nrow(df))
    for(k in seq_len(nrow(df))){
      #first year is NA because no difference can be calculated
      if(df$year[k]==min(df$year[df$country==df$country[k] & 
         df$categorie==df$categorie[k] & df$animal==df$animal[k]])){
        p[k] <- NA
      } else {
        p[k] <- df[[i]][k]-df[[i]][df$year==df$year[k]-1 & df$categorie==df$categorie[k]
                                 & df$animal==df$animal[k] & df$country==df$country[k]]
      }
    }
    df <- cbind(df, p)
    names(df)[names(df)=="p"] <- paste0(i,".change")
  }
  return(df)
}

foo <- calc.change(df, "value")


foo
year country categorie animal value value.change
1  2001       A         c      G     4           NA
2  2001       B         d      H     4           NA
3  2001       A         e      I     9           NA
4  2001       B         f      J     1           NA
5  2002       A         c      G     2           -2
6  2002       B         d      H     3           -1
7  2002       A         e      I     2           -7
8  2002       B         f      J     5            4
9  2003       A         c      G     4            2
10 2003       B         d      H    10            7
11 2003       A         e      I    10            8
12 2003       B         f      J     5            0

但是,如果缺少country categorieanimal列中的一列,则该功能将不再起作用。

foobar <- aggregate(value ~ year+country, df, mean)

head(foobar)
    year country value
1 2001       A   6.5
2 2002       A   2.0
3 2003       A   7.0
4 2001       B   2.5
5 2002       B   4.0
6 2003       B   7.5

calc.change(foobar, value) #gives an error

很明显,因为几个if语句和&运算符都需要它们。 是否有可能不对列名进行硬编码,而只是通过exsting的名称? 我想尽可能灵活。

非常感谢帮助

1 个答案:

答案 0 :(得分:-1)

您可以在R中使用更高阶函数。也就是说,您可以将函数传递给函数

test <- function(df,k)
   df$year[k]==min(df$year[df$country==df$country[k] & 
           df$categorie==df$categorie[k] & df$animal==df$animal[k]])



calc.change <- function(df, cols,test){
  for(i in cols){
    p <- vector(mode="numeric", length = nrow(df))
    for(k in seq_len(nrow(df))){
      #first year is NA because no difference can be calculated
      if(test(df,k){
        p[k] <- NA
      } else {
        p[k] <- df[[i]][k]-df[[i]][df$year==df$year[k]-1 & df$categorie==df$categorie[k]
                                 & df$animal==df$animal[k] & df$country==df$country[k]]
      }
    }
    df <- cbind(df, p)
    names(df)[names(df)=="p"] <- paste0(i,".change")
  }
  return(df)
}

calc.change(df, "value",test)

现在,你可以用任何触发数据帧和整数的函数替换test并返回一个布尔值。