去除na - 如何用R數據框中的零代替NA值?




去除na r (10)

我有一個data.frame和一些列有NA值。 我想用零代替NAs。 我如何做到這一點?


dplyr例子:

library(dplyr)

df1 <- df1 %>%
    mutate(myCol1 = if_else(is.na(myCol1), 0, myCol1))

注意:這適用於每個選定的列,如果我們需要為所有列執行此操作,請參閱使用mutate_each @reidjax的答案。


你可以使用replace()

例如:

> x <- c(-1,0,1,0,NA,0,1,1)
> x1 <- replace(x,5,1)
> x1
[1] -1  0  1  0  1  0  1  1

> x1 <- replace(x,5,mean(x,na.rm=T))
> x1
[1] -1.00  0.00  1.00  0.00  0.29  0.00 1.00  1.00

使用imputeTS包的另一個例子是:

library(imputeTS)
na.replace(yourDataframe, 0)

使用矩陣或向量中的replace()NA替換為0更一般方法

例如:

> x <- c(1,2,NA,NA,1,1)
> x1 <- replace(x,is.na(x),0)
> x1
[1] 1 2 0 0 1 1

這也是在dplyr使用ifelse()dplyr

df = data.frame(col = c(1,2,NA,NA,1,1))
df <- df %>%
   mutate(col = replace(col,is.na(col),0))

如果你想在因子變量中替換NAs,這可能是有用的:

n <- length(levels(data.vector))+1

data.vector <- as.numeric(data.vector)
data.vector[is.na(data.vector)] <- n
data.vector <- as.factor(data.vector)
levels(data.vector) <- c("level1","level2",...,"leveln", "NAlevel") 

它將因子向量轉換為數值向量並添加另一個人為數值因子級別,然後將其轉換回因子向量,並帶有一個額外的“NA級別”。


如果我們試圖在導出時替換NA ,例如寫入csv時,我們可以使用:

  write.csv(data, "data.csv", na = "0")

Datacamp提取的這個簡單函數可以幫助:

replace_missings <- function(x, replacement) {
  is_miss <- is.na(x)
  x[is_miss] <- replacement

  message(sum(is_miss), " missings replaced by the value ", replacement)
  x
}

然後

replace_missings(df, replacement = 0)

我知道這個問題已經得到解答,但這樣做可能對一些人更有用:

定義這個函數:

na.zero <- function (x) {
    x[is.na(x)] <- 0
    return(x)
}

現在,無論何時您需要將矢量中的NA轉換為零,您都可以:

na.zero(some.vector)

混合dplyr / Base R選項: mutate_all(funs(replace(., is.na(.), 0))))速度是基數R d[is.na(d)] <- 0兩倍選項。 (請參閱下面的基準分析。)

如果您正在處理大量數據幀, data.table是最快的選擇:比dplyr少30%,比Base R方法快3倍。 它還修改了數據,有效地允許您一次處理近兩倍的數據。

聚類的其他有用的Tidyverse替代方法

Locationally:

  • index mutate_at(c(5:10), funs(replace(., is.na(.), 0)))
  • 直接引用 mutate_at(vars(var5:var10), funs(replace(., is.na(.), 0)))
  • 固定匹配 mutate_at(vars(contains("1")), funs(replace(., is.na(.), 0)))
    • 或代替contains() ,請嘗試ends_with()starts_with()
  • 模式匹配 mutate_at(vars(matches("\\d{2}")), funs(replace(., is.na(.), 0)))

有條件的:
(僅改變數字(列)並保留字符串(列))。

  • 整數 mutate_if(is.integer, funs(replace(., is.na(.), 0)))
  • 雙倍 mutate_if(is.numeric, funs(replace(., is.na(.), 0)))
  • 字符串 mutate_if(is.character, funs(replace(., is.na(.), 0)))

完整的分析 -

測試方法:

# Base R: 
baseR.sbst.rssgn   <- function(x) { x[is.na(x)] <- 0; x }
baseR.replace      <- function(x) { replace(x, is.na(x), 0) }
baseR.for          <- function(x) { for(j in 1:ncol(x))
                                    x[[j]][is.na(x[[j]])] = 0 }
