根据"变化率"

时间:2016-02-10 21:01:59

标签: r loops time-series na

我正在尝试使用R中的循环估算值,这些值将根据我的最后一个值乘以的变化率(" rate")来取代我的数据框中的NA(好的,这是令人困惑,但请参考下面的例子)。这与我的数据类似:

l1 <- c(NA,NA,NA,27,31,0.5)
l2 <- c(NA,8,12,28,39,0.5)
l3 <- c(NA,NA,NA,NA,39,0.3)
l4 <- c(NA,NA,11,15,31,0.2)
l5 <- c(NA,NA,NA,NA,51,0.9)

data <- as.data.frame(rbind(l1,l2,l3,l4,l5))
colnames(data) <- c("dbh1","dbh2","dbh3","dbh4","dbh5","rate")

所以我创建了一个循环来识别每行中的第一个无NA值,然后使用该值根据&#34; rate&#34;来估计其先前的值。例如,在第1行中,第一个NA值将被&#34; 27-(0.5 * 3)&#34; 替换,然后第二个NA值将&# 34; 27-(0.5 * 2)&#34; ,第三个由&#34; 27-(0.5 * 1)&#34; 。这是我提出的循环。我知道第一部分(外部循环)有效,但内部部分没有:

for (i in 1: nrow(data)) {
  dbh.cols <- data3[i,c("dbh1","dbh2","dbh3","dbh4","dbh5")]

  sample.year <- which(dbh.cols != "NA")

  data$first.dbh[i] <- min(dbh.cols, na.rm = T)
  data$first.index[i] <- min(sample.year)

  for (j on 1: (min(sample.year)-1)) {
    ifelse(is.na(data[i,j]), min(dbh.cols, na.rm = T) - (min(sample.year)-j)*rate[i,j], data[i,j])
  }
}

我不擅长编程,所以可能是我的内部循环策略&#34; ifelse&#34;太奇怪了(而且错了)但是我无法想到其他任何可以在这里工作的东西......有什么建议吗?

2 个答案:

答案 0 :(得分:2)

1)这不使用显式循环,只使用apply。它假定NAs都是如给出的例子中那样领先的。

fillIn <- function(x) {
   rate <- tail(x, 1)
   n <- sum(is.na(x)) # no of NAs
   c(x[n+1] - rate * seq(n, 1), na.omit(x))
}
replace(data, TRUE, t(apply(data, 1, fillIn)))

,并提供:

   dbh1 dbh2 dbh3 dbh4 dbh5 rate
l1 25.5 26.0 26.5 27.0   31  0.5
l2  7.5  8.0 12.0 28.0   39  0.5
l3 37.8 38.1 38.4 38.7   39  0.3
l4 10.6 10.8 11.0 15.0   31  0.2
l5 47.4 48.3 49.2 50.1   51  0.9

2)以下是使用zoo包中的na.approx的第二种方法。它不需要apply。此处data1data具有相同的内容,只是填写了第一列。其他的NA仍然存在。最后一行使用na.approx线性填充剩余的NA。

library(zoo)

NAs <- rowSums(is.na(data))
data1 <- cbind( data[cbind(1:nrow(data), NAs + 1)] - data$rate * NAs, data[-1] )
replace(data, TRUE, t(na.approx(t(data1))))

,并提供:

   dbh1 dbh2 dbh3 dbh4 dbh5 rate
l1 25.5 26.0 26.5 27.0   31  0.5
l2  7.5  8.0 12.0 28.0   39  0.5
l3 37.8 38.1 38.4 38.7   39  0.3
l4 10.6 10.8 11.0 15.0   31  0.2
l5 47.4 48.3 49.2 50.1   51  0.9

2a)(2)的变体在中间行使用na.locf来提前每行中的第一个非NA。第一行和最后一行是相同的。

library(zoo)

NAs <- rowSums(is.na(data))
data1 <- cbind(na.locf(t(data), fromLast = TRUE)[1, ] - data$rate * NAs, data[-1])
replace(data, TRUE, t(na.approx(t(data1))))

答案 1 :(得分:1)

您不需要为此使用多个for循环。下面是一些简化的代码,可以为for循环执行您想要的操作。明确使用data,我们需要从每一行获取第一个非NA值。

for_estimate <- apply(data, 1, function(x) x[min(which(is.na(x) == FALSE))])

其次,我们需要根据有多少NA值来确定每行乘以速率的整数。

# total number of NA values per row
n_na <- apply(data,1, function(x) sum(is.na(x)) )

# make it a matrix with a 0's appended on
n_na <- matrix(c(n_na, rep(0, nrow(data) * (ncol(data)-1))), 
           nrow = nrow(data), ncol = ncol(data)-1)

# fill in the rest of the matrix
for(i in 2:ncol(n_na)){
  n_na[,i] <- n_na[,i-1] -1
}

一旦我们有了这个,我们就可以使用这段代码以您感兴趣的方式回填NA值。

for(i in (ncol(data)-1):1){
  if(sum(is.na(data[,i]))>0){
  to_fill <- which(is.na(data[,i])==TRUE)

  data[to_fill,i] <- for_estimate[to_fill] - (data$rate[to_fill]*(n_na[to_fill,i])
  }

}

输出

   dbh1 dbh2 dbh3 dbh4 dbh5 rate
l1 25.5 26.0 26.5 27.0   31  0.5
l2  7.5  8.0 12.0 28.0   39  0.5
l3 37.8 38.1 38.4 38.7   39  0.3
l4 10.6 10.8 11.0 15.0   31  0.2
l5 47.4 48.3 49.2 50.1   51  0.9