このデータフレームで、以下のような行を削除したいのです:
a) すべての列でNA
を含む。以下は私のデータフレーム例です。
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
基本的には、以下のようなデータフレームを取得したいのですが。
gene hsap mmul mmus rnor cfam
2 ENSG00000199674 0 2 2 2 2
6 ENSG00000221312 0 1 2 3 2
b) 一部のカラムにのみNA
を含む、この結果も得ることができる:
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
また、complete.cases
もご確認ください:
> 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.omitは、すべての
NA's を削除するのに適しています。complete.cases
は、データフレームの特定のカラムのみを含むことで部分選択を可能にする:
> 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
あなたの解決策はうまくいきません。もし、どうしてもis.na
を使いたいのであれば、次のようなことをしなければなりません:
> 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
が、complete.cases
を使ったほうが、かなりわかりやすく、スピードも速いです。
tidyr
には新しい関数[drop_na
]があります(https://blog.rstudio.org/2016/08/15/tidyr-0-6-0/):
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
行にNAが含まれているかどうかをチェックする方法は、次のようなものがあります:
row.has.na <- apply(final, 1, function(x){any(is.na(x))})
これは、ある行にNAがあるかどうかを示す値を持つ論理ベクトルを返します。これを使えば、何行を削除しなければならないかを確認することができます:
sum(row.has.na)
で、最終的に落とす
final.filtered <- final[!row.has.na,]
特定のNAを持つ行をフィルタリングする場合は、少し厄介になります(例えば、 'final[,5:6]' を 'apply' に送ることができます)。 一般的には、Joris Meys'のソリューションの方がよりエレガントだと思われます。
行が無効であると見なされる方法をより詳細に制御したい場合は、別のオプションがあります。
final <- final[!(is.na(final$rnor)) | !(is.na(rawdata$cfam)),]
上記を使用して、これ:
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
なる:
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
.ここで、行5のみが削除されます。これは、「rnor」と「cfam」の両方のNAを含む唯一の行であるためです。. 次に、ブールロジックを変更して、特定の要件に適合させることができます。
各行に有効なNAの数を制御する場合は、この機能を試してください。 多くの調査データセットでは、空白の質問の回答が多すぎると結果が台無しになる可能性があります。 したがって、特定のしきい値の後に削除されます。 この関数を使用すると、行が削除される前に実行できるNAの数を選択できます。
delete.na <- function(DF, n=0) {
DF[rowSums(is.na(DF)) <= n,]
}
デフォルトでは、すべてのNA:を排除します。
delete.na(final)
gene hsap mmul mmus rnor cfam
2 ENSG00000199674 0 2 2 2 2
6 ENSG00000221312 0 1 2 3 2
または、許可されるNAの最大数を指定します。
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
cols =
を使用して、 data.table
およびna.omit()
を使用します。na.omit.data.table
は最速です私のベンチマーク(以下を参照)、すべての列または選択した列(OP質問パート2)。
data.table
を使用しない場合は、complete.cases()
を使用します。バニラ data.frame
では、complete.cases
は[na .omit()
](https:/www.rdocumentation.org/packages/3.4. na.omit.data.frame
は cols =
をサポートしていないことに注意してください。
以下は、20の数値変数の100万の観測値と独立した5の観測値の想定データセットで、すべてまたは欠落観測値を選択するためのベース(青)、 dplyr
(ピンク)、および data.table
(黄色)メソッドの比較です。欠落する可能性の割合、およびパート2の4つの変数のサブセット。
結果は、特定のデータセットの長さ、幅、およびスパーシティに基づいて異なる場合があります。
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))
)
最初の質問については、すべてのNAを取り除くために快適なコードがあります。 @Gregorをシンプルにしてくれてありがとう。
final[!(rowSums(is.na(final))),]
2番目の質問では、コードは以前のソリューションからの単なる代替です。
final[as.logical((rowSums(is.na(final))-5)),]
-5はデータの列数であることに注意してください。 rowSumsの合計が5になり、減算後にゼロになるため、これによりすべてのNAを持つ行が排除されます。 今回は、as.logicalが必要です。
私はシンセサイザーです:)。 ここで、回答を1つの関数に結合しました。
#' 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)
}
データフレームとして「dat」を想定すると、期待出力はを使用して達成できます。
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。幸せ
。
> 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)
上記の関数は、任意の列に「NA」があるデータフレームからすべての行を削除し、結果として得られるデータを返します。 NA
やのような複数の値を確認したい場合?
関数paramの dart = c( 'NA')
を dart = c( 'NA'、 'に変更します?')
。
一般的でかなり読みやすいコードを生成する1つのアプローチは、dplyrパッケージで「filter」関数とそのバリアントを使用することです(「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(.))