【问题标题】:Sorting dataframe by multiple columns through list of column names通过列名列表按多列对数据框进行排序
【发布时间】:2019-08-31 09:36:41
【问题描述】:

我有一个循环,在不同的迭代中,我想使用不同的列列表对数据框进行排序。当我对排序变量进行硬编码时,我可以进行这种排序。但是我想使用变量列表传递列名。我找不到这样做的方法。

DT <-data.frame(avar = c(1,4,3,1), bvar = c("a","f","s","b"), cvar = c(3,4,5,2))

sort1 <-c("avar", "cvar")
sort2 <-c("avar", "bvar")
sorting <-list(sort1,sort2)
DT2<-list()

for (i in 1:2) {
  sorter<- sorting[[i]]
   #THE FOLLOWING SOLUTION WORKS!!!
   DT2[[i]] <- DT[do.call(order,DT[as.character(sorting[[i]])]),]       
}

我所说的按 c("avar", "cvar") 排序的意思是数据首先按 avar 排序,然后(如果有两个相同的 avar 值)然后按 cvar。换句话说,按该向量排序的输出应该只是一个排序的数据帧(而不是列表)。按 c("avar", "bvar") 排序也是一样。上面的“ps1”代表建议的解决方案之一。它给了我 DT2[[1]] 这是两个数据帧的列表。那不是我需要的。 DT2 应该是两个数据帧的列表。 DT2[[1]] 应该是一个数据帧。

我还想强调,我确实需要通过循环进行排序,而不是通过将列表(“排序”)传递给命令。换句话说,第一次迭代应该按排序列表的第一项对数据库进行排序,这是我代码中的向量“排序器”。在实际应用中,不同迭代的数据并不是同一个数据集。

第一次循环后,DT2[[1]]应该排序如下:

avar  bvar  cvar
1     b     2
1     a     3
3     s     5
4     f     4    

在第二个循环之后 DT2[[2]] 应该排序为:

avar  bvar  cvar
1     a     3
1     b     2
3     s     5
4     f     4    

在现实生活中,我在不同的迭代中也可能有不同数量的排序列。

关于建议使用“地图”功能的解决方案:我加载了一些地理空间包(mapproj、50stater、geofacet),因此除非我卸载这些包,否则“地图”功能无法按建议工作。是否有资格使用本机“地图”功能而不是地理空间地图功能?

感谢您的帮助!

【问题讨论】:

  • 您提供的示例代码不是有效的 R 代码。例如sorting &lt;-(sort1,sort2) 会抛出一个错误。 for (i = 1:2) 同上。这可能表明通用 R 语法存在更深层次的问题。也许您需要退后一步,先熟悉 R 的基础知识;你可以在网上找到很多免费的材料。一个好的起点可能是An introduction to R
  • 谢谢。我更正了帖子中的语法。
  • 谢谢。也更正了。这是 5000 行代码的简化版本。抱歉打错了。
  • “是否有资格使用原生“地图”功能而不是地理空间地图功能?”只需在前缀purrr::map

标签: r sorting dataframe vector


【解决方案1】:
The following solution works for me! Other proposed solutions I tried failed to sort by two variables in a given vector simultaneously.

DT <-data.frame(avar = c(1,4,3,1), bvar = c("a","f","s","b"), cvar = c(3,4,5,2))

sort1 <-c("avar", "cvar")
sort2 <-c("avar", "bvar")
sorting <-list(sort1,sort2)
DT2<-list()

for (i in 1:2) {
    #THE FOLLOWING SOLUTION WORKS!!!
    DT2[[i]] <- DT[do.call(order,DT[as.character(sorting[[i]])]),]       
}

