【问题标题】:R - Find first non zero elements per groups in data.tableR - 在 data.table 中查找每个组的第一个非零元素
【发布时间】:2021-04-27 20:11:26
【问题描述】:

我在 R 中有一个如下所示的数据表:

    State  City Maturing  Soil 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
 1:    PR CityA    Early SANDY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 40 40 40 40 40 40
 2:    PR CityA    Early  SILT 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 30 20 20 20 20 20 20
 3:    PR CityA    Early  CLAY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 40 40 40 30 30 20 20 20 20 20 20
 4:    PR CityA   Medium SANDY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 40 40 40 40 40 40 40
 5:    PR CityA   Medium  SILT 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 40 30 20 20 20 20 20 20 30
 6:    PR CityA   Medium  CLAY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 40 40 30 30 20 20 20 20 20 20 20
 7:    PR CityA     Late SANDY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 40 30 30 30 30 40 40  0
 8:    PR CityA     Late  SILT 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 40 40 30 30 20 20 20 20 20 30 30
 9:    PR CityA     Late  CLAY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 30 30 20 20 20 20 20 20 20 20 20
10:    PR CityB    Early SANDY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 40 30 30 30 30 30 30
11:    PR CityB    Early  SILT 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 40 40 30 30 20 20 20 20 20 20 20
12:    PR CityB    Early  CLAY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 30 30 20 20 20 20 20 20 20 20 20
13:    PR CityB   Medium SANDY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 40 40 30 30 30 20 20 30 30 30
14:    PR CityB   Medium  SILT 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 30 30 30 20 20 20 20 20 20 20 20
15:    PR CityB   Medium  CLAY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 30 20 20 20 20 20 20 20 20 20 20
16:    PR CityB     Late SANDY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 40 40 30 30 20 20 20 20 20 30 40
17:    PR CityB     Late  SILT 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 30 20 20 20 20 20 20 20 20 20 20
18:    PR CityB     Late  CLAY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 20 20 20 20 20 20 20 20 20 20 20
19:    RS CityC    Early SANDY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 40 40 40 40  0
20:    RS CityC    Early  SILT 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 40 40 30 30 30 30 30 40
21:    RS CityC    Early  CLAY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 40 30 30 30 20 30 20 30 30
22:    RS CityC   Medium SANDY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 40 40 40 40 40  0  0
23:    RS CityC   Medium  SILT 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 30 30 30 30 30 30 30  0
24:    RS CityC   Medium  CLAY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 40 30 30 30 20 20 20 30 40
25:    RS CityC     Late SANDY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 40 40 30 30 30 40  0  0
26:    RS CityC     Late  SILT 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 40 30 30 30 20 30 30 40  0
27:    RS CityC     Late  CLAY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 40 20 20 20 20 20 20 30 40
28:    RS CityD    Early SANDY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 30 30 30 30 30 30 30 30 40
29:    RS CityD    Early  SILT 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 30 20 20 20 20 20 20 20 20 30
30:    RS CityD    Early  CLAY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 20 20 20 20 20 20 20 20 20 20
31:    RS CityD   Medium SANDY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 40 30 30 30 30 20 20 30 30  0
32:    RS CityD   Medium  SILT 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 30 20 20 20 20 20 20 20 20 40
33:    RS CityD   Medium  CLAY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 20 20 20 20 20 20 20 20 20 20
34:    RS CityD     Late SANDY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 40 30 20 20 20 20 20 30 40  0
35:    RS CityD     Late  SILT 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 30 20 20 20 20 20 20 20 30  0
36:    RS CityD     Late  CLAY 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 20 20 20 20 20 20 20 20 20 30
    State  City Maturing  Soil 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36

名为136 的列代表一年中建议种植的十天时间段。我想提取每个StateMaturingSoil 的最早推荐种植日期。换句话说,我想提取前十天的列名,对于上述组来说,这不是 0。

对于上面的例子,预期的结果是:

State  Maturing  Soil   Earliest
PR     Early     SANDY  30
PR     Early     SILT   26
PR     Early     CLAY   26
PR     Medium    SANDY  27
PR     Medium    SILT   26
PR     Medium    CLAY   26
PR     Late      SANDY  26
PR     Late      SILT   26
PR     Late      CLAY   26
RS     Early     SANDY  28
RS     Early     SILT   27
RS     Early     CLAY   27
RS     Medium    SANDY  27
RS     Medium    SILT   27
RS     Medium    CLAY   27
RS     Late      SANDY  27
RS     Late      SILT   27
RS     Late      CLAY   27

