【问题标题】:R: keep c2 values long, use c1 values as column namesR:保持 c2 值较长,使用 c1 值作为列名
【发布时间】:2021-02-10 21:40:11
【问题描述】:

我有一个超过 3000 个 obs 的数据框。看起来像这样:

dat <- data.frame(
  letter = rep(c("A", "B", "C"), each=4),
  numbers = rep(seq(1,1.75, by=0.25), 3)
  )
dat
# letter numbers
# 1       A    1.00
# 2       A    1.25
# 3       A    1.50
# 4       A    1.75
# 5       B    1.00
# 6       B    1.25
# 7       B    1.50
# 8       B    1.75
# 9       C    1.00
# 10      C    1.25
# 11      C    1.50
# 12      C    1.75

我想重新排列这个数据框,使其看起来像:

# A    B    C
# 1 1.00 1.00 1.00
# 2 1.25 1.25 1.25
# 3 1.50 1.50 1.50
# 4 1.75 1.75 1.75

无需手动对所有 3,000 个观察值进行硬编码。

在我迄今为止尝试过的所有工具中(可能是错误的)(reshape、split、group_split、mutate %>% split %>% unnest、pivot_wider 和 dcast)split 提供了最接近我的输出试图实现(见下文),但我不确定如何索引嵌套在数据框中的数据框的特定列,并且我不确定如何在不加入它们的情况下重新组合各个数据框,即我想保留所有每个字母下的值相互独立。

spldf <- split(dat, dat$letter)
spldf

# $A
# letter numbers
# 1      A    1.00
# 2      A    1.25
# 3      A    1.50
# 4      A    1.75
# 
# $B
# letter numbers
# 5      B    1.00
# 6      B    1.25
# 7      B    1.50
# 8      B    1.75
# 
# $C
# letter numbers
# 9       C    1.00
# 10      C    1.25
# 11      C    1.50
# 12      C    1.75

我一直在浏览 S.O. 2天了,还没有看到一个足够相似的问题让我复制它。感谢您对这个问题的任何帮助!

【问题讨论】:

    标签: r


    【解决方案1】:

    如果“字母”列的元素数量相同,我们可以使用unstack 以及base R

    unstack(dat, numbers ~ letter)
    

    -输出

    #    A    B    C
    #1 1.00 1.00 1.00
    #2 1.25 1.25 1.25
    #3 1.50 1.50 1.50
    #4 1.75 1.75 1.75
    

    但是,如果数据真的很大,长度不等的可能性就更大。在这种情况下,我们需要一个序列列来确保如果长度较小,则可以用NA填充它

    library(dplyr)
    library(tidyr)
    library(data.table)
    dat %>% 
        mutate(rn = rowid(letter)) %>%
        pivot_wider(names_from = letter, values_from = numbers) %>% 
        select(-rn)
    

    【讨论】:

    • 一旦我将我的实际数据框减少到 2 列,就像上面的示例一样,这非常有效。谢谢!
    【解决方案2】:

    使用dcastdata.table 选项

    dcast(setDT(dat),rowid(letter)~letter,value.var = "numbers")[,-1]
    

    给予

          A    B    C
    1: 1.00 1.00 1.00
    2: 1.25 1.25 1.25
    3: 1.50 1.50 1.50
    4: 1.75 1.75 1.75
    

    【讨论】:

      【解决方案3】:

      您仍然可以在 tidyverse 框架中执行此操作,但您需要添加一个 id 变量来标记字母内的数字序列。

      library(tidyverse)
      
      dat <- data.frame(
        letter = rep(c("A", "B", "C"), each=4),
        numbers = rep(seq(1,1.75, by=0.25), 3)
      )
      
      dat%>%  group_by(letter)%>%
        mutate(id=1:n()) %>%  
        pivot_wider(id_cols=id, 
                    names_from = letter,
                    values_from=numbers) %>% 
        select(-id)
      #> # A tibble: 4 x 3
      #>       A     B     C
      #>   <dbl> <dbl> <dbl>
      #> 1  1     1     1   
      #> 2  1.25  1.25  1.25
      #> 3  1.5   1.5   1.5 
      #> 4  1.75  1.75  1.75
      

      reprex package (v0.3.0) 于 2021-02-10 创建

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-11
        • 1970-01-01
        • 1970-01-01
        • 2017-11-16
        • 2015-01-27
        • 1970-01-01
        相关资源
        最近更新 更多