# tidyverse
## dplyr
library(tidyverse)
dplyr_if_else      <- function(x) { mutate_all(x, funs(if_else(is.na(.), 0, .))) }
dplyr_coalesce     <- function(x) { mutate_all(x, funs(coalesce(., 0))) }

## tidyr
tidyr_replace_na   <- function(x) { replace_na(x, as.list(setNames(rep(0, 10), as.list(c(paste0("var", 1:10)))))) }

## hybrid 
hybrd.ifelse     <- function(x) { mutate_all(x, funs(ifelse(is.na(.), 0, .))) }
hybrd.rplc_all   <- function(x) { mutate_all(x, funs(replace(., is.na(.), 0))) }
hybrd.rplc_at.idx<- function(x) { mutate_at(x, c(1:10), funs(replace(., is.na(.), 0))) }
hybrd.rplc_at.nse<- function(x) { mutate_at(x, vars(var1:var10), funs(replace(., is.na(.), 0))) }
hybrd.rplc_at.stw<- function(x) { mutate_at(x, vars(starts_with("var")), funs(replace(., is.na(.), 0))) }
hybrd.rplc_at.ctn<- function(x) { mutate_at(x, vars(contains("var")), funs(replace(., is.na(.), 0))) }
hybrd.rplc_at.mtc<- function(x) { mutate_at(x, vars(matches("\\d+")), funs(replace(., is.na(.), 0))) }
hybrd.rplc_if    <- function(x) { mutate_if(x, is.numeric, funs(replace(., is.na(.), 0))) }

# data.table   
library(data.table)
DT.for.set.nms   <- function(x) { for (j in names(x))
                                    set(x,which(is.na(x[[j]])),j,0) }
DT.for.set.sqln  <- function(x) { for (j in seq_len(ncol(x)))
                                    set(x,which(is.na(x[[j]])),j,0) }

此分析的代碼:

library(microbenchmark)
# 20% NA filled dataframe of 5 Million rows and 10 columns
set.seed(42) # to recreate the exact dataframe
dfN <- as.data.frame(matrix(sample(c(NA, as.numeric(1:4)), 5e6*10, replace = TRUE),
                            dimnames = list(NULL, paste0("var", 1:10)), 
                            ncol = 10))
# Running 250 trials with each replacement method 
# (the functions are excecuted locally - so that the original dataframe remains unmodified in all cases)
perf_results <- microbenchmark(
    hybrid.ifelse    = hybrid.ifelse(copy(dfN)),
    dplyr_if_else    = dplyr_if_else(copy(dfN)),
    baseR.sbst.rssgn = baseR.sbst.rssgn(copy(dfN)),
    baseR.replace    = baseR.replace(copy(dfN)),
    dplyr_coalesce   = dplyr_coalesce(copy(dfN)),
    hybrd.rplc_at.nse= hybrd.rplc_at.nse(copy(dfN)),
    hybrd.rplc_at.stw= hybrd.rplc_at.stw(copy(dfN)),
    hybrd.rplc_at.ctn= hybrd.rplc_at.ctn(copy(dfN)),
    hybrd.rplc_at.mtc= hybrd.rplc_at.mtc(copy(dfN)),
    hybrd.rplc_at.idx= hybrd.rplc_at.idx(copy(dfN)),
    hybrd.rplc_if    = hybrd.rplc_if(copy(dfN)),
    tidyr_replace_na = tidyr_replace_na(copy(dfN)),
    baseR.for        = baseR.for(copy(dfN)),
    DT.for.set.nms   = DT.for.set.nms(copy(dfN)),
    DT.for.set.sqln  = DT.for.set.sqln(copy(dfN)),
    times = 250L
)

結果摘要

