将自定义函数应用于每一行仅使用参数的第一个值

Azi*_*ggy 5 r apply missing-data na

我正在尝试使用以下数据集将NA值重新编码0为列的子集:

set.seed(1)
df <- data.frame(
  id = c(1:10),
  trials = sample(1:3, 10, replace = T),
  t1 = c(sample(c(1:9, NA), 10)),
  t2 = c(sample(c(1:7, rep(NA, 3)), 10)),
  t3 = c(sample(c(1:5, rep(NA, 5)), 10))
  )
Run Code Online (Sandbox Code Playgroud)

每行都有一定数量的试验(1-3之间),由trials列指定.列t1-t3表示每个试验的分数.

试验次数表示NA应将s重新编码为的列的子集0:NA在试验次数内的s表示缺失数据,并且应该被重新编码为0,而NA在试验次数之外的s没有意义,并且应该保留为NAs .因此,对于一行,其中trials == 3NAt3将被重新编码为0,但在一行中trials == 2,一个NAin t3将保持为NA.

所以,我尝试使用这个功能:

replace0 <- function(x, num.sun) {
  x[which(is.na(x[1:(num.sun + 2)]))] <- 0
  return(x)
}
Run Code Online (Sandbox Code Playgroud)

这适用于单个矢量.当我尝试将相同的函数应用于数据框时apply(),尽管:

apply(df, 1, replace0, num.sun = df$trials)
Run Code Online (Sandbox Code Playgroud)

我收到警告说:

In 1:(num.sun + 2) :
  numerical expression has 10 elements: only the first used
Run Code Online (Sandbox Code Playgroud)

其结果是,代替具有的值num.sun变化根据所述值中的每一行trials,apply()简单地使用所述第一值在trials对于每一行的列.我怎么能应用这个函数,以便num.sun参数根据值的变化而变化df$trials

谢谢!

编辑:正如一些人评论的那样,根据试验专栏,原始示例数据有一些非NA分数没有意义.这是一个更正的数据集:

df <- data.frame(
  id = c(1:5),
  trials = c(rep(1, 2), rep(2, 1), rep(3, 2)),
  t1 = c(NA, 7, NA, 6, NA),
  t2 = c(NA, NA, 3, 7, 12),
  t3 = c(NA, NA, NA, 4, NA)
)
Run Code Online (Sandbox Code Playgroud)

Jaa*_*aap 2

另一种方法:

# create an index of the NA values
w <- which(is.na(df), arr.ind = TRUE)

# create an index with the max column by row where an NA is allowed to be replaced by a zero
m <- matrix(c(1:nrow(df), (df$trials + 2)), ncol = 2)

# subset 'w' such that only the NA's which fall in the scope of 'm' remain
i <- w[w[,2] <= m[,2][match(w[,1], m[,1])],]

# use 'i' to replace the allowed NA's with a zero
df[i] <- 0
Run Code Online (Sandbox Code Playgroud)

这使:

> df
   id trials t1 t2 t3
1   1      1  3 NA  5
2   2      2  2  2 NA
3   3      2  6  6  4
4   4      3  0  1  2
5   5      1  5 NA NA
6   6      3  7  0  0
7   7      3  8  7  0
8   8      2  4  5  1
9   9      2  1  3 NA
10 10      1  9  4  3
Run Code Online (Sandbox Code Playgroud)

您可以轻松地将其包装在一个函数中:

replace.NA.with.0 <- function(df) {
  w <- which(is.na(df), arr.ind = TRUE)
  m <- matrix(c(1:nrow(df), (df$trials + 2)), ncol = 2)
  i <- w[w[,2] <= m[,2][match(w[,1], m[,1])],]
  df[i] <- 0
  return(df)
}
Run Code Online (Sandbox Code Playgroud)

现在,使用replace.NA.with.0(df)将产生上述结果。


正如其他人所指出的,某些行(1、3 和 10)的值比踪迹多。您可以通过将上述函数重写为来解决该问题:

replace.with.NA.or.0 <- function(df) {
  w <- which(is.na(df), arr.ind = TRUE)
  df[w] <- 0

  v <- tapply(m[,2], m[,1], FUN = function(x) tail(x:5,-1))
  ina <- matrix(as.integer(unlist(stack(v)[2:1])), ncol = 2)
  df[ina] <- NA

  return(df)
}
Run Code Online (Sandbox Code Playgroud)

现在,使用replace.with.NA.or.0(df)会产生以下结果:

   id trials t1 t2 t3
1   1      1  3 NA NA
2   2      2  2  2 NA
3   3      2  6  6 NA
4   4      3  0  1  2
5   5      1  5 NA NA
6   6      3  7  0  0
7   7      3  8  7  0
8   8      2  4  5 NA
9   9      2  1  3 NA
10 10      1  9 NA NA
Run Code Online (Sandbox Code Playgroud)