Mam plik data.frame zawierający kilka kolumn ze wszystkimi wartościami NA, jak mogę je usunąć z data.frame.
Czy mogę skorzystać z funkcji
na.omit(...)
określając dodatkowe argumenty?
Mam plik data.frame zawierający kilka kolumn ze wszystkimi wartościami NA, jak mogę je usunąć z data.frame.
Czy mogę skorzystać z funkcji
na.omit(...)
określając dodatkowe argumenty?
head(data)
? Czy chcesz usunąć odpowiednie kolumny lub wiersze?
Odpowiedzi:
Jeden sposób na zrobienie tego:
df[, colSums(is.na(df)) != nrow(df)]
Jeśli liczba NA w kolumnie jest równa liczbie wierszy, musi to być w całości NA.
Lub podobnie
df[colSums(!is.na(df)) > 0]
df[, colSums(is.na(df)) < nrow(df) * 0.5]
np. Zachować tylko kolumny zawierające co najmniej 50% wartości niepustych.
df[, colSums(is.na(df)) != nrow(df) - 1]
ponieważ przekątna to zawsze1
df %>% select_if(colSums(!is.na(.)) > 0)
Oto rozwiązanie dplyr:
df %>% select_if(~sum(!is.na(.)) > 0)
Aktualizacja:summarise_if()
funkcja została zastąpiona z dniem dplyr 1.0
. Oto dwa inne rozwiązania, które wykorzystują funkcję where()
tidyselect:
df %>%
select(
where(
~sum(!is.na(.x)) > 0
)
)
df %>%
select(
where(
~!all(is.na(.x))
)
)
janitor::remove_empty_cols()
jest przestarzałe - użyjdf <- janitor::remove_empty(df, which = "cols")
Wygląda na to, że chcesz usunąć TYLKO kolumny ze WSZYSTKIMI NA
s, pozostawiając kolumny z wierszami, które mają NA
s. Zrobiłbym to (ale jestem pewien, że istnieje wydajne rozwiązanie wektoryzowane:
#set seed for reproducibility
set.seed <- 103
df <- data.frame( id = 1:10 , nas = rep( NA , 10 ) , vals = sample( c( 1:3 , NA ) , 10 , repl = TRUE ) )
df
# id nas vals
# 1 1 NA NA
# 2 2 NA 2
# 3 3 NA 1
# 4 4 NA 2
# 5 5 NA 2
# 6 6 NA 3
# 7 7 NA 2
# 8 8 NA 3
# 9 9 NA 3
# 10 10 NA 2
#Use this command to remove columns that are entirely NA values, it will elave columns where only some vlaues are NA
df[ , ! apply( df , 2 , function(x) all(is.na(x)) ) ]
# id vals
# 1 1 NA
# 2 2 2
# 3 3 1
# 4 4 2
# 5 5 2
# 6 6 3
# 7 7 2
# 8 8 3
# 9 9 3
# 10 10 2
Jeśli znajdziesz się w sytuacji, w której chcesz usunąć kolumny, które mają jakiekolwiek NA
wartości, możesz po prostu zmienić all
powyższe polecenie na any
.
NA
.
apply(is.na(df), 1, all)
tylko dlatego, że jest nieco schludniejszy i is.na()
jest używany we wszystkich df
wierszach, a nie w jednym na raz (pokaż trochę szybciej).
Intuicyjny skrypt: dplyr::select_if(~!all(is.na(.)))
. Dosłownie zachowuje tylko kolumny, w których brakuje nie wszystkich elementów. (aby usunąć wszystkie brakujące kolumny).
> df <- data.frame( id = 1:10 , nas = rep( NA , 10 ) , vals = sample( c( 1:3 , NA ) , 10 , repl = TRUE ) )
> df %>% glimpse()
Observations: 10
Variables: 3
$ id <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
$ nas <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA
$ vals <int> NA, 1, 1, NA, 1, 1, 1, 2, 3, NA
> df %>% select_if(~!all(is.na(.)))
id vals
1 1 NA
2 2 1
3 3 1
4 4 NA
5 5 1
6 6 1
7 7 1
8 8 2
9 9 3
10 10 NA
Ponieważ wydajność była dla mnie naprawdę ważna, przetestowałem wszystkie powyższe funkcje.
UWAGA: Dane z posta @Simon O'Hanlon. Tylko w rozmiarze 15000 zamiast 10.
library(tidyverse)
library(microbenchmark)
set.seed(123)
df <- data.frame(id = 1:15000,
nas = rep(NA, 15000),
vals = sample(c(1:3, NA), 15000,
repl = TRUE))
df
MadSconeF1 <- function(x) x[, colSums(is.na(x)) != nrow(x)]
MadSconeF2 <- function(x) x[colSums(!is.na(x)) > 0]
BradCannell <- function(x) x %>% select_if(~sum(!is.na(.)) > 0)
SimonOHanlon <- function(x) x[ , !apply(x, 2 ,function(y) all(is.na(y)))]
jsta <- function(x) janitor::remove_empty(x)
SiboJiang <- function(x) x %>% dplyr::select_if(~!all(is.na(.)))
akrun <- function(x) Filter(function(y) !all(is.na(y)), x)
mbm <- microbenchmark(
"MadSconeF1" = {MadSconeF1(df)},
"MadSconeF2" = {MadSconeF2(df)},
"BradCannell" = {BradCannell(df)},
"SimonOHanlon" = {SimonOHanlon(df)},
"SiboJiang" = {SiboJiang(df)},
"jsta" = {jsta(df)},
"akrun" = {akrun(df)},
times = 1000)
mbm
Wyniki:
Unit: microseconds
expr min lq mean median uq max neval cld
MadSconeF1 154.5 178.35 257.9396 196.05 219.25 5001.0 1000 a
MadSconeF2 180.4 209.75 281.2541 226.40 251.05 6322.1 1000 a
BradCannell 2579.4 2884.90 3330.3700 3059.45 3379.30 33667.3 1000 d
SimonOHanlon 511.0 565.00 943.3089 586.45 623.65 210338.4 1000 b
SiboJiang 2558.1 2853.05 3377.6702 3010.30 3310.00 89718.0 1000 d
jsta 1544.8 1652.45 2031.5065 1706.05 1872.65 11594.9 1000 c
akrun 93.8 111.60 139.9482 121.90 135.45 3851.2 1000 a
autoplot(mbm)
mbm %>%
tbl_df() %>%
ggplot(aes(sample = time)) +
stat_qq() +
stat_qq_line() +
facet_wrap(~expr, scales = "free")