【问题标题】:Long to wide format for simple dataframe [duplicate]简单数据帧的长到宽格式[重复]
【发布时间】:2019-09-29 12:54:54
【问题描述】:

我有一个这样的数据集:

df <- data.frame(origin = c('A', 'B', 'C'), freq = c(100,3000,200))

  origin freq
1      A  100
2      B 3000
3      C  200

我想把它转换成这样的结构:

A   B    C
100 3000 200

这样我就可以 cbind 将其添加到现有数据框


  1. tidyr::spread()
    我尝试使用 tidyr::spread 但这将要求行具有唯一的 ID。我可以这样做,但这不会给我想要的结果:

    > df %>% mutate(id = row_number()) %>% spread(origin, freq) id A B C 1 1 100 NA NA 2 2 NA 3000 NA 3 3 NA NA 200

  2. t()
    我可以转置数据框,但是它会将origin 转换为行而不是列名。当然,我可以通过手动设置列名来编辑它,但这似乎很麻烦。

    as.data.frame(t(df)) V1 V2 V3 origin A B C freq 100 3000 200

【问题讨论】:

  • 我没有得到同样的结果,当我运行 rownames(data.frame(t (df))) origin 和 freq 是 rownames

标签: r format tidyr transpose


【解决方案1】:

我们可以在spread 之前添加一个临时列。

library(dplyr)
library(tidyr)

df %>%
  mutate(n = 1) %>%
  spread(origin, freq) %>%
  select(-n)

#   A    B   C
#1 100 3000 200

如果您有更新版本的tidyr,我们可以使用pivot_wider 代替spread

df %>%
  mutate(n = 1) %>%
  pivot_wider(names_from = origin, values_from = freq) %>%
  select(-n)

我们也可以重构数据框

data.frame(matrix(df$freq, ncol = nrow(df), dimnames = list(NULL, df$origin)))

【讨论】:

    【解决方案2】:

    这里有一些替代方案。

    请注意,origin 列在示例中已排序,但如果不是,则 setNamesdcastdplyr 备选方案保留顺序,而其他备选方案对它们进行排序,您可能需要一个或其他行为。

    1) xtabs 我们可以使用xtabsdf 转换为c("xtabs", "table") 类的对象,然后再转换为"data.frame"。如果表格输出正常,则省略 as.data.frame.list。没有使用任何包。

    as.data.frame.list(xtabs(freq ~ origin, df))
    ##     A    B   C
    ## 1 100 3000 200
    

    1a) tapply 我们可以以几乎相同的方式使用tapply

    as.data.frame.list(tapply(df$freq, df$origin, c))
    ##     A    B   C
    ## 1 100 3000 200
    

    1b) setNames 同样,setNames 也可以以同样的方式使用。

    as.data.frame.list(setNames(df$freq, df$origin))
    ##     A    B   C
    ## 1 100 3000 200
    

    2) 拆分 另一种方法是将freq 拆分为origin,给出一个列表,然后将该列表转换为data.frame。同样,没有使用任何包。

    as.data.frame(split(df$freq, df$origin))
    ##     A    B   C
    ## 1 100 3000 200
    

    3) reshape 我们可以像这样使用reshapesetNames 行可以省略,如果我们对名称的形式不挑剔的话。

    wide <- reshape(transform(df, id = 1), dir = "wide", timevar = "origin")[-1]
    setNames(wide, df$origin)
    ##     A    B   C
    ## 1 100 3000 200
    

    4) dcast 此解决方案使用 data.table 包——reshape2 包中还有一个dcast,其工作方式类似。

    library(data.table)
    
    dcast(df, . ~ origin, value.var = "freq")
    ##     A    B   C
    ## 1 100 3000 200
    

    5) dplyr/tibble。使用指定的包,我们删除行名(仅当数据框有行名时才需要,但如果没有行名也不会受到影响),将origin 列转换为行名,转置剩下的内容并将其转换为tibble

    library(dplyr)
    library(tibble)
    
    df %>%
      remove_rownames %>%
      column_to_rownames("origin") %>%
      t %>%
      as.tibble
    
    ## # A tibble: 1 x 3
    ##       A     B     C
    ##   <dbl> <dbl> <dbl>
    ## 1   100  3000   200
    

    【讨论】:

      【解决方案3】:

      我们可以使用第一列作为行名,然后在没有它的情况下转置。

      t(`rownames<-`(df,df[,1])[-1])
      #        A    B   C
      # freq 100 3000 200
      

      【讨论】:

        猜你喜欢
        • 2021-10-20
        • 2017-07-19
        • 1970-01-01
        • 1970-01-01
        • 2021-05-01
        • 1970-01-01
        • 1970-01-01
        • 2022-07-28
        • 2020-05-18
        相关资源
        最近更新 更多