> perf_results
Unit: milliseconds
              expr       min        lq      mean    median        uq      max neval
     hybrid.ifelse 5250.5259 5620.8650 5809.1808 5759.3997 5947.7942 6732.791   250
     dplyr_if_else 3209.7406 3518.0314 3653.0317 3620.2955 3746.0293 4390.888   250
  baseR.sbst.rssgn 1611.9227 1878.7401 1964.6385 1942.8873 2031.5681 2485.843   250
     baseR.replace 1559.1494 1874.7377 1946.2971 1920.8077 2002.4825 2516.525   250
    dplyr_coalesce  949.7511 1231.5150 1279.3015 1288.3425 1345.8662 1624.186   250
 hybrd.rplc_at.nse  735.9949  871.1693 1016.5910 1064.5761 1104.9590 1361.868   250
 hybrd.rplc_at.stw  704.4045  887.4796 1017.9110 1063.8001 1106.7748 1338.557   250
 hybrd.rplc_at.ctn  723.9838  878.6088 1017.9983 1063.0406 1110.0857 1296.024   250
 hybrd.rplc_at.mtc  686.2045  885.8028 1013.8293 1061.2727 1105.7117 1269.949   250
 hybrd.rplc_at.idx  696.3159  880.7800 1003.6186 1038.8271 1083.1932 1309.635   250
     hybrd.rplc_if  705.9907  889.7381 1000.0113 1036.3963 1083.3728 1338.190   250
  tidyr_replace_na  680.4478  973.1395  978.2678 1003.9797 1051.2624 1294.376   250
         baseR.for  670.7897  965.6312  983.5775 1001.5229 1052.5946 1206.023   250
    DT.for.set.nms  496.8031  569.7471  695.4339  623.1086  861.1918 1067.640   250
   DT.for.set.sqln  500.9945  567.2522  671.4158  623.1454  764.9744 1033.463   250

結果Boxplot(以對數為單位)

# adjust the margins to prepare for better boxplot printing
par(mar=c(8,5,1,1) + 0.1) 
# generate boxplot
boxplot(opN, las = 2, xlab = "", ylab = "log(time)[milliseconds]")

試驗的彩色編碼散點圖(以對數表示)

qplot(y=time/10^9, data=opN, colour=expr) + 
    labs(y = "log10 Scaled Elapsed Time per Trial (secs)", x = "Trial Number") +
    scale_y_log10(breaks=c(1, 2, 4))

關於其他高績效員的說明

當數據集變大時, Tidyrreplace_na在歷史上一直排在前面。 使用當前收集的50M數據點,它的性能幾乎與Base R For Loop一樣。 我很好奇看到不同大小的數據框會發生什麼。

有關mutatesummarize _at_all函數變體的其他示例可以在此處找到: https://blog.exploratory.io/dplyr-0-5-is-awesome-heres-why-be095fd4eb8a _all另外,我在此處找到有用的演示和示例集合: https://blog.exploratory.io/dplyr-0-5-is-awesome-heres-why-be095fd4eb8a

歸因和讚賞

特別感謝:

  • Tyler Rinker和Akrun展示 Akrun 。
  • alexis_laz幫助我理解使用local()和(與Frank的耐心幫助一起)沉默壓制在加速這些方法中扮演的角色。
  • ArthurYip為了添加更新的coalesce()函數並更新分析。
  • 格雷戈爾輕輕data.table函數,以便最終將它們包含在該data.table中。
  • Base R For循環: alexis_laz
  • data.table對於循環: Matt_Dowle

(當然,如果你發現這些方法有用,請盡快給予他們提升。

關於使用數字的注意事項:如果您確實有純數據集,則所有函數的運行速度都會更快。 請參閱alexis_laz以獲取更多信息。 IRL,我不記得遇到包含10-15%以上整數的數據集,所以我正在全數字數據框上運行這些測試。


tidyr方法replace_na兼容的另一個dplyr管道兼容選項,適用於多列:

require(dplyr)
require(tidyr)

m <- matrix(sample(c(NA, 1:10), 100, replace = TRUE), 10)
d <- as.data.frame(m)

myList <- setNames(lapply(vector("list", ncol(d)), function(x) x <- 0), names(d))

df <- d %>% replace_na(myList)

您可以輕鬆地限制為例如數字列:

d$str <- c("string", NA)

myList <- myList[sapply(d, is.numeric)]

df <- d %>% replace_na(myList)






na