【问题标题】:Implicit sorting in tidyr::spread and dplyr::summarisetidyr::spread 和 dplyr::summarise 中的隐式排序
【发布时间】:2015-06-05 12:37:40
【问题描述】:

我的数据是有序的观察数据,我希望在进行操作时尽可能保持有序。

回答this question,我在数据框中将“B”放在“A”之前。生成的宽数据按“名称”列排序,即首先是“A”,然后是“B”。

df = data.frame(name=c("B","B","A","A"),
                group=c("g1","g2","g1","g2"),
                V1=c(10,40,20,30),
                V2=c(6,3,1,7))

gather(df, Var, Val, V1:V2) %>% 
unite(VarG, Var, group) %>% 
spread(VarG, Val)

  name V1_g1 V1_g2 V2_g1 V2_g2
1    A    20    30     1     7
2    B    10    40     6     3

有没有办法保持原来的顺序?像这样:

  name V1_g1 V1_g2 V2_g1 V2_g2
1    B    10    40     6     3
2    A    20    30     1     7

04/02 编辑:我刚刚发现 dplyr::summarise 也可以进行排序。 arrange(name, df$name) 仍然可以恢复订单。但我想知道包装设计是否需要额外的分类?

df %>% 
  group_by(name) %>% 
  summarise(n()) %>% 

  name n()
1    A   2
2    B   2

【问题讨论】:

  • 有趣。似乎在传播步骤中,甚至“名称”变量的因子水平也发生了变化......

标签: r dplyr data-manipulation tidyr


【解决方案1】:

tidyr::pivot_wider(),自 tidyr 1.0.0 以来推荐替换 tidyr::spread(),保持行顺序,以便您可以这样做:

library(tidyr)

df = data.frame(name=c("B","B","A","A"),
                group=c("g1","g2","g1","g2"),
                V1=c(10,40,20,30),
                V2=c(6,3,1,7))

pivot_wider(df, names_from = "group", values_from = c("V1", "V2"))
#> # A tibble: 2 x 5
#>   name  V1_g1 V1_g2 V2_g1 V2_g2
#>   <fct> <dbl> <dbl> <dbl> <dbl>
#> 1 B        10    40     6     3
#> 2 A        20    30     1     7

reprex package (v0.3.0) 于 2019-09-14 创建

【讨论】:

    【解决方案2】:

    顺序取自因子水平的顺序。

    str(df)
    'data.frame':   4 obs. of  4 variables:
     $ name : Factor w/ 2 levels "A","B": 2 2 1 1
     $ group: Factor w/ 2 levels "g1","g2": 1 2 1 2
     $ V1   : num  10 40 20 30
     $ V2   : num  6 3 1 7
    

    看到级别是“A”,“B”。

    因此,如果您将关卡的顺序设置为它们在其中显示的顺序,它将起作用:

    df = data.frame(name=c("B","B","A","A"),
                    group=c("g1","g2","g1","g2"),
                    V1=c(10,40,20,30),
                    V2=c(6,3,1,7))
    
    df %>% 
        mutate(name = factor(name,levels=unique(name))) %>% 
        mutate(group = factor(group,levels=unique(group))) %>% 
        gather(Var, Val, V1:V2) %>% 
        unite(VarG, Var, group) %>% 
        spread(VarG, Val)
    

    结果:

      name V1_g1 V1_g2 V2_g1 V2_g2
    1    B    10    40     6     3
    2    A    20    30     1     7
    

    【讨论】:

    • 我从来没有意识到/欣赏 unique() 以与给定相同的顺序返回 - 这对其他应用程序也很有用!
    【解决方案3】:

    您可以根据原始数据框中的顺序按名称排序:

    gather(df, Var, Val, V1:V2) %>% 
      unite(VarG, Var, group) %>% 
      spread(VarG, Val) %>%
      arrange( order(match(name, df$name)))
    
    #   name V1_g1 V1_g2 V2_g1 V2_g2
    # 1    B    10    40     6     3
    # 2    A    20    30     1     7
    

    【讨论】:

    • 谢谢。 arrange(match(name, df$name) 也可以。但是如何处理多个分组级别,比如“name”、“name1”、“name2”。 spread 默认包含排序对我来说没有意义。
    • 你不需要订单是对的。至于级别 - 您可以在arrange( a, b, c, ...) 中使用多个参数,并且可以随意排序(也许我只是看不到问题所在)。但我理解你的痛苦,因为你已经把一切都整理好了……
    • @bergant,对我来说,除了排序之外更大的问题是因子水平正在改变。
    • @AnandaMahto 我没有看到因子水平发生变化——水平在两种情况下都是“A”、“B”。但是排序确实发生了。从原始的 2, 2, 1, 1 到结果中的 1, 2。我有 tidyr 版本 0.2.0
    • 嗯。你说得对。那么arrange 会重构吗?这对我来说似乎很奇怪。
    猜你喜欢
    • 2018-07-27
    • 1970-01-01
    • 1970-01-01
    • 2019-05-19
    • 1970-01-01
    • 1970-01-01
    • 2020-02-22
    • 2016-05-24
    • 2016-09-16
    相关资源
    最近更新 更多