我已经提出了类似的问题,但是现在我只想限制NA的新值。
我有一些这样的数据:
Date 1 Date 2 Date 3 Date 4 Date 5 Date 6
A NA 0.1 0.2 NA 0.3 0.2
B 0.1 NA NA 0.3 0.2 0.1
C NA NA NA NA 0.3 NA
D 0.1 0.2 0.3 NA 0.1 NA
E NA NA 0.1 0.2 0.1 0.3
我想根据首次注册一个值的日期更改数据的NA值。例如,对于A,第一次注册是日期2。然后我希望在注册之前,A中的NA的值为0,而在第一次注册之后,NA的值成为最近值的平均值(日期3的平均值)和5)。
如果最后一个值是NA,则将其转换为最后一个注册值(如C和D)。在E的情况下,所有NA值都将变为0。
得到这样的东西:
Date 1 Date 2 Date 3 Date 4 Date 5 Date 6
A 0 0.1 0.2 0.25 0.3 0.2
B 0.1 0.2 0.2 0.3 0.2 0.1
C 0 0 0 0 0.3 0.3
D 0.1 0.2 0.3 0.2 0.1 0.1
E 0 0 0.1 0.2 0.1 0.3
你能帮我吗?我不确定如何在R中做到这一点。
答案 0 :(得分:8)
这是将na.approx
包中的zoo
和apply
与MARGIN = 1
一起使用的一种方法(因此这可能不是很有效,但是可以完成工作)。
library(zoo)
df1 <- as.data.frame(t(apply(dat, 1, na.approx, method = "constant", f = .5, na.rm = FALSE)))
这将导致
df1
# V1 V2 V3 V4 V5
#A NA 0.1 0.2 0.25 0.3
#B 0.1 0.2 0.2 0.30 0.2
#C NA NA NA NA 0.3
#E NA NA 0.1 0.20 0.1
替换NA
并重命名列。
df1[is.na(df1)] <- 0
names(df1) <- names(dat)
df1
# Date_1 Date_2 Date_3 Date_4 Date_5
#A 0.0 0.1 0.2 0.25 0.3
#B 0.1 0.2 0.2 0.30 0.2
#C 0.0 0.0 0.0 0.00 0.3
#E 0.0 0.0 0.1 0.20 0.1
说明
给出向量
x <- c(0.1, NA, NA, 0.3, 0.2)
na.approx(x)
返回带有线性插值的x
#[1] 0.1000000 0.1666667 0.2333333 0.3000000 0.2000000
但是OP要求常量值,因此我们需要method = "constant"
函数中的参数approx
。
na.approx(x, method = "constant")
# [1] 0.1 0.1 0.1 0.3 0.2
但是,这仍然不是OP所要求的,因为当您想要最接近的非NA
值的均值时,它将向前进行最后的观察。因此,我们需要参数f
(也来自approx
)
na.approx(x, method = "constant", f = .5)
# [1] 0.1 0.2 0.2 0.3 0.2 # looks good
来自?approx
f:对于method =“ constant”,表示介于0和1之间的数字(包括0和1),指示左连续和右连续连续函数之间的折衷。如果y0和y1是该点左右的值,则如果f == 0,则值为y0;如果f == 1,则值为y1;对于中间值,y0 *(1-f)+ y1 * f。这样,即使对于非有限的y值,结果对于f == 0也是右连续的,对于f == 1来说是左连续的。
最后,如果我们不想在每行的开头和结尾处替换NA
,则需要na.rm = FALSE
。
来自?na.approx
na.rm:逻辑。如果(样条)插值的结果仍然导致NA,应该将其删除吗?
数据
dat <- structure(list(Date_1 = c(NA, 0.1, NA, NA), Date_2 = c(0.1, NA,
NA, NA), Date_3 = c(0.2, NA, NA, 0.1), Date_4 = c(NA, 0.3, NA,
0.2), Date_5 = c(0.3, 0.2, 0.3, 0.1)), .Names = c("Date_1", "Date_2",
"Date_3", "Date_4", "Date_5"), class = "data.frame", row.names = c("A",
"B", "C", "E"))
编辑
如果最后一列中有NA
个,我们可以在应用NA
之前将它们替换为最后一个非{na.approx
s。
dat$Date_6[is.na(dat$Date_6)] <- dat[cbind(1:nrow(dat),
max.col(!is.na(dat), ties.method = "last"))][is.na(dat$Date_6)]
答案 1 :(得分:3)
这是另一个可能的答案,使用na.locf
包中的zoo
。
编辑:apply
实际上不是必需的;如果缺少该值,则此解决方案将填写最后一个观测值。
# create the dataframe
Date1 <- c(NA,.1,NA,NA)
Date2 <- c(.1, NA,NA,NA)
Date3 <- c(.2,NA,NA,.1)
Date4 <- c(NA,.3,NA,.2)
Date5 <- c(.3,.2,.3,.1)
Date6 <- c(.1,NA,NA,NA)
df <- as.data.frame(cbind(Date1,Date2,Date3,Date4,Date5,Date6))
rownames(df) <- c('A','B','C','D')
> df
Date1 Date2 Date3 Date4 Date5 Date6
A NA 0.1 0.2 NA 0.3 0.1
B 0.1 NA NA 0.3 0.2 NA
C NA NA NA NA 0.3 NA
D NA NA 0.1 0.2 0.1 NA
# Load library
library(zoo)
df2 <- t(na.locf(t(df),na.rm = F)) # fill last observation carried forward
df3 <- t(na.locf(t(df),na.rm = F, fromLast = T)) # last obs carried backward
df4 <- (df2 + df3)/2 # mean of both dataframes
df4 <- t(na.locf(t(df4),na.rm = F)) # fill last observation carried forward
df4[is.na(df4)] <- 0 # NA values are 0
Date1 Date2 Date3 Date4 Date5 Date6
A 0.0 0.1 0.2 0.25 0.3 0.1
B 0.1 0.2 0.2 0.30 0.2 0.2
C 0.0 0.0 0.0 0.00 0.3 0.3
D 0.0 0.0 0.1 0.20 0.1 0.1
答案 2 :(得分:3)
这是rollmean
中带有基数R + zoo
的另一个选项(对于这种情况,窗口大小为k = 2
的基数R显然很容易重写)。
t(apply(df, 1, function(x) {
means <- c(0, rollmean(na.omit(x), 2), tail(na.omit(x), 1))
replace(x, is.na(x), means[1 + cumsum(!is.na(x))[is.na(x)]])
}))
# Date1 Date2 Date3 Date4 Date5 Date6
# A 0.0 0.1 0.2 0.25 0.3 0.2
# B 0.1 0.2 0.2 0.30 0.2 0.1
# C 0.0 0.0 0.0 0.00 0.3 0.3
# D 0.1 0.2 0.3 0.20 0.1 0.1
# E 0.0 0.0 0.1 0.20 0.1 0.3
说明。假设x
是df
的第一行:
# Date1 Date2 Date3 Date4 Date5 Date6
# A NA 0.1 0.2 NA 0.3 0.2
然后
means
# [1] 0.00 0.15 0.25 0.25 0.20
是0的向量,以下两个非NA元素以及最后一个非NA元素的滚动平均值。然后,我们要做的就是replace
x
的那些元素is.na(x)
。我们将在索引means
处将其替换为1 + cumsum(!is.na(x))[is.na(x)]
的元素。那是棘手的部分。在这里
cumsum(!is.na(x))
# [1] 0 1 2 2 3 4
意味着x
的第一个元素已经看到0个非NA元素,而到目前为止,最后一个元素已经看到了4个非NA元素。然后
cumsum(!is.na(x))[is.na(x)]
# [1] 0 2
与x
中我们要替换的NA元素有关。请注意
1 + cumsum(!is.na(x))[is.na(x)]
# [1] 1 3
与我们要用于替换的means
元素相对应。
答案 3 :(得分:0)
我发现下面的函数太复杂了,但是它可以正常工作,所以就行了。
fun <- function(x){
if(anyNA(x)){
inx <- which(!is.na(x))
if(inx[1] > 1) x[seq_len(inx[1] - 1)] <- 0
prev <- inx[1]
for(i in inx[-1]){
if(i - prev > 1){
m <- mean(c(x[i], x[prev]))
while(prev < i){
x[prev] <- m
prev <- prev + 1
}
}
prev <- i
}
}
x
}
res <- t(apply(df1, 1, fun))
res <- as.data.frame(res)
res
# Date.1 Date.2 Date.3 Date.4 Date.5
#A 0.0 0.1 0.25 0.25 0.3
#B 0.2 0.2 0.20 0.30 0.2
#C 0.0 0.0 0.00 0.00 0.3
#E 0.0 0.0 0.10 0.20 0.1
数据。
df1 <- read.table(text = "
Date.1 Date.2 Date.3 Date.4 Date.5
A NA 0.1 0.2 NA 0.3
B 0.1 NA NA 0.3 0.2
C NA NA NA NA 0.3
E NA NA 0.1 0.2 0.1
", header = TRUE)