我有一个数据集,其中包含多个具有日期和相应值的列(重复测量)。有没有办法将其转换为包含(其他和仅)两列的长数据集 - 一个用于日期,一个用于值 - 使用tidyr
?
以下代码生成示例数据框:
df <- data.frame(
id = 1:10,
age = sample(100, 10),
date1 = as.Date('2015-09-22') - sample(100, 10),
value1 = sample(100, 10),
date2 = as.Date('2015-09-22') - sample(100, 10),
value2 = sample(100, 10),
date3 = as.Date('2015-09-22') - sample(100, 10),
value3 = sample(100, 10))
输入表可能(1
中1.8x10^138
的概率)如下所示:
id age date1 value1 date2 value2 date3 value3
1 1 32 2015-08-01 37 2015-07-15 38 2015-09-09 81
2 2 33 2015-07-22 16 2015-06-26 1 2015-09-12 58
...
10 10 64 2015-07-23 78 2015-08-25 70 2015-08-05 90
我最终想要的是:
id age date value
1 1 32 2015-08-01 37
2 1 32 2015-07-15 38
3 1 32 2015-09-09 81
4 2 33 2015-07-22 16
5 2 33 2015-06-26 1
...
30 10 64 2015-08-05 90
非常感谢tidyr
或reshape
中提供的任何帮助。
答案 0 :(得分:3)
应该有一些有效的方法,但这是一种方式。
分别处理日期和值,
#for date
df.date<-df%>%select(id, age,date1,date2, date3)%>%melt(id.var=c("id", "age"), value.name="date")
#for val
df.val<-df%>%select(id, age,value1,value2, value3)%>%melt(id.var=c("id", "age"), value.name="value")
现在加入,
df2<-full_join(df.date, df.val, by=c("id", "age"))
df2%>%select(-variable.x, -variable.y)
id age date value
1 1 40 2015-07-19 28
2 1 40 2015-07-19 49
3 1 40 2015-07-19 24
4 2 33 2015-06-27 99
5 2 33 2015-06-27 18
6 2 33 2015-06-27 26
7 3 75 2015-07-07 63
8 3 75 2015-07-07 74
9 3 75 2015-07-07 72
答案 1 :(得分:1)
我偶然发现了这个尝试了解如何使用gather
混合使用日期和值。
现有答案会丢失有关日期 - 值对来自哪个实例的信息,即date1&amp;的实例1。 value1等。这可能并不重要,但这里有一个保持实例的tidyverse选项。
library(stringr) # not necessary but nice
library(tidyr)
library(dplyr)
df %>%
gather(key, val, -id, -age) %>%
mutate(
measure = str_sub(key,1,-2),
instance = str_sub(key, -1)
) %>%
select(-key) %>%
spread(measure, val) %>%
mutate(date = as.Date(date, origin="1970-01-01")) # restore date class
答案 2 :(得分:1)
我对我正在处理的数据集有完全相同的问题和数据格式。在工作中众包答案。我们中的一些人想出了一个tidyr
和dplyr
管道解决方案。使用与原始问题相同的模拟 df 。
df %>%
gather(key = date_position, value = date, starts_with("date")) %>%
gather(key = value_position, value = value, starts_with("value")) %>%
mutate(date_position = gsub('[^0-9]', "", date_position),
value_position = gsub('[^0-9]', "", value_position)) %>%
filter(date_position == value_position) %>%
select(-ends_with("position")) %>%
arrange(id)
答案 3 :(得分:0)
相同的策略,但使用tidyr
代替如下:
df.value <- df %>%
gather(key="foo", value="value", starts_with("value"))
df.date <- df %>%
gather(key="bar", value="date", starts_with("date"))
控制结果维度后(注意NA
值 - na.rm
函数还有一个gather
参数)我使用base / dplyr函数加入了data.frames:< / p>
df.long <- data.frame(select(df.value, id, age, value), select(df.date, date))
我确信这两个部分都有更加优雅的方式,但它确实可以解决问题。
答案 4 :(得分:0)
这会执行reshape
,然后对行进行排序。
前两行只是为v.names
设置varying
和reshape
参数。 v.names
定义了新的列名称,varying
是一个列表,其中两个组件分别包含date
和value
列的逻辑选择向量。
最后一行代码执行排序,如果行顺序无关紧要,可以省略。
没有使用任何包裹。
v.names <- c("date", "value")
varying <- lapply(v.names, startsWith, x = names(df))
r <- reshape(df, dir = "long", varying = varying, v.names = v.names)
r[order(r$id, r$time), ]
给出以下内容,其中id和time列将输出行与输入相关联:
id age time date value
1.1 1 12 1 2015-08-14 3
1.2 1 12 2 2015-07-11 24
1.3 1 12 3 2015-07-04 4
2.1 2 92 1 2015-08-03 17
2.2 2 92 2 2015-07-19 52
2.3 2 92 3 2015-07-01 93
3.1 3 28 1 2015-08-24 86
3.2 3 28 2 2015-08-12 80
3.3 3 28 3 2015-09-01 56
4.1 4 45 1 2015-09-13 78
4.2 4 45 2 2015-07-07 92
4.3 4 45 3 2015-08-10 81
5.1 5 25 1 2015-08-27 95
5.2 5 25 2 2015-09-08 68
5.3 5 25 3 2015-06-27 82
6.1 6 1 1 2015-08-21 16
6.2 6 1 2 2015-06-15 35
6.3 6 1 3 2015-07-24 30
7.1 7 7 1 2015-07-19 59
7.2 7 7 2 2015-07-08 33
7.3 7 7 3 2015-08-11 49
8.1 8 71 1 2015-07-28 19
8.2 8 71 2 2015-06-29 74
8.3 8 71 3 2015-08-05 25
9.1 9 59 1 2015-07-05 64
9.2 9 59 2 2015-09-04 30
9.3 9 59 3 2015-07-30 74
10.1 10 96 1 2015-09-12 69
10.2 10 96 2 2015-07-23 72
10.3 10 96 3 2015-08-19 23