是否可以在类似于 dcast 的 tidyr 中的多个列上使用扩展? [复制]

Posted

技术标签:

【中文标题】是否可以在类似于 dcast 的 tidyr 中的多个列上使用扩展? [复制]【英文标题】:Is it possible to use spread on multiple columns in tidyr similar to dcast? [duplicate] 【发布时间】:2014-09-15 18:52:53 【问题描述】:

我有以下虚拟数据:

library(dplyr)
library(tidyr)
library(reshape2)
dt <- expand.grid(Year = 1990:2014, Product=LETTERS[1:8], Country = paste0(LETTERS, "I")) %>%   select(Product, Country, Year)
dt$value <- rnorm(nrow(dt))

我选择了两种产品-国家/地区组合

sdt <- dt %>% filter((Product == "A" & Country == "AI") | (Product == "B" & Country =="EI"))

我想并排查看每个组合的值。我可以用dcast 做到这一点:

sdt %>% dcast(Year ~ Product + Country)

是否可以使用 tidyr 包中的 spread 执行此操作?

【问题讨论】:

@jaap 这个问题不是旧问题的重复。较旧的一个是关于重塑数据的一般性,这个是关于如何在特定的包中实现某些旋转。 这个是个骗子。确实,另一个问题并不专注于特定问题,因此吸引了多个软件包的解决方案,包括您要求的那个。这使其成为结束特定问题的完美目标。 【参考方案1】:

基础 R 解决方案:

 # Concatenate grouping vector: 

dt$PC <- paste0(dt$Product, "_", dt$Country)

# Spread the vectors by year: 

dt2 <- reshape(dt[,c(!(names(dt) %in% c("Product", "Country")))],

               idvar = "Year",

               ids = unique(dt$Year),

               direction = "wide",

               timevar = "PC")

# Remove "value.", from the vector names:

names(dt2) <- gsub("value[.]", "", names(dt2))

数据:

dt <- expand.grid(Year = 1990:2014,

                  Product = LETTERS[1:8],

                  Country = paste0(LETTERS, "I"))

dt$value <- rnorm(nrow(dt))

【讨论】:

【参考方案2】:

使用 tidyr 1.0.0 版中引入的新函数pivot_wider(),只需一次函数调用即可完成。

pivot_wider()(对应方:pivot_longer())的工作方式类似于spread()。 但是,它提供了额外的功能,例如使用多个键/名称列(和/或多个值列)。 为此,参数names_from——指示新变量的名称取自哪一列——可能采用多个列名称(此处为ProductCountry)。

library("tidyr")

sdt %>% 
    pivot_wider(id_cols = Year,
                names_from = c(Product, Country)) %>% 
    head(2)
#> # A tibble: 2 x 3
#>     Year   A_AI    B_EI
#>    <int>  <dbl>   <dbl>
#>  1  1990 -2.08  -0.113 
#>  2  1991 -1.02  -0.0546

另请参阅:https://tidyr.tidyverse.org/articles/pivot.html

【讨论】:

【参考方案3】:

一种选择是通过paste 加入“Product”和“Country”列来创建一个新的“Prod_Count”,使用 select 删除这些列并使用 @ 从“long”重塑为“wide” 987654324@ 来自tidyr

 library(dplyr)
 library(tidyr)
 sdt %>%
 mutate(Prod_Count=paste(Product, Country, sep="_")) %>%
 select(-Product, -Country)%>% 
 spread(Prod_Count, value)%>%
 head(2)
 #  Year      A_AI       B_EI
 #1 1990 0.7878674  0.2486044
 #2 1991 0.2343285 -1.1694878

或者我们可以通过使用tidyr 中的unite(来自@beetroot 的评论)来避免几个步骤,然后像以前一样重新整形。

 sdt%>% 
 unite(Prod_Count, Product,Country) %>%
 spread(Prod_Count, value)%>% 
 head(2)
 #   Year      A_AI       B_EI
 # 1 1990 0.7878674  0.2486044
 # 2 1991 0.2343285 -1.1694878

【讨论】:

好吧,有unite(),但它似乎只适用于数字数据(虽然是故意的?)。 @beetroot,谢谢,是的,它似乎工作sdt%&gt;% unite(Prod_Count, Product,Country) %&gt;% spread(Prod_Count, value)%&gt;% head() 这是 Hadley 认可的解决此问题的方法 ;) 在过去几个月多次咨询此线程后,我发现基于 reshape2/dcast 的解决方案最优雅。另见***.com/questions/27418919/dplyr-with-subgroup-join,其中基于展开的解决方案不能推广到多个分组列,但基于重塑的可以。 @hadley 对于 tidyverse 来说,这是一个异常丑陋的解决方案。所有列都必须多次列出,更糟糕的是它们会丢失类型,所以所有内容都必须转换回数字。

以上是关于是否可以在类似于 dcast 的 tidyr 中的多个列上使用扩展? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

dcast 中的 value.var 可以是一个列表还是有多个值变量?

在 Hadoop 或 MySQL 中重塑 dcast 表

R语言—tidyr

Spark是不是支持melt和dcast [重复]

通过 dplyr 在第一个遇到的数字上使用单独的(tidyr)分离列

R语言数据集行列互换技巧