Фильтрация строк в data.frame на основе длины значений во всех группах - PullRequest
2 голосов
/ 30 июня 2019

У меня есть data.frame, подобный этому:

df<-data.frame( Id = paste0("g",1:6),
a= c(6:11),
b = c(10:13,NA,NA),
c = c(7:10,NA,10),
d = c(NA,7:9,NA,13),
e= c(NA,6:10),
f= c(NA,NA,NA,4:5,NA))
colnames(df)=c("ID",rep("normal",3),rep("patient",3))

> df
  ID normal normal normal patient patient patient
1 g1      6     10      7      NA      NA      NA
2 g2      7     11      8       7       6      NA
3 g3      8     12      9       8       7      NA
4 g4      9     13     10       9       8       4
5 g5     10     NA     NA      NA       9       5
6 g6     11     NA     10      13      10      NA

этот df содержит данные для двух групп (нормальных и пациентов). Я собираюсь выполнить некоторый анализ для всех строк, поэтому все группы в каждомстроки должны иметь как минимум два значения. Я использовал следующие коды для фильтрации строк, чтобы во всех группах не было как минимум двух значений.

    fx=function(x){length(x[!is.na(x)])>=2}
    f1=apply(df[,2:4], 1,fx)#filter based on group normal
    f2=apply(df[,5:7], 1,fx)#filter based on group patient
    df=subset(df,f1&f2)
> df
  ID normal normal.1 normal.2 patient patient.1 patient.2
2 g2      7       11        8       7         6        NA
3 g3      8       12        9       8         7        NA
4 g4      9       13       10       9         8         4
6 g6     11       NA       10      13        10        NA

, но эти коды полезны для данных с ограниченными группами.мои основные данные содержат 100 групп (и во всех группах по 3 копии), colnames(df)=paste0("grp",sort(rep(1:100,3))), поэтому мне нужны простые коды для фильтрации строк в фрейме данных с 100 группами.

моя цель: удалитьстроки, которые имеют не менее двух значений в каждой группе.

Ответы [ 3 ]

3 голосов
/ 30 июня 2019

Может сделать:

library(dplyr)

names(df) <- paste0(names(df), 1:ncol(df))

df %>%
  filter(
    rowSums(!is.na(select(., contains("normal")))) >= 2 &
      rowSums(!is.na(select(., contains("patient")))) >= 2
  )
2 голосов
/ 30 июня 2019

Мы могли бы различать столбцы "normal" и "patient" и выбирать строки, используя rowSums

normal_cols <- grep("normal", names(df))
patient_cols <- grep("patient", names(df))
df[rowSums(!is.na(df[normal_cols])) >= 2 & rowSums(!is.na(df[patient_cols])) >= 2,]

#  ID normal normal normal patient patient patient
#2 g2      7     11      8       7       6      NA
#3 g3      8     12      9       8       7      NA
#4 g4      9     13     10       9       8       4
#6 g6     11     NA     10      13      10      NA

. Или используя определенную вами функцию fx, мы можем использовать applyдважды на оба набора столбцов и выберите строки, используя subset.

fx = function(x) {length(x[!is.na(x)])>=2}
subset(df, apply(df[normal_cols], 1,fx) & apply(df[patient_cols], 1,fx))
1 голос
/ 30 июня 2019

Мы можем использовать reshape, чтобы получить длинный формат и взглянуть на colSums.

Первое правило в таких вопросах - это приложение R опиатные имена столбцов, то есть <chr_prefix>.<num_suffix>.

names(df) <- c("ID", paste(rep(c("normal", "patient"), each=3), 1:3, sep="."))

Теперь мы reshape в длинном формате и разделим by "ID".Нам нужны только те идентификаторы, в которых all colSums равны > 2, мы сохраняем их в векторе s, с которым мы можем поднастроить фрейм данных df.

r <- reshape(df, idvar="ID", direction="long", varying=list(2:4, 5:7), times=1:3)
s <- by(r[-1], r$ID, function(i) all(colSums(i, na.rm=TRUE) > 2))
df[s, ]
#   ID normal normal normal patient patient patient
# 2 g2      7     11      8       7       6      NA
# 3 g3      8     12      9       8       7      NA
# 4 g4      9     13     10       9       8       4
# 6 g6     11     NA     10      13      10      NA

Данные

df <- structure(list(Id = structure(1:6, .Label = c("g1", "g2", "g3", 
"g4", "g5", "g6"), class = "factor"), a = 6:11, b = c(10L, 11L, 
12L, 13L, NA, NA), c = c(7, 8, 9, 10, NA, 10), d = c(NA, 7, 8, 
9, NA, 13), e = c(NA, 6L, 7L, 8L, 9L, 10L), f = c(NA, NA, NA, 
4L, 5L, NA)), class = "data.frame", row.names = c(NA, -6L))
...