有人可以解释为什么下面的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中工作。)
答案 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
代替if
或ifelse
(或新的 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'))))
在这种情况下清除重复级别,这会引发警告。