แทนที่ NAs ด้วยค่า non-NA ล่าสุด


141

ใน data.frame (หรือ data.table) ฉันต้องการ "กรอกข้อมูล" NAs ด้วยค่าที่ไม่ใช่ NA ก่อนหน้านี้ที่ใกล้เคียงที่สุด ตัวอย่างง่ายๆการใช้เวกเตอร์ (แทน a data.frame) มีดังต่อไปนี้:

> y <- c(NA, 2, 2, NA, NA, 3, NA, 4, NA, NA)

ฉันต้องการฟังก์ชั่นfill.NAs()ที่ช่วยให้ฉันสร้างyyสิ่งนั้นได้:

> yy
[1] NA NA NA  2  2  2  2  3  3  3  4  4

ฉันจำเป็นต้องทำซ้ำการดำเนินการนี้สำหรับหลายคน (รวม ~ 1 Tb) data.frames ขนาดเล็ก(~ 30-50 Mb) ที่แถวเป็น NA คือรายการทั้งหมดของมัน วิธีที่ดีในการเข้าถึงปัญหาคืออะไร?

วิธีแก้ปัญหาที่น่าเกลียดที่ฉันปรุงขึ้นใช้ฟังก์ชั่นนี้:

last <- function (x){
    x[length(x)]
}    

fill.NAs <- function(isNA){
if (isNA[1] == 1) {
    isNA[1:max({which(isNA==0)[1]-1},1)] <- 0 # first is NAs 
                                              # can't be forward filled
}
isNA.neg <- isNA.pos <- isNA.diff <- diff(isNA)
isNA.pos[isNA.diff < 0] <- 0
isNA.neg[isNA.diff > 0] <- 0
which.isNA.neg <- which(as.logical(isNA.neg))
if (length(which.isNA.neg)==0) return(NULL) # generates warnings later, but works
which.isNA.pos <- which(as.logical(isNA.pos))
which.isNA <- which(as.logical(isNA))
if (length(which.isNA.neg)==length(which.isNA.pos)){
    replacement <- rep(which.isNA.pos[2:length(which.isNA.neg)], 
                                which.isNA.neg[2:max(length(which.isNA.neg)-1,2)] - 
                                which.isNA.pos[1:max(length(which.isNA.neg)-1,1)])      
    replacement <- c(replacement, rep(last(which.isNA.pos), last(which.isNA) - last(which.isNA.pos)))
} else {
    replacement <- rep(which.isNA.pos[1:length(which.isNA.neg)], which.isNA.neg - which.isNA.pos[1:length(which.isNA.neg)])     
    replacement <- c(replacement, rep(last(which.isNA.pos), last(which.isNA) - last(which.isNA.pos)))
}
replacement
}

ฟังก์ชั่นการfill.NAsใช้งานดังต่อไปนี้:

y <- c(NA, 2, 2, NA, NA, 3, NA, 4, NA, NA)
isNA <- as.numeric(is.na(y))
replacement <- fill.NAs(isNA)
if (length(replacement)){
which.isNA <- which(as.logical(isNA))
to.replace <- which.isNA[which(isNA==0)[1]:length(which.isNA)]
y[to.replace] <- y[replacement]
} 

เอาท์พุต

> y
[1] NA  2  2  2  2  3  3  3  4  4  4

... ซึ่งดูเหมือนว่าจะทำงาน แต่มนุษย์มันน่าเกลียด! ข้อเสนอแนะใด ๆ


1
จากคำถามอื่น ๆ ตั้งแต่หนึ่งนี้ผมคิดว่าคุณได้พบในขณะนี้ในroll=TRUE data.table
Matt Dowle

3
มีการแนะนำวิธีการใหม่fillในR
Saksham

14
tidyr::fill()นอกจากนี้ยังมีลักษณะเป็น
zx8754

ดูเพิ่มเติมที่: stackoverflow.com/questions/12607465/…
Michael Ohlrogge

คำตอบ:


160

