使用tidyverse gather()在数据帧中使用单个键输出多个值向量
尽管有R的惯例,数据收集和输入对我来说最容易在垂直列中完成。因此,我有一个关于使用tidyverse库中的gather()函数高效地转换为水平行的问题。我发现自己反复使用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
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)
}