I'd untuk menghilangkan garis-garis di data frame yang:
a) mengandung `NA di semua kolom. Di bawah ini adalah contoh data frame.
gene hsap mmul mmus rnor cfam
1 ENSG00000208234 0 NA NA NA NA
2 ENSG00000199674 0 2 2 2 2
3 ENSG00000221622 0 NA NA NA NA
4 ENSG00000207604 0 NA NA 1 2
5 ENSG00000207431 0 NA NA NA NA
6 ENSG00000221312 0 1 2 3 2
Pada dasarnya, saya'd untuk mendapatkan data frame seperti berikut.
gene hsap mmul mmus rnor cfam
2 ENSG00000199674 0 2 2 2 2
6 ENSG00000221312 0 1 2 3 2
b) mengandung `NA hanya dalam beberapa kolom, jadi saya juga bisa mendapatkan hasil seperti ini:
gene hsap mmul mmus rnor cfam
2 ENSG00000199674 0 2 2 2 2
4 ENSG00000207604 0 NA NA 1 2
6 ENSG00000221312 0 1 2 3 2
Juga cek lengkap.kasus
:
> final[complete.cases(final), ]
gene hsap mmul mmus rnor cfam
2 ENSG00000199674 0 2 2 2 2
6 ENSG00000221312 0 1 2 3 2
na.menghilangkan
adalah lebih baik untuk hanya menghapus semua NA
's. lengkap.kasus
memungkinkan seleksi parsial dengan hanya kolom tertentu dari dataframe:
> final[complete.cases(final[ , 5:6]),]
gene hsap mmul mmus rnor cfam
2 ENSG00000199674 0 2 2 2 2
4 ENSG00000207604 0 NA NA 1 2
6 ENSG00000221312 0 1 2 3 2
Solusi anda bisa't bekerja. Jika anda bersikeras menggunakan ini.na
, maka anda harus melakukan sesuatu seperti:
> final[rowSums(is.na(final[ , 5:6])) == 0, ]
gene hsap mmul mmus rnor cfam
2 ENSG00000199674 0 2 2 2 2
4 ENSG00000207604 0 NA NA 1 2
6 ENSG00000221312 0 1 2 3 2
tapi menggunakan lengkap.kasus
cukup banyak lebih jelas, dan lebih cepat.
tidyr
memiliki fungsi baru drop_na
:
library(tidyr)
df %>% drop_na()
# gene hsap mmul mmus rnor cfam
# 2 ENSG00000199674 0 2 2 2 2
# 6 ENSG00000221312 0 1 2 3 2
df %>% drop_na(rnor, cfam)
# gene hsap mmul mmus rnor cfam
# 2 ENSG00000199674 0 2 2 2 2
# 4 ENSG00000207604 0 NA NA 1 2
# 6 ENSG00000221312 0 1 2 3 2
Saya lebih suka cara berikut untuk memeriksa apakah baris berisi NAs:
row.has.na <- apply(final, 1, function(x){any(is.na(x))})
Ini kembali logis vektor dengan nilai-nilai yang menunjukkan apakah ada NA berturut-turut. Anda dapat menggunakannya untuk melihat berapa banyak baris yang anda'll harus drop:
sum(row.has.na)
dan akhirnya menjatuhkan mereka
final.filtered <- final[!row.has.na,]
Untuk menyaring baris dengan bagian tertentu dari NAs itu menjadi sedikit rumit (misalnya, anda dapat memberi makan 'akhir[,5:6]' ke 'menerapkan'). Umumnya, Joris Meys' solusi tampaknya menjadi lebih elegan.
Pilihan lain jika anda ingin kontrol yang lebih besar atas berapa baris yang dianggap tidak valid adalah
final <- final[!(is.na(final$rnor)) | !(is.na(rawdata$cfam)),]
Menggunakan di atas, ini:
gene hsap mmul mmus rnor cfam
1 ENSG00000208234 0 NA NA NA 2
2 ENSG00000199674 0 2 2 2 2
3 ENSG00000221622 0 NA NA 2 NA
4 ENSG00000207604 0 NA NA 1 2
5 ENSG00000207431 0 NA NA NA NA
6 ENSG00000221312 0 1 2 3 2
Menjadi:
gene hsap mmul mmus rnor cfam
1 ENSG00000208234 0 NA NA NA 2
2 ENSG00000199674 0 2 2 2 2
3 ENSG00000221622 0 NA NA 2 NA
4 ENSG00000207604 0 NA NA 1 2
6 ENSG00000221312 0 1 2 3 2
...dimana hanya baris 5 dihapus karena hanya baris yang mengandung NAs untuk investasi rnor
DAN cfam
. Boolean logic kemudian dapat diubah sesuai dengan persyaratan tertentu.
Jika anda ingin kontrol atas berapa banyak NAs yang berlaku untuk setiap baris, mencoba fungsi ini. Bagi banyak survei data set, terlalu banyak kosong tanggapan pertanyaan dapat merusak hasil. Sehingga mereka akan dihapus setelah ambang batas tertentu. Fungsi ini akan memungkinkan anda untuk memilih berapa banyak NAs baris dapat memiliki sebelum's dihapus:
delete.na <- function(DF, n=0) {
DF[rowSums(is.na(DF)) <= n,]
}
Secara default, ini akan menghilangkan semua NAs:
delete.na(final)
gene hsap mmul mmus rnor cfam
2 ENSG00000199674 0 2 2 2 2
6 ENSG00000221312 0 1 2 3 2
Atau menentukan jumlah maksimum NAs diperbolehkan:
delete.na(final, 2)
gene hsap mmul mmus rnor cfam
2 ENSG00000199674 0 2 2 2 2
4 ENSG00000207604 0 NA NA 1 2
6 ENSG00000221312 0 1 2 3 2
data.meja
dan na.menghilangkan()
dengan opsional param cols=
.na.omit.data.table
adalah yang tercepat di benchmark (lihat di bawah), apakah untuk semua kolom atau untuk memilih kolom (OP pertanyaan bagian 2).
data.meja
, gunakan lengkap.kasus()
.Pada vanili data.frame
, complete.cases
lebih cepat dari na.menghilangkan()
atau dplyr::drop_na()
. Perhatikan bahwa na.menghilangkan.data.frame
tidak mendukung cols=
.
Berikut ini adalah perbandingan dari dasar (biru), dplyr
(pink), dan data.tabel` (kuning) metode untuk menjatuhkan baik semua atau pilih pengamatan, pada nosional dataset dari 1 juta pengamatan 20 numerik variabel independen dengan 5% kemungkinan menjadi hilang, dan subset dari 4 variabel untuk bagian 2.
Hasil anda mungkin bervariasi berdasarkan panjang, lebar, dan sparsity tertentu dataset.
Catatan log skala pada sumbu y.
#------- Adjust these assumptions for your own use case ------------
row_size <- 1e6L
col_size <- 20 # not including ID column
p_missing <- 0.05 # likelihood of missing observation (except ID col)
col_subset <- 18:21 # second part of question: filter on select columns
#------- System info for benchmark ----------------------------------
R.version # R version 3.4.3 (2017-11-30), platform = x86_64-w64-mingw32
library(data.table); packageVersion('data.table') # 1.10.4.3
library(dplyr); packageVersion('dplyr') # 0.7.4
library(tidyr); packageVersion('tidyr') # 0.8.0
library(microbenchmark)
#------- Example dataset using above assumptions --------------------
fakeData <- function(m, n, p){
set.seed(123)
m <- matrix(runif(m*n), nrow=m, ncol=n)
m[m<p] <- NA
return(m)
}
df <- cbind( data.frame(id = paste0('ID',seq(row_size)),
stringsAsFactors = FALSE),
data.frame(fakeData(row_size, col_size, p_missing) )
)
dt <- data.table(df)
par(las=3, mfcol=c(1,2), mar=c(22,4,1,1)+0.1)
boxplot(
microbenchmark(
df[complete.cases(df), ],
na.omit(df),
df %>% drop_na,
dt[complete.cases(dt), ],
na.omit(dt)
), xlab='',
main = 'Performance: Drop any NA observation',
col=c(rep('lightblue',2),'salmon',rep('beige',2))
)
boxplot(
microbenchmark(
df[complete.cases(df[,col_subset]), ],
#na.omit(df), # col subset not supported in na.omit.data.frame
df %>% drop_na(col_subset),
dt[complete.cases(dt[,col_subset,with=FALSE]), ],
na.omit(dt, cols=col_subset) # see ?na.omit.data.table
), xlab='',
main = 'Performance: Drop NA obs. in select cols',
col=c('lightblue','salmon',rep('beige',2))
)
Ini akan mengembalikan baris yang memiliki setidaknya SATU non-NA nilai.
final[rowSums(is.na(final))<length(final),]
Ini akan mengembalikan baris yang memiliki setidaknya DUA non-NA nilai.
final[rowSums(is.na(final))<(length(final)-1),]
Untuk pertanyaan pertama, saya memiliki kode yang saya nyaman dengan menyingkirkan semua NAs. Terima kasih untuk @Gregor untuk membuatnya lebih sederhana.
final[!(rowSums(is.na(final))),]
Untuk pertanyaan kedua, kode ini hanya pergantian dari solusi sebelumnya.
final[as.logical((rowSums(is.na(final))-5)),]
Perhatikan -5 adalah jumlah kolom dalam data anda. Hal ini akan menghilangkan baris dengan semua NAs, sejak rowSums menambahkan hingga 5 dan mereka menjadi nol setelah pengurangan. Kali ini, sebagai.logis diperlukan.
Saya synthesizer:). Di sini saya menggabungkan jawaban menjadi salah satu fungsi:
#' keep rows that have a certain number (range) of NAs anywhere/somewhere and delete others
#' @param df a data frame
#' @param col restrict to the columns where you would like to search for NA; eg, 3, c(3), 2:5, "place", c("place","age")
#' \cr default is NULL, search for all columns
#' @param n integer or vector, 0, c(3,5), number/range of NAs allowed.
#' \cr If a number, the exact number of NAs kept
#' \cr Range includes both ends 3<=n<=5
#' \cr Range could be -Inf, Inf
#' @return returns a new df with rows that have NA(s) removed
#' @export
ez.na.keep = function(df, col=NULL, n=0){
if (!is.null(col)) {
# R converts a single row/col to a vector if the parameter col has only one col
# see https://radfordneal.wordpress.com/2008/08/20/design-flaws-in-r-2-%E2%80%94-dropped-dimensions/#comments
df.temp = df[,col,drop=FALSE]
} else {
df.temp = df
}
if (length(n)==1){
if (n==0) {
# simply call complete.cases which might be faster
result = df[complete.cases(df.temp),]
} else {
# credit: http://stackoverflow.com/a/30461945/2292993
log <- apply(df.temp, 2, is.na)
logindex <- apply(log, 1, function(x) sum(x) == n)
result = df[logindex, ]
}
}
if (length(n)==2){
min = n[1]; max = n[2]
log <- apply(df.temp, 2, is.na)
logindex <- apply(log, 1, function(x) {sum(x) >= min && sum(x) <= max})
result = df[logindex, ]
}
return(result)
}
Dengan asumsi dat
sebagai dataframe, output yang diharapkan dapat dicapai dengan menggunakan
1.rowSums
> dat[!rowSums((is.na(dat))),]
gene hsap mmul mmus rnor cfam
2 ENSG00000199674 0 2 2 2 2
6 ENSG00000221312 0 1 2 3 2
2.lapply
> dat[!Reduce('|',lapply(dat,is.na)),]
gene hsap mmul mmus rnor cfam
2 ENSG00000199674 0 2 2 2 2
6 ENSG00000221312 0 1 2 3 2
delete.dirt <- function(DF, dart=c('NA')) {
dirty_rows <- apply(DF, 1, function(r) !any(r %in% dart))
DF <- DF[dirty_rows, ]
}
mydata <- delete.dirt(mydata)
Fungsi di atas akan menghapus semua baris dari data frame yang memiliki 'NA' di setiap kolom dan kembali data yang dihasilkan. Jika anda ingin memeriksa beberapa nilai seperti NA
dan ?
perubahan panah=c('NA')
dalam fungsi param untuk panah=c('NA', '?')
Salah satu pendekatan yang's baik umum dan hasil yang cukup-kode yang dapat dibaca adalah dengan menggunakan filter
fungsi dan variannya di dplyr paket (filter_all
, filter_at
, filter_if
):
library(dplyr)
vars_to_check <- c("rnor", "cfam")
# Filter a specific list of columns to keep only non-missing entries
df %>%
filter_at(.vars = vars(one_of(vars_to_check)),
~ !is.na(.))
# Filter all the columns to exclude NA
df %>%
filter_all(~ !is.na(.))
# Filter only numeric columns
df %>%
filter_if(is.numeric,
~ !is.na(.))
Dugaan saya adalah bahwa ini bisa menjadi lebih elegan diselesaikan dengan cara ini
m <- matrix(1:25, ncol = 5)
m[c(1, 6, 13, 25)] <- NA
df <- data.frame(m)
library(dplyr)
df %>%
filter_all(any_vars(is.na(.)))
#> X1 X2 X3 X4 X5
#> 1 NA NA 11 16 21
#> 2 3 8 NA 18 23
#> 3 5 10 15 20 NA