คุณอาจต้องการใช้na.locf()ฟังก์ชั่นจากแพ็คเกจสวนสัตว์เพื่อดำเนินการสังเกตการณ์ครั้งต่อไปเพื่อแทนที่ค่า NA ของคุณ

นี่คือจุดเริ่มต้นของตัวอย่างการใช้งานจากหน้าช่วยเหลือ:

library(zoo)

az <- zoo(1:6)

bz <- zoo(c(2,NA,1,4,5,2))

na.locf(bz)
1 2 3 4 5 6 
2 2 1 4 5 2 

na.locf(bz, fromLast = TRUE)
1 2 3 4 5 6 
2 1 1 4 5 2 

cz <- zoo(c(NA,9,3,2,3,2))

na.locf(cz)
2 3 4 5 6 
9 3 2 3 2 

2
นอกจากนี้โปรดทราบว่าna.locfในสวนสัตว์จะทำงานกับเวกเตอร์สามัญรวมถึงวัตถุในสวนสัตว์ ใช้na.rmอาร์กิวเมนต์จะมีประโยชน์ในการใช้งานบางอย่าง
G. Grothendieck

5
ใช้เพื่อให้ชั้นนำna.locf(cz, na.rm=FALSE) NA
BallpointBen

ความคิดเห็นของ @BallpointBen เป็นสิ่งสำคัญและควรรวมอยู่ในคำตอบ ขอบคุณ!
เบ็น

62

ขออภัยที่ขุดคำถามเก่า ๆ ฉันไม่สามารถค้นหาฟังก์ชั่นเพื่อทำงานนี้บนรถไฟดังนั้นฉันจึงเขียนด้วยตัวเอง

ฉันภูมิใจที่พบว่ามันเร็วขึ้นเล็กน้อย
มันยืดหยุ่นน้อยกว่า

แต่มันเล่นได้ดีกับaveสิ่งที่ฉันต้องการ

repeat.before = function(x) {   # repeats the last non NA value. Keeps leading NA
    ind = which(!is.na(x))      # get positions of nonmissing values
    if(is.na(x[1]))             # if it begins with a missing, add the 
          ind = c(1,ind)        # first position to the indices
    rep(x[ind], times = diff(   # repeat the values at these indices
       c(ind, length(x) + 1) )) # diffing the indices + length yields how often 
}                               # they need to be repeated

x = c(NA,NA,'a',NA,NA,NA,NA,NA,NA,NA,NA,'b','c','d',NA,NA,NA,NA,NA,'e')  
xx = rep(x, 1000000)  
system.time({ yzoo = na.locf(xx,na.rm=F)})  
## user  system elapsed   
## 2.754   0.667   3.406   
system.time({ yrep = repeat.before(xx)})  
## user  system elapsed   
## 0.597   0.199   0.793   

แก้ไข

เนื่องจากนี่เป็นคำตอบที่ได้รับการโหวตมากที่สุดของฉันฉันได้รับการเตือนบ่อยครั้งว่าฉันไม่ได้ใช้ฟังก์ชั่นของตัวเองเพราะฉันมักจะต้องมีการmaxgapโต้แย้งของสวนสัตว์ เนื่องจากสวนสัตว์มีปัญหาแปลก ๆ ในกรณีที่ขอบเมื่อฉันใช้ dplyr + วันที่ฉันไม่สามารถแก้ปัญหาได้ฉันกลับมาที่นี่ในวันนี้เพื่อปรับปรุงฟังก์ชั่นเก่าของฉัน

ฉันเปรียบเทียบฟังก์ชั่นที่ได้รับการปรับปรุงของฉันและรายการอื่น ๆ ทั้งหมดที่นี่ สำหรับชุดคุณสมบัติพื้นฐานtidyr::fillนั้นเร็วที่สุดในขณะที่ยังไม่ได้ทำให้เคสขอบ รายการ Rcpp โดย @BrandonBertelsen นั้นยังเร็วกว่า แต่ก็ไม่ยืดหยุ่นกับประเภทของอินพุต (เขาทดสอบกรณีขอบอย่างไม่ถูกต้องเนื่องจากความเข้าใจผิดall.equal)

