在dplyr中转置

28

I have the following data.frame

df = structure(list(HEADER = c("HOME_TRPM", "AWAY_TRPM", "HOME_TEAM","AWAY_TEAM"),
                     price = c("0.863104076023855", "-0.845186446996287","CHA", "NOP")),
               .Names = c("HEADER", "price"), row.names = c(NA, 4L), class = "data.frame")

df
#>      HEADER              price
#> 1 HOME_TRPM  0.863104076023855
#> 2 AWAY_TRPM -0.845186446996287
#> 3 HOME_TEAM                CHA
#> 4 AWAY_TEAM                NOP

我希望你能够帮我转置数据。我该如何在dplyr中实现而不使用t()函数?我尝试过。
df %>% tidyr::spread(HEADER , price)

但它不会提供一个扁平的结构,而是做了这个操作:
structure(list(AWAY_TEAM = c(NA, NA, NA, "NOP"),
     AWAY_TRPM = c(NA, "-0.845186446996287", NA, NA), 
     HOME_TEAM = c(NA, NA, "CHA", NA),
     HOME_TRPM = c("0.863104076023855", NA, NA, NA)),
 .Names = c("AWAY_TEAM", "AWAY_TRPM", "HOME_TEAM", "HOME_TRPM"),
 class = "data.frame", row.names = c(NA, 4L))

生成的数据框应该像这样:
structure(list(HOME_TRPM = "0.863104076023855",
    AWAY_TRPM = "-0.845186446996287",
    HOME_TEAM = "CHA", 
    AWAY_TEAM = "NOP"), 
.Names = c("HOME_TRPM", "AWAY_TRPM", "HOME_TEAM", "AWAY_TEAM"), 
row.names = c(NA, -1L), class = "data.frame"))

2
do.call(rbind, c(df)) 可以在不使用 t() 的情况下进行转置。 - Rich Scriven
可能你想要一个结果,类似于 setNames(do.call(data.frame, as.list(DF[[2]])), DF[[1]]) 这样的,但在 dplyr 中几乎不可能实现,因为它并不是围绕数据清洗而设计的。 - Frank
@RichardScriven 这看起来和 t() 相同,但是会得到与期望输出不同的结构。 - geodex
使用t()有什么问题? - BigTimeStats
我发现使用t()会导致数值开始表达为科学计数法,这很烦人。 - FinancialRadDeveloper
5个回答

30

我认为你需要使用tidyr而不是dplyr

library(tidyr)
library(dplyr)
df %>% mutate(group = 1) %>%
       spread(HEADER, price)

  group AWAY_TEAM          AWAY_TRPM HOME_TEAM         HOME_TRPM
1     1       NOP -0.845186446996287       CHA 0.863104076023855

使用这个方法,您可以指定分组方式,并且可以在后面添加select(-group)以便稍后删除它们。


1
未来的用户请注意,spead已经被弃用,请查看下面@Revan的答案。更多信息请参见此处 - Álvaro A. Gutiérrez-Vargas

26

spread 已经被弃用,tidyr 现在建议使用 pivot_wider()

library(tidyverse)
df %>%
    pivot_wider(names_from = HEADER, values_from = price)

这可能也与此相关 https://dev59.com/W1kS5IYBdhLWcg3wJDe6#40307807 - Álvaro A. Gutiérrez-Vargas

8

使用tibble包中的as_tibble()函数,您可以消除t()带来的不良影响。

df_t = as_tibble(t(df[, -1]))
names(df_t) = df[, 1]

5

自这篇文章最初发布以来,tidyr 必须已经更新了,我认为它现在可以完成你最初的要求:

> library(dplyr)
> library(tidyr)
Warning message:
package ‘tidyr’ was built under R version 3.4.4 
> df
         HEADER              price
    1 HOME_TRPM  0.863104076023855
    2 AWAY_TRPM -0.845186446996287
    3 HOME_TEAM                CHA
    4 AWAY_TEAM                NOP

    > tidyr::spread(df, HEADER, price)
      AWAY_TEAM          AWAY_TRPM HOME_TEAM         HOME_TRPM
    1       NOP -0.845186446996287       CHA 0.863104076023855

如果你有一个更大的数据框,你总是可以进行收集 (gather) 和展开 (spread) 操作:
> mdf <- data.frame(Things = c("Cookies","Cake","Knives","Kittens", "Politics"), Darkness = sample(1:5), Despair = sample(1:5), Defeat = sample(1:5))> mdf 
    Things Darkness Despair Defeat
1  Cookies        3       4      1
2     Cake        2       2      5
3   Knives        1       3      2
4  Kittens        5       5      3
5 Politics        4       1      4
> mdf %>% tidyr::gather(Idea, Warning_Level, Darkness:Defeat)
     Things     Idea Warning_Level
1   Cookies Darkness             3
2      Cake Darkness             2
3    Knives Darkness             1
4   Kittens Darkness             5
5  Politics Darkness             4
6   Cookies  Despair             4
7      Cake  Despair             2
8    Knives  Despair             3
9   Kittens  Despair             5
10 Politics  Despair             1
11  Cookies   Defeat             1
12     Cake   Defeat             5
13   Knives   Defeat             2
14  Kittens   Defeat             3
15 Politics   Defeat             4
> mdf %>% tidyr::gather(Idea, Warning_Level, Darkness:Defeat) %>% tidyr::spread(Things, Warning_Level)
      Idea Cake Cookies Kittens Knives Politics
1 Darkness    2       3       5      1        4
2   Defeat    5       1       3      2        4
3  Despair    2       4       5      3        1

0

非常丑陋但是解决了Ben Bolker提到的问题,它允许您移动一组行。假设我们想一次性将ID为2到4的行移动到5之后

df %>%
  column_to_rownames(var = "ID") %>%
    t %>%
      as.data.frame %>%
        relocate(`2`:`4`,
                 .after = `5`) %>%
          t %>%
            as.data.frame %>%
              rownames_to_column(var = "ID") 

# output
#   ID var1 var2
# 1  1    a    1
# 2  5    e    1
# 3  2    b    1
# 4  3    c    0
# 5  4    d    0

当然,这只是将relocate的出色功能改装成行。比我更了解R的其他人可能有更简洁的解决方案。如果有一个relocate_rows()就好了!


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