【讨论】:

    【解决方案2】:

    这是setorder 来自data.table 的方法

    library(data.table)
    Map(setorderv, replicate(2, copy(DT), simplify = FALSE), sorting)
    #[[1]]
    #  avar bvar cvar
    #4    1    b    2
    #1    1    a    3
    #3    3    s    5
    #2    4    f    4
    
    #[[2]]
    #  avar bvar cvar
    #1    1    a    3
    #4    1    b    2
    #3    3    s    5
    #2    4    f    4
    

    或使用dplyr中的arrange_at(不使用求值方式)

    library(tidyverse)
    map(sorting, ~ DT %>%
                     arrange_at(.x))
    #[[1]]
    #  avar bvar cvar
    #1    1    b    2
    #2    1    a    3
    #3    3    s    5
    #4    4    f    4
    
    #[[2]]
    #  avar bvar cvar
    #1    1    a    3
    #2    1    b    2
    #3    3    s    5
    #4    4    f    4
    

    【讨论】:

    • 您好,谢谢。我有两个与此解决方案相关的问题:
    • 您好,谢谢。我有两个与此解决方案相关的问题:(1)我还加载了一些地理空间包(fifitystater、geofacet、mapproj)。所以看起来这些包中的“map”函数“取代”了本机 R map 函数。除非我卸载那些地理特殊包,否则我会在“地图”语句中收到错误消息。有没有办法使用原生地图功能而不是地理空间工具中的功能。
    • 问题(2)与这个问题更直接相关。当我说按 c("avar", "bvar") 排序时,我不想要两个单独的输出。我希望文件首先按 avar 排序,然后(如果有两个或多个相同的 avar 值)由 bvar 排序。目前,使用这个提议的解决方案,我得到一个列表的输出:第一项是按 a 排序的数据。第二项是按b排序的数据。
    • @Edith 使用purrr::map(sorting, ~ DT %&gt;% 解决问题
    【解决方案3】:

    dplyr+purrr 解决方案

    library(purrr)
    library(dplyr)
    map(sorting, ~arrange(DT, !!!syms(.x)))
    #[[1]]
    #  avar bvar cvar
    #1    1    b    2
    #2    1    a    3
    #3    3    s    5
    #4    4    f    4
    #
    #[[2]]
    #  avar bvar cvar
    #1    1    a    3
    #2    1    b    2
    #3    3    s    5
    #4    4    f    4
    

    【讨论】:

    • 谢谢。我编辑了我原来的帖子(添加最后三段),说明为什么提出的解决方案不起作用。
    • @Edit 使用purrr::map 而不是map
    【解决方案4】:

    使用基础 R,我们可以使用 do.callorder 应用于 sorting 中的选定列。我们使用lapply 来获取数据框列表

    lapply(sorting, function(x) DT[do.call(order, DT[x]), ])
    
    
    #[[1]]
    #  avar bvar cvar
    #4    1    b    2
    #1    1    a    3
    #3    3    s    5
    #2    4    f    4
    
    #[[2]]
    #  avar bvar cvar
    #1    1    a    3
    #4    1    b    2
    #3    3    s    5
    #2    4    f    4
    

    【讨论】:

    • 谢谢。我编辑了我原来的帖子(添加最后三段),说明为什么提出的解决方案不起作用。
    • @Edith 我没有在我的答案中使用任何map 函数,但对于其余的函数,您可以使用packageName::functionName 明确使用这些包。例如,purrr::map
    • 当我使用您的解决方案时( lapply(sorting[[1]], function(x) DT[do.call(order, DT[x]), ]),我得到的输出是一个列表:第一项是按 avar 排序的数据,第二项是按 cvar 排序的数据。我编辑的帖子中的第二段解释了我想要发生的事情。
    • @Edith 我得到了与您的帖子中显示的相同的预期输出。 DT2 &lt;- lapply(sorting, function(x) DT[do.call(order, DT[x]), ])DT2[[1]]DT[[2]] 是两个数据帧,如图所示。
    • 当我使用我们的解决方案时,DT2[[1]] 是两个项目的列表——日期分别按 avar 和 cvar 排序。我将编辑代码以准确显示我是如何添加该行的。
    猜你喜欢
    • 2011-11-12
    • 2010-11-20
    • 2018-06-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多