我怎样才能做到这一点?

可以使用以下代码复制数据:

library(data.table)

dat <- data.table(structure(list(State = rep(c("PR","RS"), each=18),
City = rep(c("CityA","CityB","CityC","CityD"), each=9),
Maturing = rep(rep(c("Early","Medium","Late"), each=3), 4),
Soil = rep(c("SANDY","SILT","CLAY"), 12), `1` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `2` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `3` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `4` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `5` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `6` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `7` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `8` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `9` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `10` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `11` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `12` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `13` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `14` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `15` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `16` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `17` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `18` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `19` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `20` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `21` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `22` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `23` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `24` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `25` = c(0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `26` = c(0L, 0L, 40L, 0L, 0L, 
40L, 0L, 40L, 30L, 0L, 40L, 30L, 0L, 30L, 30L, 40L, 30L, 20L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), `27` = c(0L, 0L, 
40L, 0L, 0L, 40L, 0L, 40L, 30L, 0L, 40L, 30L, 40L, 30L, 20L, 
40L, 20L, 20L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 30L, 20L, 
40L, 30L, 20L, 40L, 30L, 20L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L), `28` = c(0L, 0L, 40L, 0L, 40L, 30L, 0L, 30L, 20L, 0L, 30L, 
20L, 40L, 30L, 20L, 30L, 20L, 20L, 0L, 0L, 40L, 0L, 0L, 40L, 
0L, 40L, 40L, 30L, 20L, 20L, 30L, 20L, 20L, 30L, 20L, 20L, 20L, 
20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L), `29` = c(0L, 0L, 30L, 
0L, 30L, 30L, 40L, 30L, 20L, 0L, 30L, 20L, 30L, 20L, 20L, 30L, 
20L, 20L, 0L, 40L, 30L, 0L, 30L, 30L, 40L, 30L, 20L, 30L, 20L, 
20L, 30L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 
20L, 20L, 20L), `30` = c(0L, 30L, 30L, 40L, 20L, 20L, 30L, 20L, 
20L, 40L, 20L, 20L, 30L, 20L, 20L, 20L, 20L, 20L, 0L, 40L, 30L, 
40L, 30L, 30L, 40L, 30L, 20L, 30L, 20L, 20L, 30L, 20L, 20L, 20L, 
20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L), `31` = c(40L, 
20L, 20L, 40L, 20L, 20L, 30L, 20L, 20L, 30L, 20L, 20L, 30L, 20L, 
20L, 20L, 20L, 20L, 0L, 30L, 30L, 40L, 30L, 30L, 30L, 30L, 20L, 
30L, 20L, 20L, 30L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 
20L, 20L, 20L, 20L, 20L), `32` = c(40L, 20L, 20L, 40L, 20L, 20L, 
30L, 20L, 20L, 30L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 40L, 
30L, 20L, 40L, 30L, 20L, 30L, 20L, 20L, 30L, 20L, 20L, 20L, 20L, 
20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L
), `33` = c(40L, 20L, 20L, 40L, 20L, 20L, 30L, 20L, 20L, 30L, 
20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 40L, 30L, 30L, 40L, 30L, 
20L, 30L, 30L, 20L, 30L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 
20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L), `34` = c(40L, 20L, 
20L, 40L, 20L, 20L, 40L, 20L, 20L, 30L, 20L, 20L, 30L, 20L, 20L, 
20L, 20L, 20L, 40L, 30L, 20L, 40L, 30L, 20L, 40L, 30L, 20L, 30L, 
20L, 20L, 30L, 20L, 20L, 30L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 
20L, 30L, 20L, 20L), `35` = c(40L, 20L, 20L, 40L, 20L, 20L, 40L, 
30L, 20L, 30L, 20L, 20L, 30L, 20L, 20L, 30L, 20L, 20L, 40L, 30L, 
30L, 0L, 30L, 30L, 0L, 40L, 30L, 30L, 20L, 20L, 30L, 20L, 20L, 
40L, 30L, 20L, 20L, 20L, 20L, 30L, 20L, 20L, 30L, 20L, 20L), 
    `36` = c(40L, 20L, 20L, 40L, 30L, 20L, 0L, 30L, 20L, 30L, 
    20L, 20L, 30L, 20L, 20L, 40L, 20L, 20L, 0L, 40L, 30L, 0L, 
    0L, 40L, 0L, 0L, 40L, 40L, 30L, 20L, 0L, 40L, 20L, 0L, 0L, 
    30L, 30L, 20L, 20L, 40L, 30L, 20L, 0L, 30L, 20L)), row.names = c(NA, 
-45L), class = "data.frame"))

【问题讨论】:

  • 您能解释一下您将如何做出选择吗?我有点不清楚。
  • 抱歉,刚刚重读您的问题,我不太确定您要查找的确切内容
  • 前 10 天期限是什么意思?这是否仅仅意味着第一列的数字非零?
  • @Onyambu,是的,该列的名称。
  • 看我提供的第二个代码

标签: r data.table


【解决方案1】:

你可以这样做:

is.na(dat) <- dat == 0
dat[, cbind(.SD[,1:4], Earliest = dplyr::coalesce(!!!.SD[,-(1:4)]))]

   State  City Maturing  Soil Earliest
 1:    PR CityA    Early SANDY       40
 2:    PR CityA    Early  SILT       30
 3:    PR CityA    Early  CLAY       40
 4:    PR CityA   Medium SANDY       40
 5:    PR CityA   Medium  SILT       40
 6:    PR CityA   Medium  CLAY       40
 7:    PR CityA     Late SANDY       40
 8:    PR CityA     Late  SILT       40
 9:    PR CityA     Late  CLAY       30
10:    PR CityB    Early SANDY       40
11:    PR CityB    Early  SILT       40
12:    PR CityB    Early  CLAY       30

编辑:

如果您需要列号:那么您可以这样做,

dat[, cbind(.SD[,1:4], Earliest = max.col(.SD[,-(1:4)]>0,ties.method = "first"))]
    State  City Maturing  Soil Earliest
 1:    PR CityA    Early SANDY       31
 2:    PR CityA    Early  SILT       30
 3:    PR CityA    Early  CLAY       26
 4:    PR CityA   Medium SANDY       30
 5:    PR CityA   Medium  SILT       28
 6:    PR CityA   Medium  CLAY       26
 7:    PR CityA     Late SANDY       29
 8:    PR CityA     Late  SILT       26
 9:    PR CityA     Late  CLAY       26
10:    PR CityB    Early SANDY       30

【讨论】:

  • 基于数字,op 想要的是列名而不是值,但即使是那些也不符合预期的输出,所以我不知道什么是正确的
  • @rawr 谢谢。我不太确定 OP 到底想要什么。
  • @Onyambu,感谢您的回答。对原始问题进行了编辑以(希望)使其更清晰。
  • @Onyambu,城市不应出现在最终数据表中。代码应采用CityACityB 之间的第一个非零值的列名。
【解决方案2】:

更新

我已修改我的代码以获得您想要的结果,但这不是您首选的data.table 解决方案。我们没有得到的一点是,分组变量的组合并不总是唯一的,因此这基本上不是逐行操作,需要在考虑每个组中最早的日期时进行分组。我的输出的唯一问题是 MaturingSoil 变量的级别顺序与输出中的顺序 obs 不同。可以修。

library(dplyr)
library(tidyr)
library(purrr)

dat %>%
  mutate(Earliest = pmap(dat %>% 
                           select(`1`:`36`), ~ names(c(...))[c(...) != 0][1])) %>%
  select(-c(`1`:`36`)) %>%
  unnest(cols = c(Earliest)) %>% 
  group_by(State, Maturing, Soil) %>% 
  mutate(Earliest = as.numeric(Earliest)) %>%
  summarise(across(Earliest, ~ min(.x))) %>%
  ungroup()


# A tibble: 18 x 4
   State Maturing Soil  Earliest
   <chr> <chr>    <chr>    <dbl>
 1 PR    Early    CLAY        26
 2 PR    Early    SANDY       30
 3 PR    Early    SILT        26
 4 PR    Late     CLAY        26
 5 PR    Late     SANDY       26
 6 PR    Late     SILT        26
 7 PR    Medium   CLAY        26
 8 PR    Medium   SANDY       27
 9 PR    Medium   SILT        26
10 RS    Early    CLAY        27
11 RS    Early    SANDY       28
12 RS    Early    SILT        27
13 RS    Late     CLAY        27
14 RS    Late     SANDY       27
15 RS    Late     SILT        27
16 RS    Medium   CLAY        27
17 RS    Medium   SANDY       27
18 RS    Medium   SILT        27

【讨论】:

  • 感谢您的回答。对原始问题进行了编辑以(希望)使其更清晰。
  • @thiagoveloso 我更新了我的代码,请检查一下。
  • 它有效,谢谢!虽然data.table 方法当然是首选,但您的解决方案也同样有效。最后,真正重要的是结果。
  • @thiagoveloso 你说得对,欢迎您,很高兴它对您有所帮助。但我认为你很快也会有一些data.table 解决方案。可惜我不熟悉。
  • 我认为max.col 是这里最好的策略,而不是通过purrr::pmap,无论是在tidyverse 还是其他地方
【解决方案3】:

受到 Anoushiravan 解决方案的启发(做得很好),我尝试了单独使用 dyplrtidyr 的解决方案,并保持 OP 的所需顺序。

这是我的解决方案(使用 cmets):

library(dplyr)
library(tidyr)

# relevel Soil for same Output as desired
order_Soil <- c("SANDY", "SILT", "CLAY")

dat1 <- dat %>%
  select(where(~ any(. != 0)), -City) %>%           #remove all 0 columns
  pivot_longer(                                     #bring in longformat
    cols = c(`26`:`36`), 
    names_to = "Names",
    values_to = "Values"
  ) %>% 
  mutate(Soil = factor(Soil,                        #to keep the desired order
                       levels = order_Soil)) %>% 
  filter(Values != 0) %>%                           #remove rows with any 0
  group_by(State, Maturing, Soil) %>%
  summarise(Earliest = min(Names))                  #Summarize the Earliest

输出:

   State Maturing Soil  Earliest
   <chr> <chr>    <fct> <chr>   
 1 PR    Early    SANDY 30      
 2 PR    Early    SILT  26      
 3 PR    Early    CLAY  26      
 4 PR    Late     SANDY 26      
 5 PR    Late     SILT  26      
 6 PR    Late     CLAY  26      
 7 PR    Medium   SANDY 27      
 8 PR    Medium   SILT  26      
 9 PR    Medium   CLAY  26      
10 RS    Early    SANDY 28      
11 RS    Early    SILT  27      
12 RS    Early    CLAY  27      
13 RS    Late     SANDY 27      
14 RS    Late     SILT  27      
15 RS    Late     CLAY  27      
16 RS    Medium   SANDY 27      
17 RS    Medium   SILT  27      
18 RS    Medium   CLAY  27 

【讨论】:

    【解决方案4】:

    这是data.table 方法:

    dat_long = melt(
      data = dat, 
      measure.vars = as.character(1:36), # column names to be melted
      variable.name = 'period', 
      variable.factor = FALSE
    )
    
    res = dat_long[
      value > 0,                              # we're looking for non-zero periods
      .(Earliest = min(as.integer(period))),  # extract the minimum (first) period
      by = .(State, Maturing, Soil)           # grouping variables
    ]
    
    res
    #    State Maturing  Soil Earliest
    # 1:    PR    Early  CLAY       26
    # 2:    PR   Medium  CLAY       26
    # 3:    PR     Late  SILT       26
    # 4:    PR     Late  CLAY       26
    # 5:    PR    Early  SILT       26
    # 6:    PR   Medium  SILT       26
    # 7:    PR     Late SANDY       26
    # 8:    PR   Medium SANDY       27
    # 9:    RS    Early  SILT       27
    # 10:    RS    Early  CLAY       27
    # 11:    RS   Medium SANDY       27
    # 12:    RS   Medium  SILT       27
    # 13:    RS   Medium  CLAY       27
    # 14:    RS     Late SANDY       27
    # 15:    RS     Late  SILT       27
    # 16:    RS     Late  CLAY       27
    # 17:    RS    Early SANDY       28
    # 18:    PR    Early SANDY       30
    

    底线:将您的数据转换为长格式,计算变得非常容易(并且很可能在长格式中更有效)。

    【讨论】:

      【解决方案5】:

      解决方案:

      1. 选择每行的第一个非零元素的名称
      2. State, Maturing, Soil分组
      3. 将每个组的min设置为Earliest
      dat[, Earliest := apply(
          .SD[, -(1:4)], 1, function(x) as.numeric(names(which(x != 0)[1]))
          )][,.(Earliest = min(Earliest)),by = .(State, Maturing, Soil)]
      

      输出:

          State Maturing  Soil Earliest
       1:    PR    Early SANDY       30
       2:    PR    Early  SILT       26
       3:    PR    Early  CLAY       26
       4:    PR   Medium SANDY       27
       5:    PR   Medium  SILT       26
       6:    PR   Medium  CLAY       26
       7:    PR     Late SANDY       26
       8:    PR     Late  SILT       26
       9:    PR     Late  CLAY       26
      10:    RS    Early SANDY       28
      11:    RS    Early  SILT       27
      12:    RS    Early  CLAY       27
      13:    RS   Medium SANDY       27
      14:    RS   Medium  SILT       27
      15:    RS   Medium  CLAY       27
      16:    RS     Late SANDY       27
      17:    RS     Late  SILT       27
      18:    RS     Late  CLAY       27
      

      【讨论】:

        【解决方案6】:

        虽然上述许多方法都非常好,但我发现这可以通过使用max.col 轻松完成。这是一个只使用dplyr 的例子

        library(dplyr)
        dat %>%
          mutate(Earliest = max.col(.[, -c(1:4)] > 0, ties.method = "first")) %>%
          group_by(State, Maturing, Soil) %>%
          summarise(Earliest = min(Earliest), .groups = 'drop')
        
        # A tibble: 18 x 4
           State Maturing Soil  Earliest
           <chr> <chr>    <chr>    <int>
         1 PR    Early    CLAY        26
         2 PR    Early    SANDY       30
         3 PR    Early    SILT        26
         4 PR    Late     CLAY        26
         5 PR    Late     SANDY       26
         6 PR    Late     SILT        26
         7 PR    Medium   CLAY        26
         8 PR    Medium   SANDY       27
         9 PR    Medium   SILT        26
        10 RS    Early    CLAY        27
        11 RS    Early    SANDY       28
        12 RS    Early    SILT        27
        13 RS    Late     CLAY        27
        14 RS    Late     SANDY       27
        15 RS    Late     SILT        27
        16 RS    Medium   CLAY        27
        17 RS    Medium   SANDY       27
        18 RS    Medium   SILT        27
        

        此外,如果值和索引都需要,也可以仅在 dplyr 中完成,语法如下

        dat %>%
          mutate(Earliest = names(.[, -(1:4)])[max.col(.[, -c(1:4)] > 0, ties.method = "first")]) %>%
          rowwise() %>%
          mutate(E_val = get(Earliest)) %>%
          group_by(State, Maturing, Soil) %>%
          summarise(E_val = first(E_val[Earliest == min(Earliest)]), 
                    Earliest = min(Earliest), 
                    .groups = 'drop')
        
        # A tibble: 18 x 5
           State Maturing Soil  E_val Earliest
           <chr> <chr>    <chr> <int> <chr>   
         1 PR    Early    CLAY     40 26      
         2 PR    Early    SANDY    40 30      
         3 PR    Early    SILT     40 26      
         4 PR    Late     CLAY     30 26      
         5 PR    Late     SANDY    40 26      
         6 PR    Late     SILT     40 26      
         7 PR    Medium   CLAY     40 26      
         8 PR    Medium   SANDY    40 27      
         9 PR    Medium   SILT     30 26      
        10 RS    Early    CLAY     20 27      
        11 RS    Early    SANDY    30 28      
        12 RS    Early    SILT     30 27      
        13 RS    Late     CLAY     20 27      
        14 RS    Late     SANDY    40 27      
        15 RS    Late     SILT     30 27      
        16 RS    Medium   CLAY     20 27      
        17 RS    Medium   SANDY    40 27      
        18 RS    Medium   SILT     30 27
        

        【讨论】:

          猜你喜欢
          • 2018-12-06
          • 1970-01-01
          • 1970-01-01
          • 2023-03-08
          • 2013-12-13
          • 1970-01-01
          • 2021-09-13
          • 2021-06-03
          • 1970-01-01
          相关资源
          最近更新 更多