【问题标题】:R: Ordering data in a cell of data frameR:在数据框的单元格中排序数据
【发布时间】:2019-02-15 06:01:36
【问题描述】:

我有多个列的巨大数据框,其中一列包含这样的数据

       No  

   "48.8.1.1." 
   "48.8.1.2."
   "48.8.2." 
   "48.9." 
   "48.10." 
   "48.11." 
   "48.11.1." 
   "48.11.1.1." 
   "48.11.1.2." 
   "48.11.1.2.2.2.2.1."      

数据的子排序没有固定的顺序。

问题:

而不是

   "48.11.1.2.1."  

某些值的顺序不正确,例如:

   "48.11.1.2.2.2.2.1"   

没有 2 是额外的。 如何去除多余的 2。

我确实尝试了一些方法,例如重置索引等,但没有奏效。 需要一些建议。

【问题讨论】:

  • 您提供了问题,但提供了不存在问题的数据。请编辑您的问题,使其更易于理解。
  • @NelsonGon:嘿,我已经编辑了这个问题。
  • 请包括您到目前为止所做的尝试
  • 我看到您提供了输入数据的样本。还请添加 (1) 您想要的结果,以及 (2) 您迄今为止尝试将输入转换为结果的代码。
  • 那为什么48.11.1.148.8.1.1.不是垃圾?

标签: r regex dataframe


【解决方案1】:

试试:

编辑::

df$No<-stringr::str_remove_all(df$No,"2.{1,}(?=2.{3,})")

结果:

             No
1     48.8.1.1.
2     48.8.1.2.
3       48.8.2.
4         48.9.
5        48.10.
6        48.11.
7      48.11.1.
8    48.11.1.1.
9    48.11.1.2.
10 48.11.1.2.1.

原创::

df$No<-substring(df$No,1,9)

这假设最长的字符串是 9 个字符。其他所有内容都被删除。 结果:

df

              No
    1  48.8.1.1.
    2  48.8.1.2.
    3    48.8.2.
    4      48.9.
    5     48.10.
    6     48.11.
    7   48.11.1.
    8  48.11.1.1
    9  48.11.1.2
    10 48.11.1.2

数据:

