使用 tidyr 收集多个 date/value 列
Gather multiple date/value columns using tidyr
我有一个数据集包含(除其他外)具有日期和相应值(重复测量)的多列。有没有一种方法可以将其转换为仅包含(其他和)两列的长数据集 - 一列用于 dates,一列用于 values -使用 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))
输入 table 可能(在 1.8x10^138
中 1
的机会)看起来像这样:
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
中提供帮助,我们将不胜感激。
应该有一些有效的方法,但这是一种方法。
分别处理日期和值,
#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
相同的策略,但使用 tidyr
如下所示:
df.value <- df %>%
gather(key="foo", value="value", starts_with("value"))
df.date <- df %>%
gather(key="bar", value="date", starts_with("date"))
控制结果尺寸后(小心 NA
值 - gather
函数还有一个 na.rm
参数)我加入 data.frames 使用 base/dplyr 函数:
df.long <- data.frame(select(df.value, id, age, value), select(df.date, date))
我确信这两个部分都有更优雅的方式,但它确实成功了。
我在尝试了解如何将 gather
与日期和值混合使用时偶然发现了这一点。
现有答案丢失了有关日期值对来自哪个实例的信息,即 date1 和 value1 的实例 1 等。这可能并不重要,但这里有一个保留实例的 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
对于我正在处理的数据集,我有完全相同的问题和数据格式。在工作中众包答案。我们中的一些人想出了一个单一的 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)
这会执行 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
我有一个数据集包含(除其他外)具有日期和相应值(重复测量)的多列。有没有一种方法可以将其转换为仅包含(其他和)两列的长数据集 - 一列用于 dates,一列用于 values -使用 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))
输入 table 可能(在 1.8x10^138
中 1
的机会)看起来像这样:
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
中提供帮助,我们将不胜感激。
应该有一些有效的方法,但这是一种方法。
分别处理日期和值,
#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
相同的策略,但使用 tidyr
如下所示:
df.value <- df %>%
gather(key="foo", value="value", starts_with("value"))
df.date <- df %>%
gather(key="bar", value="date", starts_with("date"))
控制结果尺寸后(小心 NA
值 - gather
函数还有一个 na.rm
参数)我加入 data.frames 使用 base/dplyr 函数:
df.long <- data.frame(select(df.value, id, age, value), select(df.date, date))
我确信这两个部分都有更优雅的方式,但它确实成功了。
我在尝试了解如何将 gather
与日期和值混合使用时偶然发现了这一点。
现有答案丢失了有关日期值对来自哪个实例的信息,即 date1 和 value1 的实例 1 等。这可能并不重要,但这里有一个保留实例的 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
对于我正在处理的数据集,我有完全相同的问题和数据格式。在工作中众包答案。我们中的一些人想出了一个单一的 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)
这会执行 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