R Генерация новой переменной на основе условного оператора, примененного ко многим столбцам

Вероятно, есть очевидный и элегантный способ сделать это, вероятно, с помощью lapply, но я все еще осваиваю команды применения и изо всех сил пытаюсь его найти.

У меня есть кадр данных, который выглядит следующим образом, за исключением того, что вместо 5 факторных переменных есть десятки, а вместо 10 строк - сотни.

    a<- data.frame("id" = c(1:10),
                   "a1" = factor(c(0,0,1,1,0,1,0,1,0,1)),
                   "a2" = factor(c(0,0,0,0,0,0,0,0,1,0)), 
                   "a3" = factor(c(0,0,0,0,0,1,0,0,0,0)),
                   "a4" = factor(c(0,0,0,0,0,0,0,0,1,1)), 
                   "a5" = factor(c(0,0,0,1,0,0,0,0,0,0)))

Я хочу создать новую переменную, которая равна 1, если какой-либо из 13 столбцов содержит определенный уровень фактора. Эквивалентом в примере кадра данных будет создание новой переменной с именем «b», равной 1, если в любом из столбцов a1: a4 есть «1», что будет выглядеть следующим образом.

    a<- data.frame("id" = c(1:10),
                   "a1" = factor(c(0,0,1,1,0,1,0,1,0,1)),
                   "a2" = factor(c(0,0,0,0,0,0,0,0,1,0)), 
                   "a3" = factor(c(0,0,0,0,0,1,0,0,0,0)),
                   "a4" = factor(c(0,0,0,0,0,0,0,0,1,1)), 
                   "a5" = factor(c(0,0,0,1,0,0,0,0,0,0)), 
                   "b"  = c(0,0,1,1,0,1,0,1,1,1))

Должен быть способ сделать это, используя 13 позиций столбцов вместо написания условного оператора ifthen для каждой из 13 переменных.


person user2230555    schedule 29.09.2014    source источник
comment
Понятно, что вам нужно изменить форму ваших данных таким образом, чтобы у них был столбец для переменной, который затем является фактором, содержащим a1, a2, a3... и столбец для значения, который содержит все 0 и 1. См. мой ответ здесь для объяснения того, почему это значительно упрощает решение такой проблемы.   -  person David Robinson    schedule 29.09.2014
comment
Спасибо. Ссылка очень полезна. Идентификация столбцов с помощью регулярных выражений работала хорошо.   -  person user2230555    schedule 29.09.2014


Ответы (3)


Просто используйте rowSums, что-то вроде этого:

> as.numeric(rowSums(a[paste0("a", 1:5)] == 1) >= 1)
 [1] 0 0 1 1 0 1 0 1 1 1
person A5C1D2H2I1M1N2O1R2T1    schedule 29.09.2014
comment
(Теперь я вижу, что комментарий Дэвида включает ссылку, которая использует очень похожий подход...) - person A5C1D2H2I1M1N2O1R2T1; 29.09.2014
comment
Я получаю сообщение об ошибке выбора неопределенных столбцов. Дальнейшие мысли? - person user2230555; 29.09.2014
comment
@ user2230555, конечно. Вы пытаетесь выбрать столбцы, которых нет в вашем наборе данных. - person A5C1D2H2I1M1N2O1R2T1; 29.09.2014
comment
Или даже (rowSums(a[-1] == 1) > 0)+0 - person Rich Scriven; 29.09.2014

Если вы хотите попробовать lapply

  Reduce(`|`,lapply(a[,-1], function(x) as.numeric(as.character(x))))+0
  #[1] 0 0 1 1 0 1 0 1 1 1

Или просто

  Reduce(`|`, lapply(a[,-1], `==`, 1)) +0
  #[1] 0 0 1 1 0 1 0 1 1 1

Ориентиры

set.seed(155)
df <- as.data.frame(matrix(sample(0:1, 5000*1e4, replace=TRUE), ncol=5000))

library(microbenchmark)
f1 <- function() {as.numeric(rowSums(df == 1) >= 1) }
f2 <- function() {Reduce(`|`, lapply(df, `==`, 1)) +0}
f3 <- function() {apply(df == 1, 1, function(x) any(x %in% TRUE))+0}

microbenchmark(f1(), f2(), f3(), unit="relative")
# Unit: relative
# expr       min       lq   median       uq      max neval
# f1() 1.000000 1.000000 1.000000 1.000000 1.000000   100
# f2() 1.040561 1.043713 1.053773 1.032932 1.045067   100
# f3() 2.538287 2.517184 2.825253 2.477225 2.454511   100
person akrun    schedule 29.09.2014

Вы также можете использовать any после преобразования матрицы в логическую.

> apply(a[grep("a[1-4]", names(a))] == 1, 1, any)+0
# [1] 0 0 1 1 0 1 0 1 1 1

Or

> apply(a[grepl("a[1-4]", names(a))] == 1, 1, any)+0
# [1] 0 0 1 1 0 1 0 1 1 1
person Rich Scriven    schedule 29.09.2014