Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/75.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
R 用最新的非NA值替换NAs_R_Data.table_Zoo_R Faq - Fatal编程技术网

R 用最新的非NA值替换NAs

R 用最新的非NA值替换NAs,r,data.table,zoo,r-faq,R,Data.table,Zoo,R Faq,在data.frame(或data.table)中,我想用最接近的前一个非NA值“前向填充”NAs。使用向量(而不是data.frame)的简单示例如下: > y <- c(NA, 2, 2, NA, NA, 3, NA, 4, NA, NA) 我需要对许多(总容量~1 Tb)小型数据.frames(~30-50 Mb)重复此操作,其中一行是NA,其所有条目都是NA。解决问题的好方法是什么 我设计的丑陋解决方案使用以下函数: last <- function (x){

在data.frame(或data.table)中,我想用最接近的前一个非NA值“前向填充”NAs。使用向量(而不是
data.frame
)的简单示例如下:

> y <- c(NA, 2, 2, NA, NA, 3, NA, 4, NA, NA)
我需要对许多(总容量~1 Tb)小型
数据.frame
s(~30-50 Mb)重复此操作,其中一行是NA,其所有条目都是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
}
输出


。。。这似乎有效。但是,老兄,它丑吗!有什么建议吗?

您可能希望使用软件包中的
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 
图书馆(动物园)

az很抱歉,我问了一个老问题。 我在火车上找不到做这项工作的函数,所以我自己写了一个

我很自豪地发现它的速度快了一点点。
但它的灵活性较差

但它与
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   
编辑 当这成为我最上等的答案时,我经常被提醒不要使用自己的函数,因为我经常需要zoo的
maxgap
参数。因为当我使用无法调试的dplyr+日期时,zoo在边缘情况下有一些奇怪的问题,所以今天我回到这里来改进我的旧函数

我在这里对改进后的函数和所有其他条目进行了基准测试。对于基本功能集,
tidyr::fill
是最快的,同时也不会使边缘情况失败。@BrandonBertelsen的Rcpp条目速度更快,但在输入类型方面缺乏灵活性(由于对
all.equal
的误解,他错误地测试了边缘案例)

如果您需要
maxgap
,我下面的函数比zoo快(并且没有日期方面的奇怪问题)

我挂了电话

新功能
repeat\u last=函数(x,forward=TRUE,maxgap=Inf,na.rm=FALSE){
如果(!向前)x=旋转(x)#如果向后移动,则反转x两次
ind=哪个(!is.na(x))#获取非缺失值的位置
if(is.na(x[1])&&!na.rm)#如果它以na开头
ind=c(1,ind)#添加第一个位置
rep_times=diff(#将指数与长度进行差分会产生多少频率
c(ind,长度(x)+1))#它们需要重复
if(maxgapmaxgap#超过maxgap
如果(有(超过)的话{#有超过的吗?
ind=排序(c(ind[超出]+1,ind))#在间隙中添加NA
重复次数=差异(c(ind,长度(x)+1))#再次差异
}
}
x=rep(x[ind],times=rep#u times)#重复这些索引处的值
如果(!正向)x=反向(x)#第二次反向
x
}

我还将该函数放在我的(仅限Github)中。

尝试此函数。它不需要动物园套餐:

# 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)
    }
}

处理大数据量时,为了提高效率,我们可以使用data.table包

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)
}
require(data.table)

替换为最新的这对我很有效:

  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"
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;
}')
把我的帽子扔进去:

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;
}')
以防万一:

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;
}
NumericVector na_locf_numeric(NumericVector x){
int n=x.size();
LogicalVector ina=is_na(x);
对于(int i=1;i我尝试了以下方法:

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

nullIdx有许多软件包提供
na.locf
na
上次观察结转)功能:

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

还有其他软件包,其中该函数的名称不同。

这对我来说很有效,尽管我不确定它是否比其他建议更有效

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)
}

前滚跟进Brandon Bertelsen的Rcpp贡献。对我来说,NumericVector版本不起作用:它只替换了第一个NA。这是因为
ina
向量只在函数开始时计算一次

相反,可以采用与IntegerVector函数完全相同的方法。以下方法对我有效:

  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"
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;
}')
库(Rcpp)
cppFunction('NumericVector na_locf_numeric(NumericVector x)){
R_xlen_t n=x.尺寸();
对于(rxlen_t i=0;i0&&!R_有限(x[i])&&R_有限(x[i-1])){
x[i]=x[i-1];
}
}
返回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;
}')
cppFunction('CharacterVector na\u locf\u character(CharacterVector x){
R_xlen_t n=x.尺寸();
对于(R_xlen_t i=0;i 0和x[i]==NA_字符串和x[i-1]!=NA_字符串){
x[i]=x[i-1];
}
}
返回x;
}')

a
数据。表
解决方案:

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

有一个前导的
NA
有点麻烦,但我发现在前导项不缺失的情况下,执行LOCF的一种非常可读(且矢量化)的方法是:

na.省略(y)[cumsum(!is.na(y))]

一般来说,可读性稍差的修改是有效的:

c(NA,NA.省略(y))[cumsum(!is.NA(y))+1]

提供所需的输出:


c(NA,2,2,2,3,3,4,4,4)
这里是@AdamO解决方案的一个修改。这个运行得更快,因为它绕过了
NA.ommit
函数。这将覆盖向量
y
中的
NA
值(前导
NA
s除外)


z您可以使用
data.table
功能
nafill
,可从
data.table>=1.12.3
获得

library(data.table)
nafill(y, type = "locf")
# [1] NA  2  2  2  2  3  3  4  4  4
如果向量是
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
…您可以通过引用i来填写它们
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)
}
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;
}')
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;
}')
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
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
   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)]
library(data.table)
nafill(y, type = "locf")
# [1] NA  2  2  2  2  3  3  4  4  4
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
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
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
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)
    }
df[]<-lapply(df,replace_na_with_previous)
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