使用tidyverse gather()在数据帧中使用单个键输出多个值向量

使用tidyverse gather()在数据帧中使用单个键输出多个值向量,r,tidyverse,R,Tidyverse,尽管有R的惯例,数据收集和输入对我来说最容易在垂直列中完成。因此,我有一个关于使用tidyverse库中的gather()函数高效地转换为水平行的问题。我发现自己反复使用gather(),这似乎效率低下。有没有更有效的方法?一个现有的向量可以作为关键吗?以下是一个例子: 假设我们有以下关于雏鸟的健康指标 bird day_1_mass day_2_mass day_1_heart_rate day_3_heart_rate 1 1 5 6

尽管有R的惯例,数据收集和输入对我来说最容易在垂直列中完成。因此,我有一个关于使用tidyverse库中的gather()函数高效地转换为水平行的问题。我发现自己反复使用gather(),这似乎效率低下。有没有更有效的方法?一个现有的向量可以作为关键吗?以下是一个例子:

假设我们有以下关于雏鸟的健康指标

    bird day_1_mass day_2_mass day_1_heart_rate day_3_heart_rate
1    1          5          6               60               55
2    2          6          8               62               57
3    3          3          3               45               45
使用聚集函数,我可以将海量数据重新组织成行

horizontal.data <- gather(vertical.data,
                      key = age, 
                      value = mass, 
                      day_1_mass:day_2_mass, 
                      factor_key=TRUE)
并再次使用相同的函数类似地重新组织心率数据

horizontal.data.2 <- gather(horizontal.data, 
                            key = age2, 
                            value = heart_rate, 
                            day_1_heart_rate:day_3_heart_rate, 
                            factor_key=TRUE)

因此,它采取了两个步骤,但都奏效了。问题是1)有没有办法一步到位?2)也可以用一个键(“年龄”向量)来完成,我可以简单地将其替换为数字数据吗?

如果我答对了问题,你可以先将所有数据收集在一起,然后“扩展”质量和心率:

library(forcats)
library(dplyr)

mass_levs       <- names(vertical.data)[grep("mass", names(vertical.data))]
hearth_levs     <- names(vertical.data)[grep("heart", names(vertical.data))]
horizontal.data <- vertical.data %>% 
                     gather(variable, value, -bird,  factor_key = TRUE) %>% 
                     mutate(day = stringr::str_sub(variable, 5,5)) %>% 
                     mutate(variable = fct_collapse(variable,  
                                                    "mass" = mass_levs, 
                                                    "hearth_rate" = hearth_levs)) %>% 
                     spread(variable, value)
我们可以通过一次通过一个管道来了解它的工作原理。 首先,我们以长格式收集所有内容:

horizontal.data <- vertical.data %>% 
                     gather(variable, value, -bird,  factor_key = TRUE)

  bird         variable value
1     1       day_1_mass     5
2     2       day_1_mass     6
3     3       day_1_mass     3
4     1       day_2_mass     6
5     2       day_2_mass     8
6     3       day_2_mass     3
7     1 day_1_heart_rate    60
8     2 day_1_heart_rate    62
9     3 day_1_heart_rate    45
10    1 day_3_heart_rate    55
11    2 day_3_heart_rate    57
12    3 day_3_heart_rate    45
在这里,str_sub获取位置5中的子字符串,即天(注意,如果在完整数据集中有多个数字天,则必须稍微调整此值,可能是通过在
\uu
上拆分):

现在,为了完成这项工作,我们必须“展开”表格,使其有一个
质量
和一个
心率

这里我们有一个问题,因为目前在
变量
列中有两个级别,每个级别对应于质量和炉缸率。因此,在
variable
上应用
spread
将再次给出四列

为了避免这种情况,我们需要将
变量中的四个级别聚合为两个级别。我们可以使用
forcats::fc_collapse
,通过提供新级别名称和“旧”级别名称之间的关联来实现这一点。在管道外部,对应于:

