【问题标题】:Label every nth element by group in data.table在 data.table 中按组标记每个第 n 个元素
【发布时间】:2021-09-13 20:12:02
【问题描述】:

我的数据包含一组对不同组的观察。每组有不同数量的观察值。我想创建一个变量,用“1”标记观察结果,以进行进一步的手动 QA/QC。标志应该在一个组内有规律地间隔,但两个组之间的间隔可能不同。间距是通过将每个组的长度除以一个常数(本例中为 5)得出的。

数据看起来像这样:

dt<-data.table(places=c(rep("A",10), rep("B",20))) #the data
dt2<-data.table(places=c("A","B"), spacing=c(2,4)) #the spacings by group to apply to the data

然后应用一些代码来生成标记(或序列)

dt$sequence<- ????

看起来像:

places  sequence
A       1
A   
A       1
A   
...
B       1
B   
B   
B   

基本上,我希望根据已为该组确定的理想间距让每个组“计数”,并且每次计数循环时只保留“1”。我只是不确定如何为 data.table 提供间距和组组合。

【问题讨论】:

  • dplyr 很简单,但我很好奇您用于确定间距的精确规则。如果列的长度不能被相应的spacing 整除,您是要向下舍入到最接近的整数,还是向上舍入到最接近的整数...或其他什么东西?您能否提供一个函数f &lt;- function(col_length, spacing_divisor){...} 来精确定义您的意图?
  • 当然,f&lt;-function(col_length){floor(col_length/5} dplyr 解决方案会很有趣,但我对 data.table 解决方案真的很感兴趣。
  • 谢谢!马上就有答案了!
  • 我应该指出,您的示例输出显示1 每 2 行出现一次 "A",而不是在开始和中途出现一次......这就是 f将提供2 并要求将组分成 2 个相等的部分。
  • 嗯,我没有看到这个问题。我在想象我的功能被小组应用。我意识到我的解决方案比我做的要容易。见下文。

标签: r data.table


【解决方案1】:

这是另一种选择:

dt[, sq := dt2[.SD, on=.(places), +((rowid(i.places)-1) %% spacing == 0L)]]

输出:

    places sq
 1:      A  1
 2:      A  0
 3:      A  1
 4:      A  0
 5:      A  1
 6:      A  0
 7:      A  1
 8:      A  0
 9:      A  1
10:      A  0
11:      B  1
12:      B  0
13:      B  0
14:      B  0
15:      B  1
16:      B  0
17:      B  0
18:      B  0
19:      B  1
20:      B  0
21:      B  0
22:      B  0
23:      B  1
24:      B  0
25:      B  0
26:      B  0
27:      B  1
28:      B  0
29:      B  0
30:      B  0

您可以使用连接 dt2[.SD, on=.(places) 为 data.table 提供间距和组组合,然后使用 rowid 生成一个序列,然后进行模运算以找到 seq 整数可被间距。

【讨论】:

  • 感谢您将我的方法翻译成data.table!我想知道那会是什么样子。我现在对dplyr 的投资相当不错,但迟早有人必须屈服于data.table 的原始力量。 :D
【解决方案2】:

我到达了 data.table 解决方案:

dtest[, sequence := rep(seq_len(floor(.N/5)),length.out=.N), by = places]
dtest[sequence!=1,sequence:=NA]

...之前从未使用过length.out ....

【讨论】:

  • 不错!但这不只是为每个组使用相同的spacing(此处为5)吗? spacing = c(2, 4)dt2 中给出的各个组的间距呢?
  • 我现在忽略 dt2,因为我意识到它是不必要的。包裹到sequence 的定义中会更容易。它对每组使用相同数量的 1 (5),但间距不同。 .N 是组长度的 DT 简写。 A 的长度为 10,B 的长度为 20,因此计算出的间距变为 2 和 4。
  • 所以为了清楚起见,您没有使用每个组的“自定义”间距,如单独的dt2 中提供的那样?例如,您无法使用相同的除数将间距计算为 2 和 13。
  • 我明白你在说什么。如果我不喜欢计算出的间距,我可以通过 dt2 提供自定义间距。这可能会有所帮助。这个版本我不需要它,但是当协议偏差发生(并且确实发生)时,它可能会有所帮助。
  • 发布它们,很想看看这些解决方案。谢谢@Greg
【解决方案3】:

根据我们的conversation,这里是dplyr 解决方案,每个都以

library(data.table)
library(dplyr)


dt <- data.table(places=c(rep("A",10), rep("B",20))) #the data

对于讨论的两种方法:

  1. 万能除数(此处为5):
    # The divisor to be applied universally across all groups.
    universal_divisor <- 5
    
    # The vectorized function you specified.
    f <- function(group_length, divisor){
      return(floor(group_length / divisor))
    }
    
    dt_universal <- dt %>%
      # Group in order to index each row WITHIN its group.
      group_by(places) %>%
      # Mark a 1 at each point calculated by the given function 'f' from the group
      # group size, against the universal divisor; otherwise make blank (NA).
      mutate(sequence = if_else(row_number() %% f(n(), universal_divisor) == 0,
                                   1, as.numeric(NA))) %>%
      ungroup() %>% as.data.table()

  1. 自定义间距:
    # Your spacings by group to apply to the data.
    dt2 <- data.table(places=c("A","B"), spacing=c(2,4))
    
    dt_custom <- dt %>%
      # Match each row to the custom spacing value for its 'place'.
      left_join(dt2, by = "places") %>%
      # Group in order to index each row WITHIN its group.
      group_by(places) %>%
      # Mark with a 1 at the desired spacing; otherwise make blank (NA).
      transmute(places,
                sequence = if_else(row_number() %% spacing == 0,
                                   1, as.numeric(NA))) %>%
      ungroup() %>% as.data.table()

每种方法都会在下面输出data.table。虽然使用data.table 可以更有效地完成其中一些操作,但我个人认为dplyr 工作流程非常透明和灵活。

    places sequence
 1:      A       NA
 2:      A        1
 3:      A       NA
 4:      A        1
 5:      A       NA
 6:      A        1
 7:      A       NA
 8:      A        1
 9:      A       NA
10:      A        1
11:      B       NA
12:      B       NA
13:      B       NA
14:      B        1
15:      B       NA
16:      B       NA
17:      B       NA
18:      B        1
19:      B       NA
20:      B       NA
21:      B       NA
22:      B        1
23:      B       NA
24:      B       NA
25:      B       NA
26:      B        1
27:      B       NA
28:      B       NA
29:      B       NA
30:      B        1
    places sequence

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-05
    • 2021-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-21
    • 1970-01-01
    相关资源
    最近更新 更多