快速替换NA - 错误或警告

5

我有一个名为“mat”的大型数据框,包含49952个观测值和7597个变量,我正在尝试用零替换NAs。以下是我的数据框的示例:

    A   B   C   E   F   D   Q   Z   . . .
1   1   1   0   NA  NA  0   NA  NA
2   0   0   1   NA  NA  0   NA  NA
3   0   0   0   NA  NA  1   NA  NA
4   NA  NA  NA  NA  NA  NA  NA  NA
5   0   1   0   1   NA  0   NA  NA 
6   1   1   1   0   NA  0   NA  NA
7   0   0   1   0   NA  1   NA  NA 
.
.
.

我需要一个非常快的工具来替换它们。结果应该是这样的:
    A   B   C   E   F   D   Q   Z   . . .
1   1   1   0   0   0   0   0   0
2   0   0   1   0   0   0   0   0 
3   0   0   0   0   0   1   0   0
4   0   0   0   0   0   0   0   0
5   0   1   0   1   0   0   0   0 
6   1   1   1   0   0   0   0   0
7   0   0   1   0   0   1   0   0 
.
.
.

我已经尝试过lapply(mat,function(x){replace(x,is.na(x),0)}) - 没有生效 - mat[is.na(mat)] < -0 - 错误和可能太慢 - 还有一个链接 - 也没用。

@Sotos已经建议我使用plyr::rbind.fill(lapply(L,as.data.frame)),但这并没有起作用,因为它会生成379485344个观测值和1个变量的数据框(即49952x7597),所以我还必须将其转换回来。有没有更好的方法来做到这一点?

我的数据框的真正结构:

> str(mat)
'data.frame':   49952 obs. of  7597 variables:
 $ 6794602   : num  1 NA NA NA NA 0 0 0 0 0 ...
 $ 1008667   : num  NA 1 0 NA NA 0 0 0 0 0 ...
 $ 8009082   : num  NA 0 1 NA NA NA NA NA NA NA ...
 $ 6740421   : num  NA NA NA 1 NA 0 0 0 0 0 ...
 $ 6777805   : num  NA NA NA NA 1 NA NA NA NA NA ...
 $ 1001682   : num  NA NA NA NA NA 0 0 0 0 0 ...
 $ 1001990   : num  NA NA NA NA NA 0 0 0 0 0 ...
 $ 1002541   : num  NA NA NA NA NA 0 0 0 0 0 ...
 $ 1002790   : num  NA NA NA NA NA 0 0 0 0 0 ...

注意:

当我尝试使用 mat[is.na(mat)] <- 0 时,会出现警告:

> mat[is.na(mat)] <- 0
Warning messages:
1: In `[<-.factor`(`*tmp*`, thisvar, value = 0) :
  invalid factor level, NA generated
2: In `[<-.factor`(`*tmp*`, thisvar, value = 0) :
  invalid factor level, NA generated
> nlevels(mat)
[1] 0

使用 mat[is.na(mat)] <- 0 后的数据框 mat:
> str(mat)
'data.frame':   49952 obs. of  7597 variables:
 $ 6794602   : num  1 0 0 0 0 0 0 0 0 0 ...
 $ 1008667   : num  0 1 0 0 0 0 0 0 0 0 ...
 $ 8009082   : num  0 0 1 0 0 0 0 0 0 0 ...
 $ 6740421   : num  0 0 0 1 0 0 0 0 0 0 ...
 $ 6777805   : num  0 0 0 0 1 0 0 0 0 0 ...
 $ 1001682   : num  0 0 0 0 0 0 0 0 0 0 ...
 $ 1001990   : num  0 0 0 0 0 0 0 0 0 0 ...
 $ 1002541   : num  0 0 0 0 0 0 0 0 0 0 ...
 $ 1002790   : num  0 0 0 0 0 0 0 0 0 0 ...

所以问题是:

  1. 还有其他快速替换NA的方法吗?
  2. 这个警告有多大关系?因为使用mat[is.na(mat)] <- 0后的数据看起来像我想要的,但数值太多,所以我无法检查它们是否正确。