หากคุณต้องการmaxgapฟังก์ชั่นของฉันด้านล่างเร็วกว่าสวนสัตว์ (และไม่มีปัญหาแปลก ๆ กับวันที่)

ฉันวางเอกสารของการทดสอบของฉัน

ฟังก์ชั่นใหม่

repeat_last = function(x, forward = TRUE, maxgap = Inf, na.rm = FALSE) {
    if (!forward) x = rev(x)           # reverse x twice if carrying backward
    ind = which(!is.na(x))             # get positions of nonmissing values
    if (is.na(x[1]) && !na.rm)         # if it begins with NA
        ind = c(1,ind)                 # add first pos
    rep_times = diff(                  # diffing the indices + length yields how often
        c(ind, length(x) + 1) )          # they need to be repeated
    if (maxgap < Inf) {
        exceed = rep_times - 1 > maxgap  # exceeding maxgap
        if (any(exceed)) {               # any exceed?
            ind = sort(c(ind[exceed] + 1, ind))      # add NA in gaps
            rep_times = diff(c(ind, length(x) + 1) ) # diff again
        }
    }
    x = rep(x[ind], times = rep_times) # repeat the values at these indices
    if (!forward) x = rev(x)           # second reversion
    x
}

ฉันยังใส่ฟังก์ชั่นในแพ็คเกจ formrของฉัน(Github เท่านั้น)


2
+1 แต่ฉันเดาว่าจะต้องมีการวนลูปต่อคอลัมน์หากคุณต้องการใช้dfกับคอลัมน์ที่มีหลายคอลัมน์ใช่ไหม
Zhubarb

3
@ Ruben ขอบคุณอีกครั้งสำหรับรายงานของคุณ โดยตอนนี้ข้อผิดพลาดได้รับการแก้ไขใน R-Forge นอกจากนี้ฉันได้ปรับแต่งและส่งออกฟังก์ชัน workhorse na.locf0ซึ่งตอนนี้คล้ายกันในขอบเขตและประสิทธิภาพการrepeat_lastทำงานของคุณ เบาะแสคือการใช้diffมากกว่าและหลีกเลี่ยงcumsum ฟังก์ชั่นifelseหลักna.locf.defaultยังค่อนข้างช้าเพราะมันทำหน้าที่ตรวจสอบและจัดการหลายคอลัมน์มากขึ้นบางอย่าง
Achim Zeileis

23

data.tableวิธีการแก้ปัญหา:

dt <- data.table(y = c(NA, 2, 2, NA, NA, 3, NA, 4, NA, NA))
dt[, y_forward_fill := y[1], .(cumsum(!is.na(y)))]
dt
     y y_forward_fill
 1: NA             NA
 2:  2              2
 3:  2              2
 4: NA              2
 5: NA              2
 6:  3              3
 7: NA              3
 8:  4              4
 9: NA              4
10: NA              4

วิธีการนี้สามารถทำงานกับศูนย์เติมไปข้างหน้าได้เช่นกัน:

dt <- data.table(y = c(0, 2, -2, 0, 0, 3, 0, -4, 0, 0))
dt[, y_forward_fill := y[1], .(cumsum(y != 0))]
dt
     y y_forward_fill
 1:  0              0
 2:  2              2
 3: -2             -2
 4:  0             -2
 5:  0             -2
 6:  3              3
 7:  0              3
 8: -4             -4
 9:  0             -4
10:  0             -4

วิธีการนี้จะกลายเป็นประโยชน์อย่างมากกับข้อมูลในระดับและสถานที่ที่คุณต้องการที่จะดำเนินการเติมข้างหน้าโดยกลุ่ม (s), data.tableซึ่งเป็นที่น่ารำคาญด้วย เพียงเพิ่มกลุ่มลงในbyclause ก่อนcumsumตรรกะ

dt <- data.table(group = sample(c('a', 'b'), 20, replace = TRUE), y = sample(c(1:4, rep(NA, 4)), 20 , replace = TRUE))
dt <- dt[order(group)]
dt[, y_forward_fill := y[1], .(group, cumsum(!is.na(y)))]
dt
    group  y y_forward_fill
 1:     a NA             NA
 2:     a NA             NA
 3:     a NA             NA
 4:     a  2              2
 5:     a NA              2
 6:     a  1              1
 7:     a NA              1
 8:     a  3              3
 9:     a NA              3
10:     a NA              3
11:     a  4              4
12:     a NA              4
13:     a  1              1
14:     a  4              4
15:     a NA              4
16:     a  3              3
17:     b  4              4
18:     b NA              4
19:     b NA              4
20:     b  2              2

1
ความสามารถในการทำสิ่งนี้โดยกลุ่มนั้นยอดเยี่ยมมาก!
JCWong

22

การจัดการกับปริมาณข้อมูลขนาดใหญ่เพื่อให้มีประสิทธิภาพมากขึ้นเราสามารถใช้ data.table package

require(data.table)
replaceNaWithLatest <- function(
  dfIn,
  nameColNa = names(dfIn)[1]
){
  dtTest <- data.table(dfIn)
  setnames(dtTest, nameColNa, "colNa")
  dtTest[, segment := cumsum(!is.na(colNa))]
  dtTest[, colNa := colNa[1], by = "segment"]
  dtTest[, segment := NULL]
  setnames(dtTest, "colNa", nameColNa)
  return(dtTest)
}

2
สามารถเพิ่ม lapply เพื่อให้สามารถนำไปใช้กับคอลัมน์ NA ได้โดยตรง:replaceNaWithLatest <- function( dfIn, nameColsNa = names(dfIn)[1] ){ dtTest <- data.table(dfIn) invisible(lapply(nameColsNa, function(nameColNa){ setnames(dtTest, nameColNa, "colNa") dtTest[, segment := cumsum(!is.na(colNa))] dtTest[, colNa := colNa[1], by = "segment"] dtTest[, segment := NULL] setnames(dtTest, "colNa", nameColNa) })) return(dtTest) }
xclotet

ตอนแรกฉันรู้สึกตื่นเต้นกับวิธีนี้ แต่จริงๆแล้วมันไม่ได้ทำสิ่งเดียวกันเลย คำถามเกี่ยวกับการกรอกข้อมูล 1 ชุดด้วยอีกชุดหนึ่ง คำตอบนี้เป็นเพียงการใส่ความ
Hack-R

19

ขว้างหมวกของฉันใน:

library(Rcpp)
cppFunction('IntegerVector na_locf(IntegerVector x) {
  int n = x.size();

  for(int i = 0; i<n; i++) {
    if((i > 0) && (x[i] == NA_INTEGER) & (x[i-1] != NA_INTEGER)) {
      x[i] = x[i-1];
    }
  }
  return x;
}')

ตั้งค่าตัวอย่างพื้นฐานและมาตรฐาน:

x <- sample(c(1,2,3,4,NA))

bench_em <- function(x,count = 10) {
  x <- sample(x,count,replace = TRUE)
  print(microbenchmark(
    na_locf(x),
    replace_na_with_last(x),
    na.lomf(x),
    na.locf(x),
    repeat.before(x)
  ), order = "mean", digits = 1)
}

และเรียกใช้การวัดประสิทธิภาพบางอย่าง:

bench_em(x,1e6)

Unit: microseconds
                    expr   min    lq  mean median    uq   max neval
              na_locf(x)   697   798   821    814   821 1e+03   100
              na.lomf(x)  3511  4137  5002   4214  4330 1e+04   100
 replace_na_with_last(x)  4482  5224  6473   5342  5801 2e+04   100
        repeat.before(x)  4793  5044  6622   5097  5520 1e+04   100
              na.locf(x) 12017 12658 17076  13545 19193 2e+05   100

ในกรณีที่:

all.equal(
     na_locf(x),
     replace_na_with_last(x),
     na.lomf(x),
     na.locf(x),
     repeat.before(x)
)
[1] TRUE

ปรับปรุง

สำหรับเวกเตอร์ที่เป็นตัวเลขฟังก์ชันจะแตกต่างกันเล็กน้อย:

