dplyr mutate函数调用返回错误的值

时间:2016-03-30 05:27:04

标签: r dplyr

有人可以解释为什么下面的dplyr mutate调用,我在其中应用一个函数,以一列作为参数来设置新列的值,不起作用吗?它似乎没有在正确的值上调用函数:新season列是根据mon列中的第一个值而不是其自己行中的值设置的。 / p>

# Function to return season (winter, summer, or transition) given numerical month
getSeason <- function(m) {
  if(m >= 11 || m <= 3) 
    return(as.factor("Winter"))
  if(m >= 5 && m <= 9) 
    return(as.factor("Summer"))
  return(as.factor("Trans"))
}

getSeason(5) # Works: returns "Summer"

mon <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
months <- as.data.frame(mon)

months %>% mutate(season=getSeason(mon))  # doesn't work: all seasons set as "Winter"

我正在使用R版本3.2.4和dplyr的最新开发版本。 (这也没有在最新版本的dplyr中工作。)

3 个答案:

答案 0 :(得分:5)

其他答案很好地解释了为什么你遇到这个问题。

我认为这是新功能case_when可以派上用场的情况(目前在开发版本中可用, dplyr_0.4.3.9001 )。

目前,您必须使用美元符号表示法在case_when内使用mutate

months %>% mutate(season = case_when(.$mon >= 11 | .$mon <= 3 ~ "Winter",
                                     .$mon >= 5 & .$mon <= 9 ~ "Summer",
                                     TRUE ~ "Trans"))

   mon season
1    1 Winter
2    2 Winter
3    3 Winter
4    4  Trans
5    5 Summer
6    6 Summer
7    7 Summer
8    8 Summer
9    9 Summer
10  10  Trans
11  11 Winter
12  12 Winter

您可以使用case_when代替ififelse(或新的 dplyr 函数if_else)来构建您的函数。对我来说,语法似乎与使用if更相似,而不是与ifelse嵌套。

getSeason <- function(m) {
    factor(
        case_when(
            m >= 11 | m <= 3 ~ "Winter",
            m >= 5 & m <= 9 ~ "Summer",
            TRUE ~ "Trans"
            ) 
        )
}

months %>% mutate(season=getSeason(mon))

   mon season
1    1 Winter
2    2 Winter
3    3 Winter
4    4  Trans
5    5 Summer
6    6 Summer
7    7 Summer
8    8 Summer
9    9 Summer
10  10  Trans
11  11 Winter
12  12 Winter

请注意,“其他所有”条件最后在case_when完成,您只需将TRUE放在公式的左侧,以使用最终值填充其他所有内容。

答案 1 :(得分:4)

您也可以使用Vectorize

# Function to return season (winter, summer, or transition) given numerical month
getSeason <- function(m) {
  if(m >= 11 || m <= 3) 
    return(as.factor("Winter"))
  if(m >= 5 && m <= 9) 
    return(as.factor("Summer"))
  return(as.factor("Trans"))
}


getSeason <- Vectorize(getSeason)

mon <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
months <- data.frame(mon = mon)

months %>% mutate(season=gs(mon)) 

答案 2 :(得分:2)

if没有被矢量化(奇怪),所以它只使用mon中的第一个值,即1,所以你得到了所有Winter

要避免这种情况,请使用{em> 矢量化的ifelse

months %>% mutate(season = factor(ifelse(mon >= 11 | mon <=3, 
                                         'Winter', ifelse(mon >= 5 & mon <= 9, 
                                                          'Summer', 'Trans'))))
#    mon season
# 1    1 Winter
# 2    2 Winter
# 3    3 Winter
# 4    4  Trans
# 5    5 Summer
# 6    6 Summer
# 7    7 Summer
# 8    8 Summer
# 9    9 Summer
# 10  10  Trans
# 11  11 Winter
# 12  12 Winter

如果你想添加足够的级别,嵌套ifelse变得讨厌,请改用cut,因为你真正将连续数字数据转换为因子数据,这是{的目的{1}}。

cut

注意months %>% mutate(season = droplevels(cut(months$mon, c(0, 3, 4, 9, 10, 12), c('Winter', 'Trans', 'Summer', 'Trans', 'Winter')))) 在这种情况下清除重复级别,这会引发警告。