2011-12-14 3 views
4

У меня есть dataframe с четырьмя логическими векторами, v1, v2, v3, v4, которые ИСТИНА или ЛОЖЬ. Мне нужно классифицировать каждую строку dataframe на основе комбинации из булевых векторов (например, «None», «v1 только», «v1 и v3», «Все», и т.д.). Я хотел бы сделать это, не взяв подмножество фрейма данных или вложенные операторы ifelse. Любые предложения по наилучшему способу сделать это? Благодаря!Сравнение булевых векторов

ответ

3

Похоже, я Арри поздно на этой вечеринке. Тем не менее, я мог бы также поделиться тем, что я принес!

Это работает путем обработки FALSE/TRUE возможности, как биты, и работающие на них, чтобы присвоить каждой комбинации v1, v2 и v3 уникальное число от 1 до 8 (так же, как chmod может представлять биты разрешения на *NIX системах). Затем целое число используется как индекс для выбора соответствующего элемента вектора текстовых дескрипторов.

(Для демонстрации я использовал только три колонки, но этот подход масштабируется хорошо.)

# CONSTRUCT VECTOR OF DESCRIPTIONS 
description <- c("None", "v1", "v2", "v1 and v2", 
       "v3", "v1 and v3", "v2 and v3", "All") 

# DEFINE DESCRIPTION FUNCTION 
getDescription <- function(X) { 
    index <- 1 + sum(X*c(1,2,4)) 
    description[index] 
} 

# TRY IT OUT ON ALL COMBOS OF v1, v2, and v3 
df <- expand.grid(v1=c(FALSE, TRUE), 
        v2=c(FALSE, TRUE), 
        v3=c(FALSE, TRUE)) 
df$description <- apply(df, 1, getDescription) 

# YEP, IT WORKS. 
df 
#  v1 v2 v3 description 
# 1 FALSE FALSE FALSE  None 
# 2 TRUE FALSE FALSE   v1 
# 3 FALSE TRUE FALSE   v2 
# 4 TRUE TRUE FALSE v1 and v2 
# 5 FALSE FALSE TRUE   v3 
# 6 TRUE FALSE TRUE v1 and v3 
# 7 FALSE TRUE TRUE v2 and v3 
# 8 TRUE TRUE TRUE   All 
+0

Спасибо! Если я добавлю 'df $ v3 <- TRUE', а затем попробую запустить ' df $ description <- apply (df, 1, getDescription) 'снова, я получаю следующую ошибку: ** Ошибка в X * c (1, 2, 4): нечисловой аргумент для двоичного оператора ** Любые идеи, почему это происходит? Благодаря! –

+0

@BoomShakalaka - Это прекрасно работает для меня. Возможно, вы назначили «TRUE» вместо «TRUE»? Ваше сообщение об ошибке означает, что один столбец в вашем файле data.frame не является числовым. Кроме того, ваш 'df' имеет больше, чем только три столбца? Если это так, вам нужно будет выполнить «apply» (df [c («v1», «v2», «v3»)], 1, getDescription). Надеюсь, это поможет. –

+0

Существует еще один столбец, который не является числовым, так что это проблема. Благодаря! –

3

Вот один из подходов, основанный на том, что TRUE/FALSE может быть представлен как 0s и 1s. Вы можете умножить логические значения на их индекс столбца, а затем вставить все значения вместе. Это скажет вам, какие столбцы имели значение 1 для каждой строки. Вот пример:

set.seed(1) 
dat <- data.frame(v1 = sample(c(T,F), 10, TRUE), 
        v2 = sample(c(T,F), 10, TRUE), 
        v3 = sample(c(T,F), 10, TRUE), 
        v4 = sample(c(T,F), 10, TRUE) 
       ) 
#End fake data 
#Multiple T/F times the column index 
dat <- dat * rep(seq_len(ncol(dat)), each = nrow(dat)) 
#Paste together in a new column 
dat$v5 <- apply(dat, 1, function(x) paste(x, collapse = "")) 

> dat 
    v1 v2 v3 v4 v5 
1 0 0 3 4 0034 
2 0 2 0 4 0204 
... 

Включает полезные замечания ниже и дополнительный вопрос

Я хотел бы создать таблицу поиска с помощью expand.grid(), а затем записать текстовые метки, чтобы представить их, как вы считаете нужным. Вот пример с двумя колонками:

set.seed(1) 
dat <- data.frame(v1 = sample(c(T,F), 10, TRUE), 
        v2 = sample(c(T,F), 10, TRUE) 
     ) 

#Thanks @Joshua 
dat$comp <- as.character(apply(1 * dat, 1, paste, collapse="")) 

#Look up table 
lookup <- data.frame(comp = apply(expand.grid(0:1, 0:1), 1, paste, collapse = ""), 
        text = c("none", "v1 only", "v2 only", "all"), 
        stringsAsFactors = FALSE 
) 

#Use merge to join the look up table to your data. Note the consistent naming of the comp column 
> merge(dat, lookup) 
    comp v1 v2 text 
1 00 FALSE FALSE none 
2 00 FALSE FALSE none 
3 01 FALSE TRUE v2 only 
.... 
+0

