【问题标题】:Order data frame rows according to vector with specific order根据具有特定顺序的向量对数据框行进行排序
【发布时间】:2012-08-12 05:00:28
【问题描述】:

有没有一种更简单的方法来确保数据框的行按照我在下面的简短示例中实现的“目标”向量进行排序?

df <- data.frame(name = letters[1:4], value = c(rep(TRUE, 2), rep(FALSE, 2)))

df
#   name value
# 1    a  TRUE
# 2    b  TRUE
# 3    c FALSE
# 4    d FALSE

target <- c("b", "c", "a", "d")

这似乎有点太“复杂”而无法完成工作:

idx <- sapply(target, function(x) {
    which(df$name == x)
})
df <- df[idx,]
rownames(df) <- NULL

df 
#   name value
# 1    b  TRUE
# 2    c FALSE
# 3    a  TRUE
# 4    d FALSE

【问题讨论】:

    标签: r sorting dataframe


    【解决方案1】:

    试试match:

    df <- data.frame(name=letters[1:4], value=c(rep(TRUE, 2), rep(FALSE, 2)))
    target <- c("b", "c", "a", "d")
    df[match(target, df$name),]
    
      name value
    2    b  TRUE
    3    c FALSE
    1    a  TRUE
    4    d FALSE
    

    只要您的target 包含与df$name 完全相同的元素,并且不包含重复值,它就可以工作。

    来自?match

    match returns a vector of the positions of (first) matches of its first argument 
    in its second.
    

    因此match 找到与target 的元素匹配的行号,然后我们按该顺序返回df

    【讨论】:

    • 太棒了,这更像是它,正是我想要的!非常感谢
    • 一个问题,如果我要匹配的列有重复值怎么办?喜欢b,c,a,d,b,c,a,d。我试过match,但效果不好。
    • @Yulong:我认为您必须明确确保在触发 match() 之前删除重复项。想到的是duplicated()unique() 或其他一些自定义例程,这些例程“保留”所需元素,同时丢弃其他元素。 HTH
    • @Edward 这是一个不错的解决方案。但是,它也会更改索引。我怎样才能让它们按升序排列(1、2、3、4)?
    • 不确定这是最干净的方法,但只有“基本”功能,如果您在 df 中有重复项,这应该可以工作:df &lt;- data.frame(name=letters[c(1:4, 1:4)], value=c(rep(TRUE, 2), rep(FALSE, 2),rep(TRUE, 2), rep(FALSE, 2) )) target &lt;- c("b", "c", "a", "d") df[order(unlist(sapply(df$name, function(x) which(target == x)))),]
    【解决方案2】:

    每当我需要匹配数据时,我更喜欢在dplyr 中使用***_join。一种可能的尝试

    left_join(data.frame(name=target),df,by="name")
    

    请注意,***_join 的输入需要 tbls 或 data.frame

    【讨论】:

    • 是的,dplyr 中的 *_join 函数非常好。现在也经常使用这些
    • 在这种情况下,建议将目标订单声明为 tibble,以避免 data.frame() 转换为因子。 target &lt;- tibble(name = c("b", "c", "a", "d"))
    • 并使用管道语法:df %&gt;% right_join(tibble(name = target), by = "name")
    • 请小心。自 dplyr 1.0.0 以来,这不再可能。一个突破性的变化。见changelog
    【解决方案3】:

    我们可以根据target调整因子水平,并在arrange中使用

    library(dplyr)
    df %>% arrange(factor(name, levels = target))
    
    #  name value
    #1    b  TRUE
    #2    c FALSE
    #3    a  TRUE
    #4    d FALSE
    

    或者order它并在slice中使用它

    df %>% slice(order(factor(name, levels = target)))
    

    【讨论】:

    • IMO 的最佳解决方案
    • 对我来说最好和最简单的解决方案。
    • 适用很好,仅当“目标”向量包含与“名称”向量相同的元素时;否则,订单中断。
    【解决方案4】:

    这种方法有点不同,它为我提供了比上一个答案更多的灵活性。 通过使其成为有序因子,您可以在arrange 等中很好地使用它。我使用了gdata 包中的 reorder.factor。

    df <- data.frame(name=letters[1:4], value=c(rep(TRUE, 2), rep(FALSE, 2)))
    target <- c("b", "c", "a", "d")
    
    require(gdata)
    df$name <- reorder.factor(df$name, new.order=target)
    

    接下来,使用它现在已订购的事实:

    require(dplyr)
    df %>%
      arrange(name)
        name value
    1    b  TRUE
    2    c FALSE
    3    a  TRUE
    4    d FALSE
    

    如果你想回到原来的(字母)排序,只需使用as.character() 让它恢复到原来的状态。

    【讨论】:

    • 有人知道这个的 data.table 版本吗?
    • @Reilstein setDT(df)[ , name := factor(name, levels = target)]。然后看data.table这两个答案here
    【解决方案5】:

    如果您不想使用任何库并且您的数据中有重复出现,您也可以使用whichsapply

    new_order <- sapply(target, function(x,df){which(df$name == x)}, df=df)
    df        <- df[new_order,]
    

    【讨论】:

      【解决方案6】:

      这是一个类似的系统,适用于以下情况:您最初有一个要排序的变量,但随后您想根据该次要变量在初始排序中首次出现的顺序按次要变量进行排序。

      在下面的函数中,初始排序变量称为order_by,次要变量称为order_along - 如“按此变量的初始顺序排序”。

      library(dplyr, warn.conflicts = FALSE)
      df <- structure(
        list(
          msoa11hclnm = c(
            "Bewbush", "Tilgate", "Felpham",
            "Selsey", "Brunswick", "Ratton", "Ore", "Polegate", "Mile Oak",
            "Upperton", "Arundel", "Kemptown"
          ),
          lad20nm = c(
            "Crawley", "Crawley",
            "Arun", "Chichester", "Brighton and Hove", "Eastbourne", "Hastings",
            "Wealden", "Brighton and Hove", "Eastbourne", "Arun", "Brighton and Hove"
          ),
          shape_area = c(
            1328821, 3089180, 3540014, 9738033, 448888, 10152663, 5517102,
            7036428, 5656430, 2653589, 72832514, 826151
          )
        ),
        row.names = c(NA, -12L), class = "data.frame"
      )
      

      这并没有给我我需要的东西:

      df %>% 
        dplyr::arrange(shape_area, lad20nm)
      #>    msoa11hclnm           lad20nm shape_area
      #> 1    Brunswick Brighton and Hove     448888
      #> 2     Kemptown Brighton and Hove     826151
      #> 3      Bewbush           Crawley    1328821
      #> 4     Upperton        Eastbourne    2653589
      #> 5      Tilgate           Crawley    3089180
      #> 6      Felpham              Arun    3540014
      #> 7          Ore          Hastings    5517102
      #> 8     Mile Oak Brighton and Hove    5656430
      #> 9     Polegate           Wealden    7036428
      #> 10      Selsey        Chichester    9738033
      #> 11      Ratton        Eastbourne   10152663
      #> 12     Arundel              Arun   72832514
      

      这是一个函数:

      order_along <- function(df, order_along, order_by) {
        cols <- colnames(df)
        
        df <- df %>%
          dplyr::arrange({{ order_by }})
        
        df %>% 
          dplyr::select({{ order_along }}) %>% 
          dplyr::distinct() %>% 
          dplyr::full_join(df) %>% 
          dplyr::select(dplyr::all_of(cols))
        
      }
      
      order_along(df, lad20nm, shape_area)
      #> Joining, by = "lad20nm"
      #>    msoa11hclnm           lad20nm shape_area
      #> 1    Brunswick Brighton and Hove     448888
      #> 2     Kemptown Brighton and Hove     826151
      #> 3     Mile Oak Brighton and Hove    5656430
      #> 4      Bewbush           Crawley    1328821
      #> 5      Tilgate           Crawley    3089180
      #> 6     Upperton        Eastbourne    2653589
      #> 7       Ratton        Eastbourne   10152663
      #> 8      Felpham              Arun    3540014
      #> 9      Arundel              Arun   72832514
      #> 10         Ore          Hastings    5517102
      #> 11    Polegate           Wealden    7036428
      #> 12      Selsey        Chichester    9738033
      

      reprex package (v0.3.0) 于 2021-01-12 创建

      【讨论】:

      • 如果我有 27 个观察值(A1 到 A38)重复多次(总行 7938)并且我想根据相同的情况进行排序,如何处理。目标
      猜你喜欢
      • 2020-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多