簡體   English   中英

用先前的非NA可用值R填充NA

[英]Fill NAs with Previous non-NA available value R

我正在嘗試使用300萬行數據集中的非NA先前值填充NA值。 目前,我可以執行此操作,但是大約需要3個小時。

約束-我無法使用任何庫,必須使用R basic完成

數據-我的數據如下所示(提取)

數據提取為例

目前,我一直在使用以下代碼

CHARDIF <- diff(VERINDEX_VEC)

k = 1
for (j in VERINDEX_VEC){
  #when value is in vector calculate difference to next value and copy VER. 
Special cases for First and Last value
  ifelse(j == 1, ALL_POS$C01[j:CHARDIF[k]] <- ALL_POS$C01[j],
         ifelse(j == max(VERINDEX_VEC), ALL_POS$C01[j:max(as.numeric
(row.names(ALL_POS)))] <- ALL_POS$C01[j],ALL_POS$C01[j:(j+CHARDIF[k]-1)] <- 
ALL_POS$C01[j]))
  k = k + 1
}

如您所見,我有一個帶有非NA位置的向量,然后我計算了位置之間的差,這有助於我選擇要粘貼的范圍,因為我知道當下一個非NA值發生時。

有誰有更好的解決方案? 特別是更快的

首先,我將生成隨機數據以對此進行測試

# generate random data 
test_data <- data.frame(x = 1:100, y = rnorm(100))
# add random NAs
test_data$y[sample(1:100, 50)] <- NA

現在嘗試這個:

# locate non NAs in the wanted column
not_na <- which(!is.na(test_data$y))

# define the function replace_NAs_custom

replace_NAs_custom <- function(i, col){
         if(is.na(col[i])){
           col[i] <- col[max(not_na[not_na < i] )]
         }
         return(col[i] )
       }

test_data$y_2 <- unlist(lapply(1:nrow(test_data), replace_NAs_custom, test_data$y))

看起來您的代碼每次循環都在執行大量計算和內存分配。 為了減少時間,我們想減少循環執行每次迭代的工作量。

對於您的問題,我不是100%清楚的,但是我想我已經掌握了要點。 聽起來您只是想獲取最后一個非NA值並將其復制到具有NA值的行中。 我們可以使用一對或索引來執行此操作。

在下面的方法中,在進入循環之前,所有內存已被預先分配。 唯一的內存操作是用另一個值替換一個值(NA)。 除該操作外,還有一個檢查以查看該值是否為NA以及對索引進行加法操作。 為了更快地解決此問題,您將需要使用c優化的向量函數(可能來自程序包/庫)。

要使用先前的值來填充NA:

# Fill with previous non-NA value
VERINDEX_VEC <- c(NA,"A1","A2",NA,NA,"A3",NA)
VERINDEX_VEC
# [1] NA   "A1" "A2" NA   NA   "A3" NA  

non_na_positions <- which(!is.na(VERINDEX_VEC))
# If the first value is NA we need to fill with NA until we hit a known value...
if(is.na(VERINDEX_VEC[1])){
  non_na_positions <- c(NA,non_na_positions)
}

index = 1

for(i in 1:length(VERINDEX_VEC)){
  if(is.na(VERINDEX_VEC[i])) {
    VERINDEX_VEC[i] <- VERINDEX_VEC[non_na_positions[index]]
  } else {
    index <- index + 1
  }
}

VERINDEX_VEC
# [1] NA   "A1" "A2" "A2" "A2" "A3" "A3"

要使用下一個值來填充NA:

# Fill with next non-NA Value
VERINDEX_VEC <- c(NA,"A1","A2",NA,NA,"A3",NA)
VERINDEX_VEC
# [1] NA   "A1" "A2" NA   NA   "A3" NA  

non_na_positions <- which(!is.na(VERINDEX_VEC))
# Never need the first position of the vector if we are looking-ahead...
index <- ifelse(non_na_positions[1]==1,2,1)

for(i in 1:length(VERINDEX_VEC)){
  if(is.na(VERINDEX_VEC[i])) {
    VERINDEX_VEC[i] <- VERINDEX_VEC[non_na_positions[index]]
  } else {
    index <- index + 1
  }
}

VERINDEX_VEC
# [1] "A1" "A1" "A2" "A3" "A3" "A3" NA  

我相信我可能找到了一種更快的方法,至少比上一個答案要快得多,但是由於我無法重現輸出,因此我無法將其與您的代碼進行比較。

(請參閱下面的基准化結果)

你可以嘗試一下:

set.seed(223)
# generate random data 
test_data <- data.frame(x = 1:1000, y = rnorm(1000))
# add random NAs
test_data$y[sample(1:1000, 500)] <- NA



# which records are filled
not_na <- which(!is.na(test_data$y))

# calculate the distance from the previous filled value
# this is to identify how many times should each value be repeated
dist <- unlist(lapply(1:(length(not_na) - 1), 
                        function(i){
                          not_na[i+1] - not_na[i]
                        }))

# compine both to create a kind of "look-up table"
not_na <- data.frame(idx = not_na, 
                       rep_num = c(dist, nrow(test_data) - not_na[length(not_na)] + 1))

test_data$y_3 <- unlist(lapply(1:nrow(not_na), 
                                 function(x){
                                   rep(test_data[not_na$idx[x], "y"], times = not_na$rep_num[x])
                                 }))

基准測試:

f1()是最后一個答案

f2()是這個答案

  • 對於test_data中的100.000行

     # microbenchmark(f1(), times = 10) # Unit: seconds # expr min lq mean median uq max neval # f1() 39.54495 39.72853 40.38092 40.7027 40.76339 41.29006 10 # microbenchmark(f2(), times = 10) # Unit: seconds # expr min lq mean median uq max neval # f2() 1.578852 1.610565 1.666488 1.645821 1.736301 1.755673 10 
  • 對於1.000.000行,新方法大約需要16秒

     # microbenchmark(f2(), times = 1) # Unit: seconds # expr min lq mean median uq max neval # f2() 16.33777 16.33777 16.33777 16.33777 16.33777 16.33777 1 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM