Сравните три (или более) переменных в R с ifelse одновременно с помощью цикла - PullRequest
5 голосов
/ 01 ноября 2019

Я хочу сравнить три переменные. Если у всех одинаковый результат (например, 0, 0, 0 и 2, 2, 2), возвращается значение (например, «совпадение»).

Я пробую это:


df_1 <- data.frame(
  x = c(0, 1, 0, 2, 0), 
  y = c(0, 2, 1, 2, 1), 
  z = c(0, 2, 1, 2, 1)
)


ifelse(df_1$x == df_1$y == df_1$z,  'match', 'not')

Ошибка: неожиданное '==' в "ifelse (df_1 $ x == df_1 $ y =="

Но это не работает. Спасибо.

Ответы [ 7 ]

5 голосов
/ 01 ноября 2019

Вам нужен &, поэтому df_1$x == df_1$y & df_1$y == df_1$z, то есть x равно y И y равно x. Вам также не нужно ifelse для такого сравнения. Просто сравните и добавьте вывод в ваш фрейм данных:

df_1$match <- df_1$x == df_1$y & df_1$y == df_1$z

#### OUTPUT ####
  x y z match
1 0 0 0  TRUE
2 1 2 2 FALSE
3 0 1 1 FALSE
4 2 2 2  TRUE
5 0 1 1 FALSE

Однако, если вы действительно хотите, чтобы "совпали" с "не", вы можете сделать это тоже:

df_1$match <- ifelse(df_1$x == df_1$y & df_1$y == df_1$z, "matched", "not")

#### OUTPUT ####

  x y z match
1 0 0 0 match
2 1 2 2   not
3 0 1 1   not
4 2 2 2 match
5 0 1 1   not

Редактирование на основе комментария :

Для произвольного числа переменных вы можете попробовать что-то вроде этого, который проверяет, что unique возвращает только одно значение, то есть все равны:

df_1$match <- apply(df_1, 1, function(r) length(unique(r)) == 1)
2 голосов
/ 01 ноября 2019

Вы можете попробовать ifelse с apply и использовать unique, чтобы увидеть, соответствует ли:

df$match <- apply(df, 1, function(x) ifelse(length(unique(x))==1, 'match','not'))
2 голосов
/ 01 ноября 2019

Вы также можете использовать rowSums():

rowSums(df_1[, -1] == df_1[, 1]) == length(df_1[, -1])

[1]  TRUE FALSE FALSE  TRUE FALSE

Он проверяет, совпадают ли столбцы второго включения с первым столбцом. Если все они одинаковы, возвращается ИСТИНА.

И если вам нужен match/not результат:

ifelse(rowSums(df_1[, -1] == df_1[, 1]) == length(df_1[, -1]), "match", "not")
2 голосов
/ 01 ноября 2019

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

Вот один из вариантовс purrr:

library(purrr)

df_1$comparison <- map_chr(as.data.frame(t(df_1)), ~ ifelse(
  length(unique(.x)) == 1, 'match', 'not'))

Вывод:

  x y z comparison
1 0 0 0      match
2 1 2 2        not
3 0 1 1        not
4 2 2 2      match
5 0 1 1        not
2 голосов
/ 01 ноября 2019

Если у вас большое количество переменных, вы можете сделать:

df_1$match <- c("match", "no match")[apply(df_1, 1, function(x) length(unique(x)) != 1) + 1]
df_1

  x y z    match
1 0 0 0    match
2 1 2 2 no match
3 0 3 1 no match
4 2 2 2    match
5 0 1 1 no match
1 голос
/ 01 ноября 2019

Вот подход с Reduce()

n_cols <- length(df_1)

Reduce(`&`,
       lapply(seq_len(n_cols - 1),
              function(j) df_1[[j]] == df_1[[j+1]])
       )

Вот производительность некоторых ответов с оценкой TRUE или FALSE:

# A tibble: 4 x 13
  expression                                                 min  median
  <bch:expr>                                             <bch:t> <bch:t>
1 Reduce_way                                              47.7us  50.5us
2 rowSums(df_1[, -1] == df_1[, 1]) == length(df_1[, -1]) 159.6us 168.6us
3 apply(df_1, 1, function(x) length(unique(x)) == 1)     150.6us 158.1us
4 df_1[[1]] == df_1[[2]] & df_1[[2]] == df_1[[3]]         27.5us  29.6us

Производительность зависитна количество оцениваемых столбцов и строк. Например, 100 000 x 3:

df_1 <- as.data.frame(replicate(3, sample(3, 100000, replace = T)))

  expression                                                  min  median
  <bch:expr>                                             <bch:tm> <bch:t>
1 Reduce_way                                              931.5us  1.13ms
2 rowSums(df_1[, -1] == df_1[, 1]) == length(df_1[, -1])  10.96ms 12.69ms
3 apply(df_1, 1, function(x) length(unique(x)) == 1)        1.01s   1.01s
4 df_1[[1]] == df_1[[2]] & df_1[[2]] == df_1[[3]]         894.8us  1.06ms

# following is used from here on out instead of writing out df_1[[1]] == ...

n_cols <- length(df_1)
eval_parse <- paste(
  apply(matrix(rep(seq_len(n_cols), c(1, rep(2, n_cols - 2), 1)), 2),
        2, 
        function(cols) paste0("df_1[[", cols, "]]", collapse = ' == ')
  ),
  collapse = ' & '
)

## for 100 x 1000 data.frame

df_1 <- as.data.frame(replicate(1000, sample(3, 100, replace = T)))

# A tibble: 4 x 13
  expression                                                min median `itr/sec`
  <bch:expr>                                             <bch:> <bch:>     <dbl>
1 Reduce_way                                             15.9ms 16.3ms      60.9
2 rowSums(df_1[, -1] == df_1[, 1]) == length(df_1[, -1]) 16.5ms 17.1ms      58.1
3 apply(df_1, 1, function(x) length(unique(x)) == 1)     10.4ms 10.7ms      92.4
4 eval(parse(text = eval_parse))                         20.1ms 20.6ms      47.4
1 голос
/ 01 ноября 2019

Аналогично ответу @tmfmnk (обновлено в соответствии с комментарием @ Коул):

ifelse(rowMeans(df_1 == df_1[, 1]) == 1, 'match', 'not')
#[1] "match" "not"   "not"   "match" "not" 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...