Jak mogę usunąć kolumny mające więcej niż próg NA? czy w procentach (powiedzmy powyżej 50%)?
discipulus
2
@lovedynasty Prawdopodobnie najlepiej przesłać osobne pytanie, zakładając, że nie zostało to jeszcze zrobione od czasu opublikowania komentarza. Ale tak czy inaczej, zawsze możesz zrobić coś takiego, jak df[, colSums(is.na(df)) < nrow(df) * 0.5]np. Zachować tylko kolumny zawierające co najmniej 50% wartości niepustych.
Ciarán Tobin
2
Osoby pracujące z macierzą korelacji muszą używać, df[, colSums(is.na(df)) != nrow(df) - 1]ponieważ przekątna to zawsze1
Boern
9
Można tego również użyć z funkcją dplyr (wersja 0.5.0) select_if. df %>% select_if(colSums(!is.na(.)) > 0)
Stefan Avey
@MadScone daje mi błąd składni na "," dla df [, colSums (is.na (df))! = Nrow (df)] i błąd składni na "!" w df [colSums (! is.na (df))> 0]. Czy czegoś mi brakuje
Aravind S
53
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:
janitor::remove_empty_cols()jest przestarzałe - użyjdf <- janitor::remove_empty(df, which = "cols")
André.B
24
Wygląda na to, że chcesz usunąć TYLKO kolumny ze WSZYSTKIMINA s, pozostawiając kolumny z wierszami, które mają NAs. 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 NAwartości, możesz po prostu zmienić allpowyższe polecenie na any.
Data.frame posiada dwa rodzaje kolumn: jeden w whohc wszystkie wartości są liczbami, a drugi, w którym wszystkie wartości są NA
Lorenzo Rigamonti
Więc to zadziała. Usuwa tylko kolumny, w których są WSZYSTKIE wartości NA.
Simon O'Hanlon,
1
Dobre rozwiązanie. Zrobiłbym to apply(is.na(df), 1, all)tylko dlatego, że jest nieco schludniejszy i is.na()jest używany we wszystkich dfwierszach, a nie w jednym na raz (pokaż trochę szybciej).
Ciarán Tobin
@MadScone dobra wskazówka - wygląda schludniej. Należy jednak zastosować w kolumnach, a nie wierszach.
Simon O'Hanlon
@MadScone Edycje są blokowane po 5 minutach od komentarzy. Nie powinienem się martwić, to nic wielkiego !! :-)
Simon O'Hanlon
20
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
11NA22133144NA5516617718829931010NA
Unit: microseconds
expr min lq mean median uq max neval cld
MadSconeF1 154.5178.35257.9396196.05219.255001.01000 a
MadSconeF2 180.4209.75281.2541226.40251.056322.11000 a
BradCannell 2579.42884.903330.37003059.453379.3033667.31000 d
SimonOHanlon 511.0565.00943.3089586.45623.65210338.41000 b
SiboJiang 2558.12853.053377.67023010.303310.0089718.01000 d
jsta 1544.81652.452031.50651706.051872.6511594.91000c
akrun 93.8111.60139.9482121.90135.453851.21000 a
autoplot(mbm)
Czasami pierwsza iteracja jest skompilowana w JIT, więc ma bardzo słabe i niezbyt charakterystyczne czasy. Myślę, że interesujące jest to, co większy rozmiar próbki robi z właściwymi ogonami rozkładu. To dobra robota.
EngrStudent
Uruchomiłem go jeszcze raz, nie byłem pewien, czy zmieniłem fabułę. Jeśli chodzi o dystrybucję, rzeczywiście. Powinienem prawdopodobnie porównać różne rozmiary próbek, kiedy będę miał czas.
DJV
1
jeśli qqplot ( ggplot2.tidyverse.org/reference/geom_qq.html ) jeden z trendów, taki jak „akrun”, to założę się, że jest jeden punkt, który bardzo różni się od dystrybucji pozostałych. Reszta przedstawia, ile czasu potrzeba, jeśli uruchomisz go wielokrotnie, ale to pokazuje, co się stanie, jeśli uruchomisz go raz. Jest takie stare powiedzenie: możesz mieć 20-letnie doświadczenie lub możesz mieć tylko roczne doświadczenie 20 razy.
EngrStudent
bardzo dobrze! Jestem zaskoczony, że kilka próbek znajduje się w skrajnym ogonie. Zastanawiam się, dlaczego są one o wiele droższe. JIT może wynosić 1 lub 2, ale nie 20. Warunek? Przerwania? Inny? Jeszcze raz dziękuję za aktualizację.
EngrStudent
Nie ma za co, dziękuję za przemyślenia. Nie wiem, faktycznie pozwoliłem mu działać „swobodnie”.
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]
źródło
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 dniemdplyr 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)) ) )
źródło
Inną opcją jest
janitor
pakiet:https://github.com/sfirke/janitor
źródło
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 naany
.źródło
NA
.apply(is.na(df), 1, all)
tylko dlatego, że jest nieco schludniejszy iis.na()
jest używany we wszystkichdf
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
źródło
Inna opcja z
Filter
Filter(function(x) !all(is.na(x)), df)
UWAGA: Dane z posta @Simon O'Hanlon.
źródło
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")
źródło