使用tidyr收集多个日期/值列

4

我有一个数据集,其中包含多列日期和相应的值(重复测量)。是否有一种方法可以使用 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.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

任何在tidyrreshape中完成此操作的帮助都将不胜感激。

我看到了几个非常相似的问题/答案(其中一个可能是完全重复的)-请参见这里这里 - aosmith
5个回答

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

我使用tidyr分别收集两种类型的列,得出了相同的结论 - 我将答案发布供参考。 - Daniel Stekhoven

1
我在学习如何使用gather混合日期和值时偶然发现了这个问题。
现有的答案丢失了关于日期-值对来自哪个实例的信息,即日期1和值1的第1个实例等。这可能不重要,但这里有一个保留实例的整洁宇宙选项。
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

1
我曾经遇到过同样的问题,需要处理一份数据集,涉及编程方面的内容。我在工作中向众人征求答案,最终我们想到了一个使用单一的 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)

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值 - gather函数还有一个na.rm参数),我使用基本的/dplyr函数将数据框连接起来:

df.long <- data.frame(select(df.value, id, age, value), select(df.date, date))

我相信有更优雅的方法来完成这两个部分,但这样做已经解决了问题。


0

这段代码进行了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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接