【问题标题】:Sort a data table with specific value order对具有特定值顺序的数据表进行排序
【发布时间】:2016-08-10 17:31:20
【问题描述】:

这是一个简短的data.table:

DT <- data.table(Tag1 = c(22,253,6219,6219,252862,252864,312786,312812),
                 Tag2 = c(22,255,6220,252857,252863,252865,251191,252863),
                 Date= as.Date(as.character(c("7/25/2008","6/15/2000","6/30/2000","9/6/2002","9/6/2002","9/6/2002","9/3/2003","9/5/2003")),format = "%m/%d/%Y"))
DT

     Tag1   Tag2       Date
1:     22     22 2008-07-25
2:    253    255 2000-06-15
3:   6219   6220 2000-06-30
4:   6219 252857 2002-09-06
5: 252862 252863 2002-09-06
6: 252864 252865 2002-09-06
7: 312786 251191 2003-09-03
8: 312812 252863 2003-09-05

我想按 3 列升序对 data.table 进行排序:Tag1、Tag2 和 Date。 我测试过:

> test <- DT[order(Tag1, Tag2, Date)]
> test
     Tag1   Tag2       Date
1:     22     22 2008-07-25
2:    253    255 2000-06-15
3:   6219   6220 2000-06-30
4:   6219 252857 2002-09-06
5: 252862 252863 2002-09-06
6: 252864 252865 2002-09-06
7: 312786 251191 2003-09-03
8: 312812 252863 2003-09-05

但是,我想按如下方式对 data.table 进行排序:

> test
         Tag1   Tag2       Date
    1:     22     22 2008-07-25
    2:    253    255 2000-06-15
    3:   6219   6220 2000-06-30
    4:   6219 252857 2002-09-06
    5: 252862 252863 2002-09-06
    6: 312812 252863 2003-09-05
    7: 252864 252865 2002-09-06
    8: 312786 251191 2003-09-03

特别是,Tag1 或 Tag1 的重复值应该一个在另一个之下(例如:Tag1 为 6219,Tag2 为 252863)。 我该怎么做?

编辑

建议的解决方案适用于较短的 data.table(如上面的 data.table)。 这是一个更长的版本:

DT <- data.table(Tag1 = c(252860, 252862, 312812, 252864, 252866, 252868, 252870, 318880, 252872, 252874, 252876, 252878, 252880, 252880, 252881, 252883,
252885, 252887, 311264, 252889, 252889, 252892, 318879, 318880, 318881), Tag2 = c(252861, 252863, 252863, 252865, 252867, 252869, 252871, 252871, 252873,
252875, 252877, 252879, 414611, 905593, 252882, 252884, 252886, 252888, 252888, 252890, 318904, 252893, 318878, 414547, 318882), Date = c("9/6/2002",
"9/6/2002", "9/5/2003", "9/6/2002", "9/6/2002", "9/6/2002", "9/6/2002", "10/8/2003", "9/6/2002", "9/6/2002", "9/6/2002", "9/6/2002", "10/5/2004",
"9/6/2002", "9/6/2002", "9/6/2002", "9/10/2002", "9/10/2002", "7/15/2003", "9/10/2002", "10/15/2003", "9/10/2002", "10/8/2003", "9/29/2004","10/8/2003"))

这是预期的结果(即 data.table “After”)。特别是,data.table "After" 应该遵守两个条件:

1) 行按日期升序排序

2) Tag1 或 Tag1 的重复值一个在另一个之下(最终不需要按升序排列)

Tag1 和 Tag2 的所有重复值都是黄色的。

【问题讨论】:

  • 那么你可能需要破解order。即DT[, lapply(DT, sort)]
  • @Sathish 那是评论而不是答案。这就是我没有发布它的原因。
  • 你使用什么样的数据需要这种分组/排序?
  • 这些是带有动物耳标编号的捕获数据。
  • 我不知道这个命令背后的逻辑是什么。在您想要的输出中,没有一列是有序的,而是您从一种无序状态转移到了另一种状态。

标签: r data.table


【解决方案1】:

旧秩序

df[order(Tag1, Tag2, Date)]
#      Tag1   Tag2       Date
# 1:     22     22 2008-07-25
# 2:    253    255 2000-06-15
# 3:   6219   6220 2000-06-30
# 4:   6219 252857 2002-09-06
# 5: 252862 252863 2002-09-06
# 6: 252864 252865 2002-09-06
# 7: 312786 251191 2003-09-03
# 8: 312812 252863 2003-09-05

新秩序
Date 列按降序排序,然后按Tag2 分组的升序对Tag1 进行排序。

setcolorder(dt1 <- df[order(-Date)][order(Tag1), .SD, by = Tag2], colnames(df))

dt1
#      Tag1   Tag2       Date
# 1:     22     22 2008-07-25
# 2:    253    255 2000-06-15
# 3:   6219 252857 2002-09-06
# 4:   6219   6220 2000-06-30
# 5: 252862 252863 2002-09-06
# 6: 312812 252863 2003-09-05
# 7: 252864 252865 2002-09-06
# 8: 312786 251191 2003-09-03

cmets 中@akrun 的解决方案扰乱了数据的结构。这是比较。看#4:6219 应该有 252857 而不是 251191

df[,lapply(df, sort)]
#      Tag1   Tag2       Date
# 1:     22     22 2000-06-15
# 2:    253    255 2000-06-30
# 3:   6219   6220 2002-09-06
# 4:   6219 251191 2002-09-06
# 5: 252862 252857 2002-09-06
# 6: 252864 252863 2003-09-03
# 7: 312786 252863 2003-09-05
# 8: 312812 252865 2008-07-25

