применять условно к двум группам столбцов в рамках датафрейма - PullRequest
1 голос
/ 04 июня 2019

У меня есть df:

a<-c(5,1,5,3,5,3,5,1)
b<-c(1,5,1,5,1,5,3,5)

df<-as.data.frame(rbind(a,b))
names(df)<-c('pre1','post1','pre2','post2','pre3','post3','pre4','post4')

И у меня есть две группы сэмплов в столбцах, например, 'pre' и post ':

pre<-seq(1,8,by=2)
post<-seq(2,8,by=2)

Я хотел бы применить условие, что 100% до и 50% после прохождения ИЛИ 50% до и 100% после

например

если 100% 'pre' равны 3 или более, а 50% post - 3 или более ИЛИ ЖЕ если 50% 'pre' - 3 или более, а 100% post - 3 или более, оставьте строку поэтому в примере df останется только строка 'a'

У меня есть:

test<- ((df[apply(df[pre],1,function(x) sum(x>=3)/length(x)),] & 
         df[apply(df[post],1,function(x) sum(x>3)/length(x))>=0.5,]) | 
        (df[apply(df[pre],1,function(x) sum(x>3)/length(x))>=0.5,] & 
         df[apply(df[post],1,function(x) sum(x>3)/length(x)),]))

Но я получаю вектор «ИСТИНА», а это не то, что я хочу.

Ответы [ 4 ]

2 голосов
/ 04 июня 2019

Вот гораздо менее сжатое решение, которое может быть существенно сокращено.

library(tidyverse)
pass_val = 3
df %>%
  rownames_to_column() %>%
  gather(col, val, -rowname) %>%
  separate("col", c("type", "num"), sep = -1) %>%
  count(rowname, type, pass = val >= pass_val) %>%
  spread(pass, n, fill = 0) %>%
  transmute(rowname, type, pass_pct = `TRUE`/(`TRUE` + `FALSE`)) %>%
  spread(type, pass_pct) %>%
  filter(post == 1 & pre >= 0.5 | post >= 0.5 & pre == 1)
2 голосов
/ 04 июня 2019

Мы можем создать логический вектор для сравнения, используя rowSums

df[(rowSums(df[pre] >= 3)/length(pre) == 1) & 
    (rowSums(df[post] >= 3)/length(post) >= 0.5) |
    (rowSums(df[post] >= 3)/length(post) == 1) & 
    (rowSums(df[pre] >= 3)/length(pre) >= 0.5), ]

#  pre1 post1 pre2 post2 pre3 post3 pre4 post4
#a    5     1    5     3    5     3    5     1

Используя apply, мы можем сделать

df[apply(df[pre] >= 3, 1, all) & apply(df[post] >= 3, 1, sum)/length(post) >= 0.5 |
   apply(df[post] >= 3, 1, all) & apply(df[pre] >= 3, 1, sum)/length(pre) >= 0.5, ]
0 голосов
/ 04 июня 2019

Вот базовое решение R, которое разбивает по имени строки, проверяет условия с помощью sapply и использует вывод в качестве логического индекса для df:

df[sapply(split(df, rownames(df)), function(x) {
    (sum(x[pre] > 2)/ncol(x[pre]) >= .5) & (sum(x[post] > 2)/ncol(x[post]) == 1) ||
    (sum(x[pre] > 2)/ncol(x[pre]) == 1) & (sum(x[post] > 2)/ncol(x[post]) >= .5)
}),]

#### OUTPUT ####

  pre1 post1 pre2 post2 pre3 post3 pre4 post4
a    5     1    5     3    5     3    5     1
0 голосов
/ 04 июня 2019

Вот один вариант с tidyverse

library(tidyverse)
library(rap)
crossing(val = c(0.5, 1), cols = c("pre", "post")) %>%
   rap(x = ~ df %>% 
                 select(matches(cols)) %>%
                 {rowMeans(. >=3) >= val}) %>%
                 group_by(val) %>% 
                 transmute(ind = reduce(x, `&`)) %>% 
                 filter(any(ind)) %>% 
                 pull(ind) %>% 
   filter(df, .)
#  pre1 post1 pre2 post2 pre3 post3 pre4 post4
#1    5     1    5     3    5     3    5     1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...