【问题标题】:How to consolidate a data frame in which the date variable is repeated in a column next to each variable如何合并其中日期变量在每个变量旁边的列中重复的数据框
【发布时间】:2015-03-30 11:42:54
【问题描述】:

我继承了一个 csv 文件,其中的数据格式如下:

date        v1  date.1      v2  date.2      v3
2015-01-01  1   2015-01-01  4   2015-01-02  5
2015-01-02  2   2015-01-03  5   2015-01-03  2
2015-01-03  3   2015-01-04  3   2015-01-04  6
2015-01-04  4   2015-01-05  2   2015-01-05  2
2015-01-05  5   2015-01-06  6   2015-01-06  4
2015-01-06  6   2015-01-07  3   2015-01-07  5
2015-01-07  7   2015-01-08  1   2015-01-09  1

实际文件有 70 多个日期变量对

注意:第 1、3 和 5 列中的日期不相同

我想清理 R 中的这些数据,以便有一列包含日期,然后在接下来的三列中对应于这些日期的 v1、v2 和 v3 的值:

date        v1  v2  v3
2015-01-01  1   4   NA
2015-01-02  2   NA  5
2015-01-03  3   5   2
2015-01-04  4   3   6
2015-01-05  5   2   2
2015-01-06  6   6   4
2015-01-07  7   3   5
2015-01-08  NA  1   NA
2015-01-09  NA  NA  1

如果所有日期 (date, date.1, ... date.n) 列都相同,我可以简单地删除它们。但是,因为它们不是,所以删除它们会错误地将某些变量与错误的日期相关联,因为它们的位置(例如,var3 在 2015-01-01 的值似乎是 5,即使 var3 没有值日期)。

我考虑了堆栈(随后是消除非唯一值),但考虑到原始数据集的日期变量配对,这似乎不可行。

我考虑在 dplyr 包中使用 outer_join,如果所有日期列都具有相同的名称(即,如果每个列都称为“date”而不是“date”、“date.1”等),这可能会起作用.我可以重命名每个日期列,但考虑到它们的数量很大,这会很麻烦。

最后,我考虑了合并,但这似乎需要首先将大数据框(包括所有日期变量对)分解为多个数据框。此外,由于日期变量的名称不同,我不得不将它们一一合并。

我怀疑可能有一种方法可以通过应用命令到达我要去的地方,但我对应用命令的技能有限。

提前感谢您的帮助和指导。

【问题讨论】:

  • 您考虑过merge.zoo 选项吗?

标签: r


【解决方案1】:

使用下面的for循环怎么样?

res <- merge(df[,1:2], df[,3:4], by = c(1,1), all = TRUE)

for(i in seq_len((length(df)-4)/2)){
    res <- merge(res, df[,(3 + i*2):(4 + i*2)], by = c(1,1), all = TRUE)
}
res
        date v1 v2 v3
1 2015-01-01  1  4 NA
2 2015-01-02  2 NA  5
3 2015-01-03  3  5  2
4 2015-01-04  4  3  6
5 2015-01-05  5  2  2
6 2015-01-06  6  6  4
7 2015-01-07  7  3  5
8 2015-01-08 NA  1 NA
9 2015-01-09 NA NA  1

【讨论】:

  • 谢谢RStudent。这很有帮助。我确实遇到了一个我还没有解决的问题。也就是说,我在第一对的末尾有两行 NA 行。该循环在所有对中复制了这些。易于管理,但很想知道为什么会这样。
【解决方案2】:

这是我使用包reshape2 的方法。我敢肯定还有更简洁的方法,但是reshape2 有非常好的工具来解决此类问题。这个过程也很容易阅读。

# Split the paired columns and put them in a list 
# so you can work on all three at once
df_list <- list(df[1:2], df[3:4], df[5:6])



# Melt each chunk then stack them.
# If you're not familiar with "melting" and "casting" data
# and the reshape2 package, it's well worth learning.
library(reshape2)