【讨论】:

  • 是否可以使用函数setcolorder保留所有data.table列,而不仅仅是“Tag1”、“Tag2”和“Date”三列?例如,我有一个data.table与三列“Tag1”、“Tag2”和“Date”等列。
  • 为什么将第 4 行的日期(在 data.table 旧顺序中)替换为第 3 行的日期(即 2002-09-06 而不是2000-06-30 在第 3 行和 2000-06-30 而不是 2002-09-06 在第 4 行?
  • 例如:DT &lt;- data.table(Tag1 = c(22,253,6219,6219,252862,252864,312786,312812), Tag2 = c(22,255,6220,252857,252863,252865,251191,252863), aa = c(1,5,9,6,8,1,1,3), Date= as.Date(as.character(c("7/25/2008","6/15/2000","9/6/2002", "6/30/2000","9/6/2002","9/6/2002","9/3/2003","9/5/2003")),format = "%m/%d/%Y")) setcolorder(test &lt;- DT[order(Tag1, Tag2, Date)][, .SD, by = Tag2], colnames(DT))。在这种情况下,日期没有按顺序排序(新顺序中的第 3 行和第 4 行)
  • 在这种情况下是否可以重新排列日期?
  • 我在我的问题中添加了一个更大的数据表:代码不适用于值 318880 (Tag1)。
【解决方案2】:

示例中的数据已经排序,所以这里是一个未排序的缩短版本来说明如何更改排序顺序。

> library(data.table)
> DT <- data.table(Tag1 = c(22,253,22,22),
                   Tag2 = c(1,255,2,2),
                   Date = as.Date(as.character(c(
                 "1/1/2010","4/4/2000","3/3/2003","2/2/2000")), format = "%m/%d/%Y"))
> DT                 

   Tag1 Tag2       Date
1:   22    1 2010-01-01
2:  253  255 2000-04-04
3:   22    2 2003-03-03
4:   22    2 2000-02-02

使用order 以特定的排序顺序创建一个新的data.table。 Order 函数采用单个字段或多个字段按指定顺序排序。

# sorts first by Tag1 then by Tag2 and finally by Date (in ascending order)
> DT2 <- DT[order(Tag1, Tag2, Date)]
> DT2

   Tag1 Tag2       Date
1:   22    1 2010-01-01
2:   22    2 2000-02-02
3:   22    2 2003-03-03
4:  253  255 2000-04-04

要对 data.table 重新排序,请使用 setorder 函数。

setorder(DT, Tag1, Tag2, 日期)

如果要按降序排序,请在字段名称上使用- 前缀。

 > DT[order(Tag1, Tag2, -Date)]
 > setorder(DT, Tag1, Tag2, -Date)

【讨论】:

  • 非常感谢 JasonM1 的回答。我的原始数据表与我的示例类似,即按排序顺序。
【解决方案3】:

在对问题的更新中,OP 表示先前的答案(包括已接受的答案)不适用于更长的数据集。使用问题编辑后的新数据,我们可以这样排序:

诀窍是从按日期排序的表格开始,然后按标签升序排列(OP 中的初始数据已经处于此状态,但一般而言,我开始确保数据按setkey(DT, asDate, Tag1, Tag2) 排序)。然后按照它们出现的顺序对 tag2 的不同值进行编号,并按这些组编号(接下来的两行)排序。这将确保 tag2 的相同值彼此跟随,而不会干扰表格的顺序。接下来,对 tag1 做同样的事情。

DT[, asDate := as.Date(Date, format = "%m/%d/%Y")]
setkey(DT, asDate, Tag1, Tag2)

DT[, g2 := .GRP, Tag2]
setkey(DT, g2)
DT[, g1 := .GRP, Tag1]
setkey(DT, g1)

DT[, c("g1", "g2", "asDate") := NULL][]

      Tag1   Tag2       Date
 1: 252860 252861   9/6/2002
 2: 252862 252863   9/6/2002
 3: 312812 252863   9/5/2003
 4: 252864 252865   9/6/2002
 5: 252866 252867   9/6/2002
 6: 252868 252869   9/6/2002
 7: 252870 252871   9/6/2002
 8: 318880 252871  10/8/2003
 9: 318880 414547  9/29/2004
10: 252872 252873   9/6/2002
11: 252874 252875   9/6/2002
12: 252876 252877   9/6/2002
13: 252878 252879   9/6/2002
14: 252880 905593   9/6/2002
15: 252880 414611  10/5/2004
16: 252881 252882   9/6/2002
17: 252883 252884   9/6/2002
18: 252885 252886  9/10/2002
19: 252887 252888  9/10/2002
20: 311264 252888  7/15/2003
21: 252889 252890  9/10/2002
22: 252889 318904 10/15/2003
23: 252892 252893  9/10/2002
24: 318879 318878  10/8/2003
25: 318881 318882  10/8/2003
      Tag1   Tag2       Date

注意事项

这对样本数据非常有效。但是,请注意。甚至不能保证所有可能的数据都存在解决方案(通过此方法或通过任何方法),特别是如果重复标签占所有标签的很大一部分时。例如,考虑以下列,其中不可能对行进行排序,以使相同的字母总是同时连续出现在两列中:

 a b
 a c
 b a
 b c
 c a
 c b

【讨论】:

  • @Nell 我几天前添加了这个答案——据我所知,它准确地回答了你的问题。此答案是否对您不起作用,或者是否解决了您的问题?
猜你喜欢
  • 2012-08-12
  • 1970-01-01
  • 2019-05-14
  • 2021-09-23
  • 1970-01-01
  • 2014-01-01
  • 2020-06-18
  • 1970-01-01
相关资源
最近更新 更多