【问题标题】:Spreading key value pairs into columns将键值对分散到列中
【发布时间】:2016-10-12 13:50:35
【问题描述】:

我遇到了以下数据整理问题。每个数据集都有多个aValue 值,每个aName 值。这可以很容易地用一个整洁的数据框来表示。

someDatasets <- list(dataset1 = data.frame(aName = c("a", "a", "a", "b", "b"), aValue = 1:5, dataset = "ds1"),
                     dataset2 = data.frame(aName = c("a", "a", "a", "b", "c", "c"), aValue = (1:6)*10 , dataset = "ds2"),
                     dataset3 = data.frame(aName = c("a", "c", "c", "c"), aValue = (1:4)*100, dataset = "ds3"))

tidyData <- Reduce(dplyr::bind_rows, someDatasets)

我想将数据集变量“传播”到各个列中。 (由于重复的键,我无法使用 tidyr::spread 创建所需的输出。)

###
# Desired output
###
# aName ds1 ds2 ds3
# a     1   10  100
# a     2   20  NA
# a     3   30  NA
# b     4   40  NA
# b     5   NA  NA
# c     NA  50  200
# c     NA  60  300
# c     NA  NA  400

有没有一种简洁的方法来生成所需的输出?

ps:我知道spread-key-value-pairs-when-keys-are-in-different-columns 的问题,但解决方案

dcast(melt(someDatasets, id = "aName", na.rm = TRUE), aName~value)

由于使用了聚合函数length,因此不会产生所需的输出。

【问题讨论】:

  • 长度在哪里使用,为什么不理想?
  • 可能是bind_rows(someDatasets) %&gt;% group_by(dataset) %&gt;% mutate(aName = paste0(aName, 1:n())) %&gt;% spread(dataset, aValue) %&gt;% mutate(aName = substr(aName, 1, 1))
  • 根据“aName”和“dataset”(来自您的“tidyData”数据集)的分组添加辅助ID,然后使用dcast。例如,如果您将辅助 ID 命名为“ID”,则可以使用 dcast(tidyDataWithID, aName + ID ~ dataset, value.var = "aValue")
  • @Hack-R dcast 说“缺少聚合函数:默认为长度”。 @lukeA 非常接近,是的,除了它会产生 5 个“c”行,其中 3 行实际上就足够了。 @a Hancard 和马海毛谢谢你,这工作tidyData %&gt;% group_by(aName, dataset) %&gt;% mutate(ID = 1:n()) %&gt;% dcast(aName + ID ~ dataset, value.var = "aValue")。如果您发布带有解释的答案,我可以接受它作为答案。
  • 在我看来,必须有更多的信息。可以用作ID的东西。例如数据集 1 的第 1 行和第 2 行无法区分:它们都有 aName = a 和 dataset = ds1。

标签: r dataframe dplyr tidyr dcast


【解决方案1】:

正如@lukeA 和@A Handcart 和 Mohair 在 cmets 中所述,您可以在数据中添加额外的 ID 以避免重复键问题。

library(dplyr)
library(tidyr)

tidyData = bind_rows(someDatasets) %>% 
   group_by(dataset, aName) %>% 
   mutate(id = paste0(aName, 1:n())) %>% 
   ungroup() %>% 
   select(-aName)

# head(tidyData)
# Source: local data frame [6 x 3]
# 
#   aValue dataset    id
#    <dbl>   <chr> <chr>
# 1      1     ds1    a1
# 2      2     ds1    a2
# 3      3     ds1    a3
# 4      4     ds1    b1
# 5      5     ds1    b2
# 6     10     ds2    a1

id 现在在每个组(数据集)中都是唯一的,因此我们可以继续传播:

tidyData %>% 
   spread(dataset, aValue) %>% 
   mutate(id = substr(id, 1, 1))

# Source: local data frame [10 x 4]
# 
#      id   ds1   ds2   ds3
#   <chr> <dbl> <dbl> <dbl>
# 1     a     1    10   100
# 2     a     2    20    NA
# 3     a     3    30    NA
# 4     b     4    40    NA
# 5     b     5    NA    NA
# 6     c    NA    50   200
# 7     c    NA    60   300
# 8     c    NA    NA   400

【讨论】:

  • 谢谢。第二个输出基于非唯一的aValues 和tidyData %&gt;% group_by(aName, dataset) %&gt;% mutate(ID = 1:n()) %&gt;% ungroup() %&gt;% tidyr::unite(col = "aName", aName, ID, sep = "#") %&gt;% tidyr::spread(dataset, aValue) %&gt;% tidyr::separate(col = "aName", into = c("aName", "ID"), remove = T, sep = "#") %&gt;% dplyr::select(- ID) 完成了这项工作。我觉得tidyr 版本比reshape2 版本更冗长——这很不幸。
  • @Drey 抱歉,我忘记更新代码的上半部分了——现在看(稍微不那么冗长...)
  • retouring uniteseparate 确实更易读。再次感谢您和其他人。
猜你喜欢
  • 1970-01-01
  • 2013-11-14
  • 1970-01-01
  • 1970-01-01
  • 2015-05-24
  • 1970-01-01
  • 2014-09-05
  • 2017-06-16
  • 2020-11-25
相关资源
最近更新 更多