df_melt <- ldply(df_list, .fun = function(x) {

    # Melt it
    x_melt <- melt(x,
                   id.var = names(x)[1],
                   measure.var = names(x)[2]
    )

    # Rename it
    names(x_melt) <- c("date", "variable", "value")


    # Return it
    x_melt

})


# Now you've got a stack of records where each value
# is defined by two other variables: the date and the
# variable of origin (v1, v2, v3).
# Cast that data wide
df_wide <- dcast(df_melt,
                 date ~ variable,
                 value.var = "value"
)

【讨论】:

  • 据我了解,他希望避免手动制作块,因为有很多 (70) 日期列对
  • 我想你可以做这样的事情来创建一个列表。 odd &lt;- seq(1, 70, 2); lapply(odd, function(x) mydf[, c(x, x+1)])。然后,您可以避免手动工作并应用此过程。
  • 谢谢你,Matt Parker、RStudent 和爵士乐。马特的建议很有帮助,但正如 RStudent 指出的那样,我试图避免手动命名每一对。我能够使用 jazzurro 的代码用三对三对建立一个列表,但后来无法重塑它。我收到以下错误:名称错误(x_melt)
  • @DavidS 很抱歉疏忽 - 这绝对不是您想要手动执行的操作。 jazzurro 的 sn-p 仅使用示例数据生成了一个与我的df_list 相同的列表,因此很难知道整个集合中的错误可能是什么。您可以尝试将该 sn-p 应用于 head(df) - 应该 为您提供 70 个 6 行 data.frames 的列表,该列表足够小,您可以手动查看奇数。跨度>
  • @DavidS 如果您愿意,您可以发布 dput(head(df)) 的完整数据集的输出 - 这样可能更容易识别问题。祝你好运!
【解决方案3】:

从这个例子中,似乎可以将您的“data.frame”转换为长格式:

lDF = data.frame(date = unlist(DF[grep("^date", names(DF))]),
                 var = rep(names(DF)[grep("v", names(DF))], each = nrow(DF)),
                 val = unlist(DF[grep("v", names(DF))]))
lDF

从那里,一个方便的方法是这样的:

mat = array(NA, c(length(levels(lDF$date)), length(levels(lDF$var))), 
            list(levels(lDF$date), levels(lDF$var)))
mat[as.matrix(lDF[c("date", "var")])] = lDF$val              
mat
#           v1 v2 v3
#2015-01-01  1  4 NA
#2015-01-02  2 NA  5
#2015-01-03  3  5  2
#2015-01-04  4  3  6
#2015-01-05  5  2  2
#2015-01-06  6  6  4
#2015-01-07  7  3  5
#2015-01-08 NA  1 NA
#2015-01-09 NA NA  1

结果是“矩阵”,但很容易转换为所需的“data.frame”cbind.data.frame(date = rownames(mat), mat)。 “DF”:

DF = structure(list(date = structure(1:7, .Label = c("2015-01-01", 
"2015-01-02", "2015-01-03", "2015-01-04", "2015-01-05", "2015-01-06", 
"2015-01-07"), class = "factor"), v1 = 1:7, date.1 = structure(1:7, .Label = c("2015-01-01", 
"2015-01-03", "2015-01-04", "2015-01-05", "2015-01-06", "2015-01-07", 
"2015-01-08"), class = "factor"), v2 = c(4L, 5L, 3L, 2L, 6L, 
3L, 1L), date.2 = structure(1:7, .Label = c("2015-01-02", "2015-01-03", 
"2015-01-04", "2015-01-05", "2015-01-06", "2015-01-07", "2015-01-09"
), class = "factor"), v3 = c(5L, 2L, 6L, 2L, 4L, 5L, 1L)), .Names = c("date", 
"v1", "date.1", "v2", "date.2", "v3"), class = "data.frame", row.names = c(NA, 
-7L))

现在,我更加关注答案,上面的概念已经包含在 Matt Parker 的方法中,但使用了基本工具。

【讨论】:

  • 谢谢,alexis_laz。从矩阵到数据帧的转换非常优雅,这需要比我想用 70 个日期变量对做更多的手动工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-22
  • 1970-01-01
相关资源
最近更新 更多