【问题标题】:Numbering rows within groups in a data frame but without considering the NAs对数据框中组内的行进行编号,但不考虑 NA
【发布时间】:2020-09-16 06:21:34
【问题描述】:

在 stackoverflow 中有几篇文章询问如何标记列之间的特定级别组合。但是,我找不到如何做到这一点,但没有考虑NAs。举个例子:

df <- read.table(header=TRUE, text="
   cat        val  
1  aaa 0.05638315  
2  aaa 0.25767250  
3  aaa NA  
4  aaa 0.46854928  
5  aaa 0.55232243  
6  bbb NA  
7  bbb 0.37032054  
8  bbb 0.48377074  
9  bbb 0.54655860  
10 bbb 0.81240262  
11 ccc 0.28035384  
12 ccc 0.39848790  
13 ccc 0.62499648  
14 ccc 0.76255108  
15 ccc 0.88216552")

我希望这样:

df
   cat        val id
1  aaa 0.05638315  1
2  aaa 0.25767250  2
3  aaa         NA NA
4  aaa 0.46854928  3
5  aaa 0.55232243  4
6  bbb         NA NA
7  bbb 0.37032054  1
8  bbb 0.48377074  2
9  bbb 0.54655860  3
10 bbb 0.81240262  4
11 ccc 0.28035384  1
12 ccc 0.39848790  2
13 ccc 0.62499648  3
14 ccc 0.76255108  4
15 ccc 0.88216552  5

可能的代码是那些,但是他们不考虑NAs

library(dplyr)
df <- df %>% group_by(cat) %>% mutate(id = row_number())

head(df)
# A tibble: 6 x 3
# Groups:   cat [2]
  cat       val    id
  <fct>   <dbl> <int>
1 aaa    0.0564     1
2 aaa    0.258      2
3 aaa   NA          3
4 aaa    0.469      4
5 aaa    0.552      5
6 bbb   NA          1
library(data.table)
DT <- data.table(df)

DT[, id := seq_len(.N), by = cat]
df <- DT[, id := rowid(cat)]

head(df)
   cat        val id
1: aaa 0.05638315  1
2: aaa 0.25767250  2
3: aaa         NA  3
4: aaa 0.46854928  4
5: aaa 0.55232243  5
6: bbb         NA  1

另外,我想知道如果我想要从第一条记录开始编号该怎么办,然后我们在不考虑NAs 的情况下进行编号。一个例子:

df2 <- read.table(header=TRUE, text="
   cat        val  
1  aaa 0.05638315  
2  aaa 0.25767250  
3  aaa NA  
4  aaa 0.46854928  
5  aaa 0.55232243  
6  bbb NA  
7  bbb 0.37032054  
8  bbb 0.48377074  
9  bbb NA  
10 bbb 0.81240262  
11 ccc 0.28035384  
12 ccc 0.39848790  
13 ccc 0.62499648  
14 ccc 0.76255108  
15 ccc 0.88216552")

我希望:

df2
   cat      val id
1  aaa 0.056383  1
2  aaa 0.257673  2
3  aaa       NA  3
4  aaa 0.468549  4
5  aaa 0.552322  5
6  bbb       NA NA
7  bbb 0.370321  1
8  bbb 0.483771  2
9  bbb       NA  3
10 bbb 0.812403  4
11 ccc 0.280354  1
12 ccc 0.398488  2
13 ccc 0.624996  3
14 ccc 0.762551  4
15 ccc 0.882166  5

我将不胜感激。

【问题讨论】:

  • 你很亲密。试试setDT(df)[!is.na(val), id := seq_len(.N), cat]

标签: r dplyr data.table


【解决方案1】:

您可以调整获得所需输出的建议:

library(dplyr)

df %>%
  group_by(cat) %>%
  mutate(id = replace(row_number() - cumsum(is.na(val)), is.na(val), NA))

#   cat       val    id
#   <chr>   <dbl> <int>
# 1 aaa    0.0564     1
# 2 aaa    0.258      2
# 3 aaa   NA         NA
# 4 aaa    0.469      3
# 5 aaa    0.552      4
# 6 bbb   NA         NA
# 7 bbb    0.370      1
# 8 bbb    0.484      2
# 9 bbb    0.547      3
#10 bbb    0.812      4
#11 ccc    0.280      1
#12 ccc    0.398      2
#13 ccc    0.625      3
#14 ccc    0.763      4
#15 ccc    0.882      5

这个也可以写成data.table

library(data.table)
setDT(df)[, id:= replace(seq_len(.N) - cumsum(is.na(val)), is.na(val), NA), cat]

和基础R:

df$id <- with(df, replace(ave(val, cat, FUN = function(x) 
                  seq_along(x) - cumsum(is.na(x))), is.na(val), NA))

逻辑是创建一个id 变量,该变量是组中的当前行号减去到那时为止发生的NA 的数量。


对于更新的df2,我们可以只在第一行使用NA

df2 %>%
  group_by(cat) %>%
  mutate(id = replace(row_number() - is.na(first(val)),1* is.na(first(val)), NA))

#   cat       val    id
#   <chr>   <dbl> <int>
# 1 aaa    0.0564     1
# 2 aaa    0.258      2
# 3 aaa   NA          3
# 4 aaa    0.469      4
# 5 aaa    0.552      5
# 6 bbb   NA         NA
# 7 bbb    0.370      1
# 8 bbb    0.484      2
# 9 bbb   NA          3
#10 bbb    0.812      4
#11 ccc    0.280      1
#12 ccc    0.398      2
#13 ccc    0.625      3
#14 ccc    0.763      4
#15 ccc    0.882      5

【讨论】:

  • 感谢@Ronak Shah 的时间和勤奋。您的回复非常完整。
【解决方案2】:

您可以使用[.data.table 的第一个参数将:= 分配限制为某些行:

setDT(df)
df[complete.cases(val), id := seq_len(.N), by = .(cat)]

【讨论】:

    猜你喜欢
    • 2012-10-07
    • 1970-01-01
    • 2022-10-14
    • 2021-08-17
    • 1970-01-01
    • 2020-12-27
    • 1970-01-01
    相关资源
    最近更新 更多