使用dplyr在R中自动创建变量的最佳方法

时间:2015-04-21 20:34:09

标签: r dplyr

df <- as.data.frame(cbind(c(1:10), c(15, 70, 29, 64, 57, 29, 10, 80,81, 71)))

   V1 V2
1   1 15
2   2 70
3   3 29
4   4 64
5   5 57
6   6 29
7   7 10
8   8 80
9   9 81
10 10 71

cuts <- c(5, 10, 90, 95)

我想为所有(在本例中为四个)切割值x(例如P5P10P90和{{1}创建逻辑变量})表示是否P95。 “手动”添加变量的简单方法不会扩展到少数几个:

v2 <= x

显然,为了使数据保持“整洁”格式,应该应用最终df %<>% mutate( P5 = V2 <= 5) %>% mutate(P10 = V2 <= 10) %>% mutate(P90 = V2 <= 90) %>% mutate(P95 = V2 <= 95) V1 V2 P5 P10 P90 P95 1 1 15 FALSE FALSE TRUE TRUE 2 2 70 FALSE FALSE TRUE TRUE 3 3 29 FALSE FALSE TRUE TRUE 4 4 64 FALSE FALSE TRUE TRUE 5 5 57 FALSE FALSE TRUE TRUE 6 6 29 FALSE FALSE TRUE TRUE 7 7 10 FALSE TRUE TRUE TRUE 8 8 80 FALSE FALSE TRUE TRUE 9 9 81 FALSE FALSE TRUE TRUE 10 10 71 FALSE FALSE TRUE TRUE

我尝试的替代方法是

gather(year, islegal, c(3;6))

显然,我会删除最后的do.call(rbind, lapply(cuts, function(x) { df %>% mutate(year = x, islegal = V2 <= x) })) %>% spread(year, islegal) V1 V2 5 10 90 95 1 1 15 FALSE FALSE TRUE TRUE 2 2 70 FALSE FALSE TRUE TRUE 3 3 29 FALSE FALSE TRUE TRUE 4 4 64 FALSE FALSE TRUE TRUE 5 5 57 FALSE FALSE TRUE TRUE 6 6 29 FALSE FALSE TRUE TRUE 7 7 10 FALSE TRUE TRUE TRUE 8 8 80 FALSE FALSE TRUE TRUE 9 9 81 FALSE FALSE TRUE TRUE 10 10 71 FALSE FALSE TRUE TRUE 以使数据保持“整洁”格式。

问题:是否有更好或更通用的方法使用spread()而不是第二种方法来自动创建变量(类似分位数的截止值,如此类,或虚拟或类似),不需要像第一种方法那样明确地输入{dplyr}的内容吗?

3 个答案:

答案 0 :(得分:6)

当然,你不需要dplyr这么简单。

names(cuts) <- paste0("p", cuts)
data.frame(df, lapply(cuts, function(x) df$V2 <= x))

   V1 V2    p5   p10  p90  p95
1   1 15 FALSE FALSE TRUE TRUE
2   2 70 FALSE FALSE TRUE TRUE
3   3 29 FALSE FALSE TRUE TRUE
4   4 64 FALSE FALSE TRUE TRUE
5   5 57 FALSE FALSE TRUE TRUE
6   6 29 FALSE FALSE TRUE TRUE
7   7 10 FALSE  TRUE TRUE TRUE
8   8 80 FALSE FALSE TRUE TRUE
9   9 81 FALSE FALSE TRUE TRUE
10 10 71 FALSE FALSE TRUE TRUE

答案 1 :(得分:4)

如果你想以编程方式&#34;与dplyr合作,你应该看看&#34;标准评估&#34;通常版本的功能的替代品。请参阅非标准评估小插图(vignette("nse", "dplyr"))。

除了mutate函数之外,还有一个mutate_函数允许您指定转换列表。在您的情况下,您可以使用类似的内容构建列表

cuts <- c(5,10,90,95)
mymutate <- setNames(lapply(cuts , function(x) 
     lazyeval::interp(~V2<=x, x=x)), paste0("P", cuts ))

然后您可以使用

执行转换
df %>% mutate_(.dots=mymutate )

#    V1 V2    P5   P10  P90  P95
# 1   1 15 FALSE FALSE TRUE TRUE
# 2   2 70 FALSE FALSE TRUE TRUE
# 3   3 29 FALSE FALSE TRUE TRUE
# 4   4 64 FALSE FALSE TRUE TRUE
# 5   5 57 FALSE FALSE TRUE TRUE
# 6   6 29 FALSE FALSE TRUE TRUE
# 7   7 10 FALSE  TRUE TRUE TRUE
# 8   8 80 FALSE FALSE TRUE TRUE
# 9   9 81 FALSE FALSE TRUE TRUE
# 10 10 71 FALSE FALSE TRUE TRUE

答案 2 :(得分:0)

如果您计划最终将数据转换为整洁的数据,则可以从一个开始:

library(dplyr)
df <- as.data.frame(cbind(c(1:10), c(15, 70, 29, 64, 57, 29, 10, 80,81, 71)))
cuts <- data_frame(P=c(5, 10, 90, 95))

p_df <- df %>% tidyr::crossing(cuts) %>%
  mutate(flag=V2<=P)
p_df

#   V1 V2  P  flag
#1   1 15  5 FALSE
#2   1 15 10 FALSE
#3   1 15 90  TRUE
#4   1 15 95  TRUE
#5   2 70  5 FALSE
#...

如果原始格式确实是您想要的,tidyr::spread结果

p_df %>% 
  tidyr::spread(P, flag, sep="")
#   V1 V2    P5   P10  P90  P95
#1   1 15 FALSE FALSE TRUE TRUE
#2   2 70 FALSE FALSE TRUE TRUE
#3   3 29 FALSE FALSE TRUE TRUE
#4   4 64 FALSE FALSE TRUE TRUE
#5   5 57 FALSE FALSE TRUE TRUE
#6   6 29 FALSE FALSE TRUE TRUE
#7   7 10 FALSE  TRUE TRUE TRUE
#8   8 80 FALSE FALSE TRUE TRUE
#9   9 81 FALSE FALSE TRUE TRUE
#10 10 71 FALSE FALSE TRUE TRUE