df<-read.table(text='No  

               "48.8.1.1." 
               "48.8.1.2."
               "48.8.2." 
               "48.9." 
               "48.10." 
               "48.11." 
               "48.11.1." 
               "48.11.1.1." 
               "48.11.1.2." 
               "48.11.1.2.2.2.2.1." ',header=T,stringsAsFactors=F)

【讨论】:

  • 只有当字符串是 9 个字符但我的字符串没有固定长度时才会起作用。
  • 尝试编辑。也更好地准确表示您的数据的样子。使用dput添加示例数据。
【解决方案2】:

假设字符串序列表示大纲中的部分编号,这是一个可能的解决方案:

library(data.table)
# reshape to long format
long <- DT[, rn := .I][
  , strsplit(No, "[.]"), by = rn][
    , V1 := as.integer(V1)][
      , lvl := rowid(rn)][]

# find contiguous streaks of rows where there is a gap in levels
nlvl <- long[, .N, keyby = rn][
  , gap := cumsum(c(diff(N), 0L) > 1L)][
    , M := first(N) + 1L, by = gap]

# non-equi anti-join and recast
long[!nlvl[N > M], on = .(rn, lvl >= M, lvl < N)][
  , .(No = paste(V1, collapse = ".")), by = rn]
    rn          No
 1:  1    48.8.1.1
 2:  2    48.8.1.2
 3:  3      48.8.2
 4:  4        48.9
 5:  5       48.10
 6:  6       48.11
 7:  7     48.11.1
 8:  8   48.11.1.1
 9:  9   48.11.1.2
10: 10 48.11.1.2.1
11: 11 48.11.1.2.2
12: 12 48.11.1.2.3
13: 13     48.11.2
14: 14   48.11.2.1
15: 15 48.11.2.1.1
16: 16     48.11.3
17: 17   48.11.3.1
18: 18          50

说明

如果我理解正确的话,字符串序列表示大纲中的部分编号,这些部分已通过插入虚假的附加级别而被扭曲。 OP 正在寻找一种方法来删除这些额外的级别。

所以,让我们假设一些规则来对大纲的各个部分进行编号:

  1. 节号间隙:在同一级别上,节号始终提前 1。
    例如,遵循4.1.3 部分
    • 4.1.4 (第 3 部分提前)
    • 4.2(如果父级高级)
    • 5(前进到下一章)。
  2. 级别差距:子级别始终比父级别低 1 级。子级的节编号从 1 开始。
    例如,4.1.3 部分后面可以跟 4.1.3.1 作为子部分,但 不是 4.1.3.1.1 从第 3 级跳转到第 5 级子子节。

由于 OP 问题可能与情况 2 相关,我们需要用 相对于前几行的水平差距。作为修复,所有中间盈余水平将被删除。最后一层被保留,因为它的编号可能是正确的。

第一步包括添加行号,在"." 处拆分字符串,将节号强制为整数,并对每行的级别进行编号。现在,节号是长格式:

 long
    rn V1 lvl
 1:  1 48   1
 2:  1  8   2
 3:  1  1   3
 4:  1  1   4
 5:  2 48   1
 6:  2  8   2
[...]
25:  9 48   1
26:  9 11   2
27:  9  1   3
28:  9  2   4
29: 10 48   1
30: 10 11   2
31: 10  1   3
32: 10  2   4
33: 10  2   5
34: 10  2   6
35: 10  2   7
36: 10  1   8
37: 11 48   1
38: 11 11   2
39: 11  1   3
40: 11  2   4
41: 11  2   5
42: 11  2   6
43: 11  2   7
44: 11  2   8
45: 12 48   1
46: 12 11   2
47: 12  1   3
48: 12  2   4
49: 12  2   5
50: 12  3   6
51: 13 48   1
52: 13 11   2
53: 13  2   3
54: 14 48   1
55: 14 11   2
56: 14  2   3
57: 14  1   4
58: 15 48   1
59: 15 11   2
60: 15  2   3
61: 15  1   4
62: 15  1   5
63: 16 48   1
64: 16 11   2
65: 16  3   3
66: 17 48   1
67: 17 11   2
68: 17  3   3
69: 17  3   4
70: 17  3   5
71: 17  1   6
72: 18 50   1
    rn V1 lvl

在下一步中,将识别出现在节级别的间隙之后的连续行条纹。节级别是属于一行的元素的数量Ngap 标记在节级别非法跳转之后的所有行。 M 表示根据上述规则 2 合法的最大部分级别。

nlvl
    rn N gap M
 1:  1 4   0 5
 2:  2 4   0 5
 3:  3 3   0 5
 4:  4 2   0 5
 5:  5 2   0 5
 6:  6 2   0 5
 7:  7 3   0 5
 8:  8 4   0 5
 9:  9 4   1 5
10: 10 8   1 5
11: 11 8   1 5
12: 12 6   1 5
13: 13 3   1 5
14: 14 4   1 5
15: 15 5   1 5
16: 16 3   2 4
17: 17 6   2 4
18: 18 1   2 4

在最后一步中,通过非等值反连接long 中消除额外的虚假级别。然后,通过将各个部分粘贴在一起来重新创建部分编号。

为了比较,我们可以将结果与原始数据连接起来:

long[!nlvl[N > M], on = .(rn, lvl >= M, lvl < N)][
  , .(No = paste(V1, collapse = ".")), by = rn][DT, on = "rn"]
    rn          No               i.No
 1:  1    48.8.1.1          48.8.1.1.
 2:  2    48.8.1.2          48.8.1.2.
 3:  3      48.8.2            48.8.2.
 4:  4        48.9              48.9.
 5:  5       48.10             48.10.
 6:  6       48.11             48.11.
 7:  7     48.11.1           48.11.1.
 8:  8   48.11.1.1         48.11.1.1.
 9:  9   48.11.1.2         48.11.1.2.
10: 10 48.11.1.2.1 48.11.1.2.2.2.2.1.
11: 11 48.11.1.2.2 48.11.1.2.2.2.2.2.
12: 12 48.11.1.2.3     48.11.1.2.2.3.
13: 13     48.11.2           48.11.2.
14: 14   48.11.2.1         48.11.2.1.
15: 15 48.11.2.1.1       48.11.2.1.1.
16: 16     48.11.3           48.11.3.
17: 17   48.11.3.1     48.11.3.3.3.1.
18: 18          50                50.

数据

OP 发布的数据的扩展版本。

library(data.table)
DT <- data.table(No = c(
  "48.8.1.1.", 
  "48.8.1.2.",
  "48.8.2." ,
  "48.9." ,
  "48.10." ,
  "48.11." ,
  "48.11.1." ,
  "48.11.1.1." ,
  "48.11.1.2." ,
  "48.11.1.2.2.2.2.1.",
  "48.11.1.2.2.2.2.2.",
  "48.11.1.2.2.3.",
  "48.11.2.",
  "48.11.2.1.",
  "48.11.2.1.1.",
  "48.11.3.",
  "48.11.3.3.3.1.",
  "50."
))

【讨论】:

  • 优秀。在我注意到您的中间 cmet 和您的问题的编辑后,我担心测试用例的数量太少而无法彻底测试相当复杂的逻辑。
  • 是的,我对代码做了一些更改,现在可以正常工作了。
  • 你在代码中做了什么改变?请告诉我如何改进我的答案 - 谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-18
  • 2018-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多