NumericVector na_locf_numeric(NumericVector x) {
  int n = x.size();
  LogicalVector ina = is_na(x);

  for(int i = 1; i<n; i++) {
    if((ina[i] == TRUE) & (ina[i-1] != TRUE)) {
      x[i] = x[i-1];
    }
  }
  return x;
}

15

สิ่งนี้ได้ผลสำหรับฉัน:

  replace_na_with_last<-function(x,a=!is.na(x)){
     x[which(a)[c(1,1:sum(a))][cumsum(a)+1]]
  }


> replace_na_with_last(c(1,NA,NA,NA,3,4,5,NA,5,5,5,NA,NA,NA))

[1] 1 1 1 1 3 4 5 5 5 5 5 5 5 5

> replace_na_with_last(c(NA,"aa",NA,"ccc",NA))

[1] "aa"  "aa"  "aa"  "ccc" "ccc"

ความเร็วก็สมเหตุสมผลเช่นกัน:

> system.time(replace_na_with_last(sample(c(1,2,3,NA),1e6,replace=TRUE)))


 user  system elapsed 

 0.072   0.000   0.071 

2
ฟังก์ชั่นนี้ไม่ได้ทำตามที่คุณคาดหวังเมื่อมี NA ชั้นนำ replace_na_with_last(c(NA,1:4,NA))(เช่นพวกเขาเต็มไปด้วยค่าต่อไปนี้) imputeTS::na.locf(x, na.remaining = "rev")นอกจากนี้ยังเป็นพฤติกรรมที่เริ่มต้นของ
Ruben

ดีกว่าที่จะเพิ่มค่าเริ่มต้นสำหรับกรณีนี้วิธีการที่แตกต่างกันเล็กน้อย: replace_na_with_last<-function(x,p=is.na,d=0)c(d,x)[cummax(seq_along(x)*(!p(x)))+1]
Nick Nassuphis

คำตอบของ @NickNassuphis สั้นหวานไม่ขึ้นกับแพ็คเกจและทำงานได้ดีกับท่อ dplyr!
Kim

14

ลองใช้ฟังก์ชั่นนี้ ไม่ต้องการแพ็คเกจ ZOO:

# last observation moved forward
# replaces all NA values with last non-NA values
na.lomf <- function(x) {

    na.lomf.0 <- function(x) {
        non.na.idx <- which(!is.na(x))
        if (is.na(x[1L])) {
            non.na.idx <- c(1L, non.na.idx)
        }
        rep.int(x[non.na.idx], diff(c(non.na.idx, length(x) + 1L)))
    }

    dim.len <- length(dim(x))

    if (dim.len == 0L) {
        na.lomf.0(x)
    } else {
        apply(x, dim.len, na.lomf.0)
    }
}

ตัวอย่าง:

> # vector
> na.lomf(c(1, NA,2, NA, NA))
[1] 1 1 2 2 2
> 
> # matrix
> na.lomf(matrix(c(1, NA, NA, 2, NA, NA), ncol = 2))
     [,1] [,2]
[1,]    1    2
[2,]    1    2
[3,]    1    2

if (!anyNA(x)) return(x)ที่จะปรับปรุงมันคุณสามารถเพิ่มนี้:
Artem Klevtsov

13

การเป็นผู้นำNAเป็นรอยย่นเล็กน้อย แต่ฉันพบวิธีการทำ LOCF ที่อ่านง่ายมาก (และเวกเตอร์) เมื่อคำศัพท์นำไม่หายไปคือ:

na.omit(y)[cumsum(!is.na(y))]

การปรับเปลี่ยนที่สามารถอ่านได้น้อยกว่าโดยทั่วไปใช้งานได้:

c(NA, na.omit(y))[cumsum(!is.na(y))+1]

ให้ผลลัพธ์ที่ต้องการ:

c(NA, 2, 2, 2, 2, 3, 3, 4, 4, 4)


3
นี่ค่อนข้างหรูหรา ไม่แน่ใจว่ามันใช้ได้ในทุกกรณี แต่มันก็ใช้ได้กับฉันด้วย!
ABT