mat[is.na(mat)] = 0 应该是最快的方法,毫无疑问(对于密集矩阵来说)。如果不是这样,那在R中是一个显眼的错误…… - Konrad Rudolph
1
这只是一个警告,而且它很好地解释了正在发生的事情,对吧?如果您惊讶于数据具有因子,可以尝试使用View(mat [sapply(mat,is.factor)])或者使用str代替View - Frank
@Frank,这个问题包含str(mat)的输出,没有任何因素。但警告消息与该输出不符。 - Konrad Rudolph
@Konrad OP 截断了 str 输出。尝试使用 str(as.data.frame(replicate(7597, 1, simplify=FALSE))) -- 首先,OP 给我们展示的比他们看到的少;其次,即使完整显示输出,也无法显示所有 7597 列。总之,当 OP 只提供数据的一瞥而不是一个好的例子时,我们无法确定。 - Frank
@Frank @KonradRudolph 我认为这个数据框不应该包括任何因素: 'data.frame': 199235 obs. of 3 variables: $ Invoice_Date: Factor w/ 627 levels $ SKU : Factor w/ 53113 levels $ CustomerID : Factor w/ 55945 levels 我将其拆分为627个数据框,根据Invoice_Date使用droplevels进行简化计算,然后在列中制作SKU的频率数据框,在行中制作CustomerID的频率数据框,最后使用mat <- rbindlist(cop.data1, fill=T)将其重新组合(我不需要CusotmerID),结果获得了数据框 mat - Martina Zapletalová
编辑:我找到了两个因素!但是这是怎么回事?! - Martina Zapletalová
3个回答

10

请尝试以下方法:

mat %>% replace(is.na(.), 0)

它比 mat[is.na(mat)] <- 0 要花费更长的时间,但也许我会让它在夜间运行,以找出是否还会有警告。编辑:它需要更长的时间,并且再次出现警告。所以正如我上面写的,我想我会忽略这个警告。 - Martina Zapletalová
你能检查一下以下问题,了解那个警告信息吗?这可能有助于解决问题。 https://dev59.com/MmQn5IYBdhLWcg3wcm57#16820025 - Sagar

2

如果您怀疑某些列是因子变量,您可以使用以下代码来检测并将它们更改为数值型。

inx <- sapply(mat, inherits, "factor")
mat[inx] <- lapply(mat[inx], function(x) as.numeric(as.character(x)))

那么请尝试以下方法。
mat[] <- lapply(mat, function(x) {x[is.na(x)] <- 0; x})
mat

以下是数据。

mat <-
structure(list(A = c(1L, 0L, 0L, NA, 0L, 1L, 0L), B = c(1L, 0L, 
0L, NA, 1L, 1L, 0L), C = c(0L, 1L, 0L, NA, 0L, 1L, 1L), E = c(NA, 
NA, NA, NA, 1L, 0L, 0L), F = c(NA_real_, NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_, NA_real_), D = c(0L, 0L, 1L, NA, 
0L, 0L, 1L), Q = c(NA_real_, NA_real_, NA_real_, NA_real_, NA_real_, 
NA_real_, NA_real_), Z = c(NA_real_, NA_real_, NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_)), .Names = c("A", "B", "C", "E", 
"F", "D", "Q", "Z"), row.names = c("1", "2", "3", "4", "5", "6", 
"7"), class = "data.frame")

警告信息: 1:在[<-.factor(*tmp*, is.na(x), value = 0)中: 无效的因子水平,生成NA 2:在[<-.factor(*tmp*, is.na(x), value = 0)中: 无效的因子水平,生成NA也许我会忽略这个警告,因为它不像其他情况那样是错误。 - Martina Zapletalová
@MartinaZapletalová 如果您的 str(mat) 输出正确,那么不应该发生这种情况,因为所有列都是 numeric 类型。您确定这 7597 个变量都是 numeric 吗?如果其中有两个是因子,则可能需要先将它们转换为 numeric - Rui Barradas
所以我尝试了这个:a <- 0 for (i in 1:ncol(mat)){ if (class(mat[[i]]) == "numeric"){ a <- a+1 } else { a <- a+1 print(i) } } 结果发现mat[[2260]]和mat[[2261]]有问题,于是我查看了一下,你说得对,它们是因子,但我不明白它怎么会发生。 - Martina Zapletalová
@MartinaZapletalová 好的,我会编辑我的答案并提供代码,让您自动消除因素。 - Rui Barradas

0

请查看我详细的回答这里

#install.packages("xlsx")
library(xlsx)
extracted_df <- read.xlsx("test.xlsx", sheetName='Sheet1', stringsAsFactors=FALSE)
# Replace all NAs in a data frame with "G" character
extracted_df[is.na(extracted_df)] <- "G"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接