使用 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^1381 的机会)看起来像这样:

   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

如能在 tidyrreshape 中提供帮助,我们将不胜感激。

应该有一些有效的方法,但这是一种方法。

分别处理日期和值,

#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

对于我正在处理的数据集,我有完全相同的问题和数据格式。在工作中众包答案。我们中的一些人想出了一个单一的 tidyrdplyr 管道解决方案。使用与原始问题相同的模拟 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.namesvarying 参数设置为 reshapev.names 定义了新的列名,varying 是一个列表,其两个组件分别包含 datevalue 列的逻辑选择向量。

最后一行代码进行排序,如果行顺序无关紧要,则可以省略。

没有使用包。

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