+1 Красиво сделано. Другим вариантом, также использующим представление 0/1, было бы умножение каждого на мощность 10 и добавление; это можно сделать с помощью умножения на матрицу, например, 'as.matrix (dat)% *% 10^rev (seq_len (ncol (dat)) - 1)'. (Или используйте мощность 2, если вы предпочитаете думать в двоичном формате.) – Aaron

+1

+1, но я не вижу необходимости в «индексе столбца», так как он определяется положением '1' в строке. Альтернативы были бы "apply (1 * dat, 1, paste, collapse =" ")' или 'do.call (paste, c (1 * dat, sep =" "))'. –

+0

Спасибо.Поэтому, основываясь на вашем ответе, я думаю о следующем: 'v1 <- ifelse (v1 == TRUE, 1000, 0)' 'v2 <- ifelse (v1 == TRUE, 100, 0)' 'v3 <- ifelse (v1 == TRUE, 10, 0) '' v4 <- ifelse (v1 == TRUE, 1, 0) '' dat $ v5 <- sum (v1, v2, v3, v4) 'Должен ли я затем создать список значений для поиска метки (например, 1111 == «Все») или есть лучший способ? –

1
set.seed(123) 
> dat <- data.frame(v1 = sample(c(T,F), 10, TRUE), 
+     v2 = sample(c(T,F), 10, TRUE), 
+     v3 = sample(c(T,F), 10, TRUE), 
+     v4 = sample(c(T,F), 10, TRUE) 
+     ) 
> dat 

Первой стратегией использует различные комбинации шаблонов для индексации в вектор символа с дефолтом от 1 до индекса «Другого»:

> dat$bcateg <- c("Other", "v2 only", "v1 and v3", "All")[1+ 
+ with(dat, 1*(v2 & !v1 &!v3 &!v4)) 
+ +with(dat, 2*(v1&v3))+ 
+ with(dat, v1&v2&v3&v4)] 
> dat 
     v1 v2 v3 v4 bcateg 
1 TRUE FALSE FALSE FALSE  Other 
2 FALSE TRUE FALSE FALSE v2 only 
3 TRUE FALSE FALSE FALSE  Other 
4 FALSE FALSE FALSE FALSE  Other 
5 FALSE TRUE FALSE TRUE  Other 
6 TRUE FALSE FALSE TRUE  Other 
7 FALSE TRUE FALSE FALSE v2 only 
8 FALSE TRUE FALSE TRUE  Other 
9 FALSE TRUE TRUE TRUE  Other 
10 TRUE FALSE TRUE TRUE v1 and v3 

Вторая стратегия concatentate имена столбцов в истинах, используя разделитель «»:

> dat$bcateg2 <-paste(c("","v1")[dat[["v1"]]+1 ], c("","v2")[dat[["v2"]]+1 ], c("","v3")[dat[["v3"]]+1 ], c("","v4")[dat[["v4"]]+1 ], sep = ",") 
> dat 
     v1 v2 v3 v4 bcateg bcateg2 
1 TRUE FALSE FALSE FALSE  Other  v1,,, 
2 FALSE TRUE FALSE FALSE v2 only  ,v2,, 
3 TRUE FALSE FALSE FALSE  Other  v1,,, 
4 FALSE FALSE FALSE FALSE  Other  ,,, 
5 FALSE TRUE FALSE TRUE  Other ,v2,,v4 
6 TRUE FALSE FALSE TRUE  Other v1,,,v4 
7 FALSE TRUE FALSE FALSE v2 only  ,v2,, 
8 FALSE TRUE FALSE TRUE  Other ,v2,,v4 
9 FALSE TRUE TRUE TRUE  Other ,v2,v3,v4 
10 TRUE FALSE TRUE TRUE v1 and v3 v1,,v3,v4 
+0

Спасибо. Я многому научился и от этого ответа. –

2

Позвольте мне бросить шляпу в кольцо, а

plyr::adply(dat, 1, function(x) paste(names(Filter(isTRUE, x)), collapse = " and ")) 

     v1 v2 v3 v4    V1 
1 TRUE TRUE FALSE TRUE v1 and v2 and v4 
2 TRUE TRUE TRUE FALSE v1 and v2 and v3 
3 FALSE FALSE FALSE TRUE    v4 
4 FALSE TRUE TRUE TRUE v2 and v3 and v4 
5 TRUE FALSE TRUE FALSE  v1 and v3 
6 FALSE TRUE TRUE FALSE  v2 and v3 
7 FALSE FALSE TRUE FALSE    v3 
8 FALSE FALSE TRUE TRUE  v3 and v4 
9 FALSE TRUE FALSE FALSE    v2 
10 TRUE FALSE TRUE TRUE v1 and v3 and v4 
+0

Эта шляпа стоит +1! Регулярные выражения могут дополнительно уточнить это, заменив все, кроме последнего 'и' на ','. Вот что должно работать: 'txt <-" v1 и v2 и v3 и v4 "', затем 'gsub (" ([[: space:]] и) (?! [[: Space:]] v [[: digit:]] $) ",", ", txt, perl = TRUE). –

Смежные вопросы