horizontal.data$variable <- fct_collapse(horizontal.data$variable, 
                                mass = c("day_1_mass", "day_2_mass",
                                heart = c("day_1_hearth_rate", "day_3_heart_rate")
,之后我们有:

  bird    variable value day
1     1        mass     5   1
2     2        mass     6   1
3     3        mass     3   1
4     1        mass     6   2
5     2        mass     8   2
6     3        mass     3   2
7     1 hearth_rate    60   1
8     2 hearth_rate    62   1
9     3 hearth_rate    45   1
10    1 hearth_rate    55   3
11    2 hearth_rate    57   3
12    3 hearth_rate    45   3
,因此我们现在可以根据
变量
再次“展开”表格,使用:

%>% spread(variable, value)

  bird day mass hearth_rate
1    1   1    5          60
2    1   2    6          NA
3    1   3   NA          55
4    2   1    6          62
5    2   2    8          NA
6    2   3   NA          57
7    3   1    3          45
8    3   2    3          NA
9    3   3   NA          45

HTH

如果你坚持一个命令,我可以给你一个

设置data.frame

c1<-c(1,2,3)
c2<-c(5,6,3)
c3<-c(6,8,3)
c4<-c(60,62,45)
c5<-c(55,57,45)
dt<-as.data.table(cbind(c1,c2,c3,c4,c5))
colnames(dt)<-c("bird","day_1_mass","day_2_mass","day_1_heart_rate","day_3_heart_rate")
最终结果是

     bird        age     mass             age2 heart_rate
 1:    1 day_1_mass         5 day_1_heart_rate         60
 2:    1 day_1_mass         5 day_3_heart_rate         55
 3:    1 day_2_mass         6 day_1_heart_rate         60
 4:    1 day_2_mass         6 day_3_heart_rate         55
 5:    2 day_1_mass         6 day_1_heart_rate         62
 6:    2 day_1_mass         6 day_3_heart_rate         57
 7:    2 day_2_mass         8 day_1_heart_rate         62
 8:    2 day_2_mass         8 day_3_heart_rate         57
 9:    3 day_1_mass         3 day_1_heart_rate         45
10:    3 day_1_mass         3 day_3_heart_rate         45
11:    3 day_2_mass         3 day_1_heart_rate         45
12:    3 day_2_mass         3 day_3_heart_rate         45

虽然已经回答了,但我有一个不同的解决方案,您可以保存一个要运行的聚集参数列表,然后为列表中的每一组参数运行gather_u2;()命令

# Create a list of gather parameters
# Format is key, value, columns_to_gather
gather.list <- list(c("age", "mass", "day_1_mass", "day_2_mass"),
                    c("age2", "heart_rate", "day_1_heart_rate", "day_3_heart_rate"))

# Run gather command for each list item
for(i in gather.list){
  df <- gather_(df, key_col = i[1], value_col = i[2], gather_cols = c(i[3:length(i)]), factor_key = TRUE)
}
#创建聚集参数列表
#格式为键、值、列到集合

为什么不使用管道函数来组合这两个步骤呢。我认为没有一种方法可以在一个
gather()
function>
gather(vertical.data,key=age,value=mass,day\u 1\u mass:day\u 2\u mass,factor\u key=TRUE)中包含您想要的操作%>%gather(key=age2,value=心率,day\u 1\u心率:day\u心率,factor\u key=TRUE)
可能是Yeah的复制品,它工作得很漂亮,是一个优雅的脚本。如果你能稍加注释,特别是你在使用stringr(?)和fct_-collapse的mutate中所做的事情,这将有助于更好地“教人钓鱼”。不,应该清楚得多。谢谢你的建议很好的解释!
mass_levs       <- names(vertical.data)[grep("mass", names(vertical.data))]
hearth_levs     <- names(vertical.data)[grep("heart", names(vertical.data))]
%>% mutate(variable = fct_collapse(variable,  
                              "mass" = mass_levs, 
                              "hearth_rate" = hearth_levs))
  bird    variable value day
1     1        mass     5   1
2     2        mass     6   1
3     3        mass     3   1
4     1        mass     6   2
5     2        mass     8   2
6     3        mass     3   2
7     1 hearth_rate    60   1
8     2 hearth_rate    62   1
9     3 hearth_rate    45   1
10    1 hearth_rate    55   3
11    2 hearth_rate    57   3
12    3 hearth_rate    45   3
%>% spread(variable, value)

  bird day mass hearth_rate
1    1   1    5          60
2    1   2    6          NA
3    1   3   NA          55
4    2   1    6          62
5    2   2    8          NA
6    2   3   NA          57
7    3   1    3          45
8    3   2    3          NA
9    3   3   NA          45
c1<-c(1,2,3)
c2<-c(5,6,3)
c3<-c(6,8,3)
c4<-c(60,62,45)
c5<-c(55,57,45)
dt<-as.data.table(cbind(c1,c2,c3,c4,c5))
colnames(dt)<-c("bird","day_1_mass","day_2_mass","day_1_heart_rate","day_3_heart_rate")
merge(melt(dt[,c("bird","day_1_mass","day_2_mass")],id.vars = c("bird"),variable.name = "age",value.name="mass"),melt(dt[,c("bird","day_1_heart_rate","day_3_heart_rate")],id.vars = c("bird"),variable.name = "age2",value.name="heart_rate"),by = "bird")
     bird        age     mass             age2 heart_rate
 1:    1 day_1_mass         5 day_1_heart_rate         60
 2:    1 day_1_mass         5 day_3_heart_rate         55
 3:    1 day_2_mass         6 day_1_heart_rate         60
 4:    1 day_2_mass         6 day_3_heart_rate         55
 5:    2 day_1_mass         6 day_1_heart_rate         62
 6:    2 day_1_mass         6 day_3_heart_rate         57
 7:    2 day_2_mass         8 day_1_heart_rate         62
 8:    2 day_2_mass         8 day_3_heart_rate         57
 9:    3 day_1_mass         3 day_1_heart_rate         45
10:    3 day_1_mass         3 day_3_heart_rate         45
11:    3 day_2_mass         3 day_1_heart_rate         45
12:    3 day_2_mass         3 day_3_heart_rate         45
# Create a list of gather parameters
# Format is key, value, columns_to_gather
gather.list <- list(c("age", "mass", "day_1_mass", "day_2_mass"),
                    c("age2", "heart_rate", "day_1_heart_rate", "day_3_heart_rate"))

# Run gather command for each list item
for(i in gather.list){
  df <- gather_(df, key_col = i[1], value_col = i[2], gather_cols = c(i[3:length(i)]), factor_key = TRUE)
}