如何基于观察组的另一个变量为观察组创建一个新变量

时间:2019-08-27 01:50:00

标签: r dplyr

我正在尝试添加一个新变量,该变量基于对我的数据集中组中某个因素水平的观察。我一直在尝试利用各种dplyr函数(filterselectmutategroup_by),但无法弄清楚如何使它们协同工作并完成工作我的目标。

这是我的数据示例:

  rep   rate       n  mort   avg
   <fct> <fct>  <int> <dbl> <dbl>
 1 1     0.747     10     7   0.7
 2 1     0.373     10     7   0.7
 3 1     0.187     10     6   0.6
 4 1     0.0933    10     0   0  
 5 1     0.00      10     1   0.1
 6 2     0.747     10     7   0.7
 7 2     0.373     10     5   0.5
 8 2     0.187     10     1   0.1
 9 2     0.0933    10     4   0.4
10 2     0.00      10     0   0  

我希望完成的工作是创建一个名为cont的新变量,该变量是在avg时从rate == "0.00"变量派生的。对于同一rep组中的每个观察,此变量将相同。最终产品将是与以下表格相似的表格:

  rep   rate       n  mort   avg  cont
   <fct> <fct>  <int> <dbl> <dbl> <dbl>
 1 1     0.747     10     7   0.7  0.1
 2 1     0.373     10     7   0.7  0.1
 3 1     0.187     10     6   0.6  0.1
 4 1     0.0933    10     0   0    0.1
 5 1     0.00      10     1   0.1  0.1
 6 2     0.747     10     7   0.7  0
 7 2     0.373     10     5   0.5  0
 8 2     0.187     10     1   0.1  0
 9 2     0.0933    10     4   0.4  0
10 2     0.00      10     0   0    0

我尝试了以下代码:data %>% group_by(rep) %>% filter(rate =="0.00") %>% select(avg)将导致一个数据框,其中包含我想添加的数据作为新变量:

  rep     avg
  <fct> <dbl>
1 1       0.1
2 2       0  
3 3       0.1
4 4       0.3
5 5       0  
6 6       0  
7 7       0  
8 8       0  

我现在的问题是我不知道如何为rep组内的每个观察值创建新变量。我不确定在这种情况下如何正确使用mutate。预先感谢您的帮助!

2 个答案:

答案 0 :(得分:4)

假设每个组中只有rate == "0.00"出现一次,我们可以做到

library(dplyr)
df %>%
   group_by(rep) %>%
   mutate(cont = avg[rate == "0.00"])

#   rep   rate       n  mort   avg  cont
#  <fct> <fct>  <int> <dbl> <dbl> <dbl>
# 1 1     0.747     10     7   0.7   0.1
# 2 1     0.373     10     7   0.7   0.1
# 3 1     0.187     10     6   0.6   0.1
# 4 1     0.0933    10     0   0     0.1
# 5 1     0.00      10     1   0.1   0.1
# 6 2     0.747     10     7   0.7   0  
# 7 2     0.373     10     5   0.5   0  
# 8 2     0.187     10     1   0.1   0  
# 9 2     0.0933    10     4   0.4   0  
#10 2     0.00      10     0   0     0  

如果有多个事件,我们可以使用which.max选择第一个事件

df %>% group_by(rep) %>% mutate(cont = avg[which.max(rate == "0.00")])

使用data.table,我们可以做到

library(data.table)
setDT(df)[, cont := avg[rate == "0.00"], by = rep]

数据

df <- structure(list(rep = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 
2L, 2L, 2L), .Label = c("1", "2"), class = "factor"), rate = structure(c(5L, 
4L, 3L, 2L, 1L, 5L, 4L, 3L, 2L, 1L), .Label = c("0.00", "0.0933", 
"0.187", "0.373", "0.747"), class = "factor"), n = c(10L, 10L, 
10L, 10L, 10L, 10L, 10L, 10L, 10L, 10L), mort = c(7, 7, 6, 0, 
1, 7, 5, 1, 4, 0), avg = c(0.7, 0.7, 0.6, 0, 0.1, 0.7, 0.5, 0.1, 
0.4, 0)), row.names = c("1", "2", "3", "4", "5", "6", "7", "8", 
"9", "10"), class = "data.frame")

答案 1 :(得分:1)

我们可以使用match

library(dplyr)
df  %>%
   group_by(rep) %>% 
   mutate(cont = avg[match("0.00", rate)])
# A tibble: 10 x 6
# Groups:   rep [2]
#   rep   rate       n  mort   avg  cont
#   <fct> <fct>  <int> <dbl> <dbl> <dbl>
# 1 1     0.747     10     7   0.7   0.1
# 2 1     0.373     10     7   0.7   0.1
# 3 1     0.187     10     6   0.6   0.1
# 4 1     0.0933    10     0   0     0.1
# 5 1     0.00      10     1   0.1   0.1
# 6 2     0.747     10     7   0.7   0  
# 7 2     0.373     10     5   0.5   0  
# 8 2     0.187     10     1   0.1   0  
# 9 2     0.0933    10     4   0.4   0  
#10 2     0.00      10     0   0     0  

或与data.table

library(data.table)
setDT(df)[, cont := avg[match("0.00", rate)], rep]

或按照@thelatemail建议使用联接

setDT(df)[df[rate=="0.00"], on= .(rep), cont := i.avg]

注意;即使存在重复的值,这两种方法也都可以使用,因为match仅返回第一个匹配项的索引。

数据

df <- structure(list(rep = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 
2L, 2L, 2L), .Label = c("1", "2"), class = "factor"), rate = structure(c(5L, 
4L, 3L, 2L, 1L, 5L, 4L, 3L, 2L, 1L), .Label = c("0.00", "0.0933", 
"0.187", "0.373", "0.747"), class = "factor"), n = c(10L, 10L, 
10L, 10L, 10L, 10L, 10L, 10L, 10L, 10L), mort = c(7, 7, 6, 0, 
1, 7, 5, 1, 4, 0), avg = c(0.7, 0.7, 0.6, 0, 0.1, 0.7, 0.5, 0.1, 
0.4, 0)), row.names = c("1", "2", "3", "4", "5", "6", "7", "8", 
"9", "10"), class = "data.frame")