data.frame에서 모든 또는 일부 NA (결 측값)가있는 행 제거
이 데이터 프레임에서 다음과 같은 줄을 제거하고 싶습니다.
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) 일부 열에 만 s를 포함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
좋습니다. 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
은 훨씬 더 명확하고 빠릅니다.
시도해보십시오 na.omit(your.data.frame)
. 두 번째 질문에 대해서는 다른 질문으로 게시 해보십시오 (명확성을 위해).
tidyr
새로운 기능이 있습니다 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
행에 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
AND 둘 다에 대한 NA를 포함하는 유일한 행이기 때문에 제거됩니다 cfam
. 그런 다음 특정 요구 사항에 맞게 부울 논리를 변경할 수 있습니다.
각 행에 유효한 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
성능이 우선이라면 data.table
및 na.omit()
옵션 param 과 함께 사용하십시오 cols=
.
na.omit.data.table
모든 열 또는 일부 열 (OP 질문 파트 2)에 대해 내 벤치 마크 (아래 참조)에서 가장 빠릅니다.
을 사용하지 않으려면을 data.table
사용하십시오 complete.cases()
.
바닐라 data.frame
에서는 또는 complete.cases
보다 빠릅니다 . 을 지원하지 않습니다 .na.omit()
dplyr::drop_na()
na.omit.data.frame
cols=
벤치 마크 결과
다음은 누락 될 가능성이 독립적 인 5 % 인 20 개의 숫자 변수에 대한 100 만 개의 관측치에 대한 개념적 데이터 세트에서 모든 또는 일부 누락 된 관측치를 삭제 하는 기본 (파란색), 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))
)
dplyr 패키지를 사용하여 다음과 같이 NA를 필터링 할 수 있습니다.
dplyr::filter(df, !is.na(columnname))
이렇게하면 NA가 아닌 값이 하나 이상있는 행이 반환됩니다.
final[rowSums(is.na(final))<length(final),]
이렇게하면 NA가 아닌 값이 2 개 이상있는 행이 반환됩니다.
final[rowSums(is.na(final))<(length(final)-1),]
For your first question, I have a code that I am comfortable with to get rid of all NAs. Thanks for @Gregor to make it simpler.
final[!(rowSums(is.na(final))),]
For the second question, the code is just an alternation from the previous solution.
final[as.logical((rowSums(is.na(final))-5)),]
Notice the -5 is the number of columns in your data. This will eliminate rows with all NAs, since the rowSums adds up to 5 and they become zeroes after subtraction. This time, as.logical is necessary.
We can also use the subset function for this.
finalData<-subset(data,!(is.na(data["mmul"]) | is.na(data["rnor"])))
This will give only those rows that do not have NA in both mmul and rnor
I am a synthesizer:). Here I combined the answers into one function:
#' 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)
}
Assuming dat
as your dataframe, the expected output can be achieved using
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)
위 함수는 모든 열에 'NA'가있는 데이터 프레임에서 모든 행을 삭제하고 결과 데이터를 반환합니다. 여러 개의 같은 값을 확인하려면 NA
및 ?
변경 dart=c('NA')
기능 PARAM의에dart=c('NA', '?')
두 장군이고 공정하게 읽을 수있는 코드를 산출 한 가지 방법은 사용하는 filter
기능과 dplyr 패키지 그 변종을 ( 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(.))
내 생각 엔 이런 식으로 좀 더 우아하게 해결할 수있을 것 같아
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
'programing' 카테고리의 다른 글
Assert를 사용하여 예외가 발생했는지 확인하려면 어떻게합니까? (0) | 2020.09.29 |
---|---|
루비에서 난수를 얻는 방법 (0) | 2020.09.29 |
이전 커밋이 아닌 특정 커밋을 원격으로 푸시하려면 어떻게해야합니까? (0) | 2020.09.29 |
이진 세마포어와 뮤텍스의 차이점 (0) | 2020.09.29 |
JavaScript에서 문자열이 같은지 확인하는 올바른 방법은 무엇입니까? (0) | 2020.09.29 |