【问题标题】:Update all the records in between from NA to the value将 NA 之间的所有记录更新为该值
【发布时间】:2017-10-25 11:09:54
【问题描述】:

我有一个格式如下的数据表:

id      c1        c2
1       1         NA
1       1         NA
1       1         10 
1       1         NA   
1       1         NA
1       1         10 
1       1         NA
1       1         NA
1       1         11 
1       1         NA   
1       1         NA
1       1         11
2       1         NA
2       1         12 
2       1         NA   
2       1         NA
2       1         12

从这个数据表中,我想更新 c2 中两个值之间的所有 NA,如下所示:

    id      c1        c2
    1       1         NA
    1       1         NA
    1       1         10 
    1       1         10   
    1       1         10
    1       1         10 
    1       1         NA
    1       1         NA
    1       1         11 
    1       1         11   
    1       1         11
    1       1         11
    2       1         NA
    2       1         12 
    2       1         12   
    2       1         12
    2       1         12

【问题讨论】:

  • 你能澄清一下吗:“我想更新 c2 中两个值之间的所有 NA,如下所示:”
  • 我想让 c2 的值在 c2 的范围开始和结束之间相同
  • 每个值最初总是只有 2 个吗?
  • 我不明白你的问题。 “c2的范围开始和结束”是什么意思?在我看来,您正在随机更改 NAs 以获取来自列 c2 的值。您能否提供一套明确的规则,或者更好的是,展示您生成第二个表格的尝试。
  • indx <- setDT(df)[!is.na(c2), .(min(.I):max(.I)), by = c2] ; df[indx$V1, c2 := indx$c2] 或许

标签: r dplyr data.table


【解决方案1】:

可以使用for 循环和which()

df=data.frame(id = c(rep(1,12)),c2 = c(NA,NA,10,NA,NA,10, NA,NA,11,NA,11,NA))

查找 c2 的唯一值:

vals=unique(df[which(!is.na(df$c2)),'c2']) 

循环遍历唯一值并替换它们第一次和最后一次出现之间的观察:

for(i in vals){
  df[min(which(df$c2==i)):max(which(df$c2==i)),'c2']=i
}

【讨论】:

  • 如果数据框有两个连续的数字,这不会发生
  • 你能举个例子,或者更新你的问题以显示它什么时候不起作用?
【解决方案2】:

除了直接使用行索引的David's approach 之外,还有另一种使用非等值连接data.table 方法:

# coerce to data.table
setDT(DT)[
  # append unique row id
  , rn := .I][
    # non-equi join on row ids
    DT[!is.na(c2), .(rmin = min(rn), rmax = max(rn)), by = c2], 
    on = .(rn >= rmin, rn <= rmax), c2 := i.c2][
      # remove row id column
      , rn := NULL][]
    id c1 c2
 1:  1  1 NA
 2:  1  1 NA
 3:  1  1 10
 4:  1  1 10
 5:  1  1 10
 6:  1  1 10
 7:  1  1 NA
 8:  1  1 NA
 9:  1  1 11
10:  1  1 11
11:  1  1 11
12:  1  1 11
13:  2  1 NA
14:  2  1 12
15:  2  1 12
16:  2  1 12
17:  2  1 12

警告

表达式

DT[!is.na(c2), .(rmin = min(rn), rmax = max(rn)), by = c2]

返回 c2 的每个唯一值的行 ID 范围

   c2 rmin rmax
1: 10    3    6
2: 11    9   12
3: 12   14   17

有一个隐含的假设,即行 ID 范围不重叠。它要求每个“间隙”都与唯一的c2 值相关联。这也会影响其他解决方案12

使用rleid() 改进的解决方案

可以改进代码以处理违反上述假设的情况。

使用rleid(),即使c2 值相同,我们也可以区分不同的间隙。比如对于第二个样本数据集

DT2[!is.na(c2), .(c2 = first(c2), rmin = min(rn), rmax = max(rn)), by = rleid(c2)]
   rleid c2 rmin rmax
1:     1 10    3    6
2:     2 11    9   12
3:     3 12   14   17
4:     4 10   20   23

完整代码:

setDT(DT2)[, rn := .I][
  DT2[!is.na(c2), .(c2 = first(c2), rmin = min(rn), rmax = max(rn)), by = rleid(c2)], 
  on = .(rn >= rmin, rn <= rmax), c2 := i.c2][, rn := NULL][]
    id c1 c2
 1:  1  1 NA
 2:  1  1 NA
 3:  1  1 10
 4:  1  1 10
 5:  1  1 10
 6:  1  1 10
 7:  1  1 NA
 8:  1  1 NA
 9:  1  1 11
10:  1  1 11
11:  1  1 11
12:  1  1 11
13:  2  1 NA
14:  2  1 12
15:  2  1 12
16:  2  1 12
17:  2  1 12
18:  2  1 NA
19:  2  1 NA
20:  2  1 10
21:  2  1 10
22:  2  1 10
23:  2  1 10
24:  2  1 NA
25:  2  1 NA
    id c1 c2

数据

library(data.table)
DT <- fread("id      c1        c2
1       1         NA
1       1         NA
1       1         10 
1       1         NA   
1       1         NA
1       1         10 
1       1         NA
1       1         NA
1       1         11 
1       1         NA   
1       1         NA
1       1         11
2       1         NA
2       1         12 
2       1         NA   
2       1         NA
2       1         12")

扩展数据集(注意c2 == 10的重复出现):

DT2 <- fread("id      c1        c2
1       1         NA
1       1         NA
1       1         10 
1       1         NA   
1       1         NA
1       1         10 
1       1         NA
1       1         NA
1       1         11 
1       1         NA   
1       1         NA
1       1         11
2       1         NA
2       1         12 
2       1         NA   
2       1         NA
2       1         12
2       1         NA
2       1         NA
2       1         10 
2       1         NA   
2       1         NA
2       1         10 
2       1         NA
2       1         NA")

【讨论】:

    【解决方案3】:

    好的(新的/编辑的答案),我们可以利用这样一个事实,即解决方案的所需属性是填充应该产生与填充相同的结果:

    library(tidyverse)    
    df %>% 
    mutate(filled_down = c2, filled_up = c2) %>% 
    fill(filled_down, .direction="down") %>% 
    fill(filled_up, .direction="up") %>% 
    mutate(c2 = ifelse(filled_down == filled_up, filled_down, c2)) %>% 
    select(-filled_down, -filled_up)
    

    【讨论】:

    • 你是对的。似乎只是想在不变的值之间替换 NA。
    • 请注意我的答案,因为编辑后现在应该可以满足要求了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-21
    • 1970-01-01
    • 2021-10-28
    • 2023-04-04
    • 1970-01-01
    • 2013-03-08
    • 2021-08-01
    相关资源
    最近更新 更多