13

คุณสามารถใช้data.tableฟังก์ชั่นพร้อมใช้งานจากnafilldata.table >= 1.12.3

library(data.table)
nafill(y, type = "locf")
# [1] NA  2  2  2  2  3  3  4  4  4

หากเวกเตอร์ของคุณเป็นคอลัมน์ใน a data.tableคุณสามารถอัปเดตได้โดยอ้างอิงกับsetnafill:

d <- data.table(x = 1:10, y)
setnafill(d, type = "locf", cols = "y")
d
#      x  y
#  1:  1 NA
#  2:  2  2
#  3:  3  2
#  4:  4  2
#  5:  5  2
#  6:  6  3
#  7:  7  3
#  8:  8  4
#  9:  9  4
# 10: 10  4

หากคุณมีNAหลายคอลัมน์ ...

d <- data.table(x = c(1, NA, 2), y = c(2, 3, NA), z = c(4, NA, 5))
#     x  y  z
# 1:  1  2  4
# 2: NA  3 NA
# 3:  2 NA  5

... คุณสามารถเติมได้โดยการอ้างอิงในครั้งเดียว:

setnafill(d, type = "locf")
d
#    x y z
# 1: 1 2 4
# 2: 1 3 4
# 3: 2 3 5

โปรดทราบว่า:

ขณะนี้สนับสนุนเฉพาะประเภทข้อมูลสองเท่าและจำนวนเต็ม [ data.table 1.12.6]

ฟังก์ชั่นส่วนใหญ่จะถูกขยายในไม่ช้า ดูเปิดประเด็นnafill, setnafill สำหรับตัวปัจจัยและประเภทอื่น ๆที่คุณยังหาวิธีแก้ปัญหาชั่วคราว


5

แพคเกจ tidyverse เสนอวิธีง่ายๆในการทำเช่นนี้:

y = c(NA, 2, 2, NA, NA, 3, NA, 4, NA, NA)

# first, transform it into a data.frame

y = as.data.frame(y)
   y
1  NA
2   2
3   2
4  NA
5  NA
6   3
7  NA
8   4
9  NA
10 NA

fill(y, y, .direction = 'down')
    y
1  NA
2   2
3   2
4   2
5   2
6   3
7   3
8   4
9   4
10  4

3

มีกลุ่มของแพคเกจที่เสนอฟังก์ชั่นna.locf(การNAสังเกตสุดท้ายดำเนินการส่งต่อ)

  • xts - xts::na.locf
  • zoo - zoo::na.locf
  • imputeTS - imputeTS::na.locf
  • spacetime - spacetime::na.locf

และแพ็คเกจอื่น ๆ ที่ฟังก์ชั่นนี้ตั้งชื่อต่างออกไป


2

ติดตามผลงาน Rcpp ของ Brandon Bertelsen สำหรับฉันแล้วรุ่น NumericVector ใช้งานไม่ได้: มันแทนที่รุ่นแรกเท่านั้น นี่เป็นเพราะinaเวกเตอร์ได้รับการประเมินเพียงครั้งเดียวที่จุดเริ่มต้นของฟังก์ชัน

แต่สามารถใช้วิธีการเดียวกันกับฟังก์ชั่น IntegerVector แทน การทำงานต่อไปนี้สำหรับฉัน:

library(Rcpp)
cppFunction('NumericVector na_locf_numeric(NumericVector x) {
  R_xlen_t n = x.size();
  for(R_xlen_t i = 0; i<n; i++) {
    if(i > 0 && !R_finite(x[i]) && R_finite(x[i-1])) {
      x[i] = x[i-1];
    }
  }
  return x;
}')

ในกรณีที่คุณต้องการรุ่น CharacterVector วิธีการพื้นฐานเดียวกันก็ใช้งานได้:

cppFunction('CharacterVector na_locf_character(CharacterVector x) {
  R_xlen_t n = x.size();
  for(R_xlen_t i = 0; i<n; i++) {
    if(i > 0 && x[i] == NA_STRING && x[i-1] != NA_STRING) {
      x[i] = x[i-1];
    }
  }
  return x;
}')

int n = x.size () และสำหรับ (int i = 0; i <n; i ++) ควรถูกแทนที่ด้วย double ใน R เวกเตอร์อาจมีขนาดใหญ่กว่าขนาด c ++ ได้
stats0007

ดูเหมือนว่าฟังก์ชันนี้จะส่งคืน "R_xlen_t" หาก R ถูกคอมไพล์ด้วยการสนับสนุนเวคเตอร์แบบยาวจะถูกกำหนดเป็น ptrdiff_t; ถ้ามันไม่ใช่มันเป็น int ขอบคุณสำหรับการแก้ไข!
Evan Cortens

1

นี่คือการแก้ไขโซลูชันของ @ AdamO อันนี้ทำงานได้เร็วขึ้นเพราะมันข้ามna.omitฟังก์ชั่น สิ่งนี้จะเขียนทับNAค่าในเวกเตอร์y(ยกเว้นส่วนนำNA)

   z  <- !is.na(y)                  # indicates the positions of y whose values we do not want to overwrite
   z  <- z | !cumsum(z)             # for leading NA's in y, z will be TRUE, otherwise it will be FALSE where y has a NA and TRUE where y does not have a NA
   y  <- y[z][cumsum(z)]

0

ฉันลองด้านล่าง:

nullIdx <- as.array(which(is.na(masterData$RequiredColumn)))
masterData$RequiredColumn[nullIdx] = masterData$RequiredColumn[nullIdx-1]

nullIdx รับหมายเลข idx ที่ masterData $ RequiredColumn เคยมีค่า Null / NA ในบรรทัดถัดไปเราแทนที่ด้วยค่า Idx-1 ที่สอดคล้องกันนั่นคือค่าสุดท้ายสุดท้ายก่อนแต่ละ NULL / NA


นี้จะไม่ทำงานถ้ามีหลายค่าที่ขาดหายไปติดต่อกัน - กลายเป็น1 NA NA 1 1 NAนอกจากนี้ฉันคิดว่าas.array()ไม่จำเป็น
Gregor Thomas

0

สิ่งนี้ใช้ได้กับฉันแม้ว่าฉันจะไม่แน่ใจว่ามีประสิทธิภาพมากกว่าคำแนะนำอื่น ๆ หรือไม่

rollForward <- function(x){
  curr <- 0
  for (i in 1:length(x)){
    if (is.na(x[i])){
      x[i] <- curr
    }
    else{
      curr <- x[i]
    }
  }
  return(x)
}

0
fill.NAs <- function(x) {is_na<-is.na(x); x[Reduce(function(i,j) if (is_na[j]) i else j, seq_len(length(x)), accumulate=T)]}

fill.NAs(c(NA, 2, 2, NA, NA, 3, NA, 4, NA, NA))

[1] NA  2  2  2  2  3  3  4  4  4

ย่อขนาดเป็นแนวคิดการเขียนโปรแกรมที่ใช้งานได้ดีซึ่งอาจมีประโยชน์สำหรับงานที่คล้ายกัน น่าเสียดายที่ R มันช้ากว่าrepeat.beforeคำตอบข้างต้นประมาณ 70 เท่า


0

ฉันใช้ฟังก์ชั่นนี้เป็นการส่วนตัว ฉันไม่รู้ว่าเร็วหรือช้าแค่ไหน แต่มันทำงานได้โดยไม่ต้องใช้ห้องสมุด

replace_na_with_previous<-function (vector) {
        if (is.na(vector[1])) 
            vector[1] <- na.omit(vector)[1]
        for (i in 1:length(vector)) {
            if ((i - 1) > 0) {
                if (is.na(vector[i])) 
                    vector[i] <- vector[i - 1]
            }
        }
        return(vector)
    }

ถ้าคุณต้องการใช้ฟังก์ชั่นนี้ใน dataframe ถ้า dataframe ของคุณถูกเรียกว่า df ดังนั้น

df[]<-lapply(df,replace_na_with_previous)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.