Эффективный способ условно классифицировать по столбцам в R? - PullRequest
0 голосов
/ 18 апреля 2020

Я пытаюсь отсортировать фрейм данных по категориям. Подобно тому, что вам нужно для диаграммы Венна, но я бы хотел как-то «grepl» сэмплировать заголовки столбцов. То есть, если шаблон является общим и удовлетворяет порогу цифр c, его можно отсортировать по указанной категории.

Пример данных:

df <- data.frame(a_b_c = c(1,3,5,0,0), a_b=c(0,0,4,0,0), a_b_c_d=c(1,2,2,3,0),
                 b_d=c(0,0,3,2,3), a_c = c(1,5,1,0,0))
df

>  a_b_c a_b a_b_c_d b_d a_c    
>     1   0       1   0   1     
>     3   0       2   0   5     
>     5   4       2   3   1   
>     0   0       3   2   0   
>     0   0       0   3   0 

Требуемый вывод

df_final <- data.frame(df, category = c("Other", "Shared c", "Shared all", "Shared d", "Appears once"))

df_final

>  a_b_c a_b a_b_c_d b_d a_c     category
>     1   0       1   0   1        Other
>     3   0       2   0   5     Shared c
>     5   4       2   3   1   Shared all
>     0   0       3   2   0     Shared d
>     0   0       0   3   0 Appears once

Я думаю, что это включает в себя оператор аккуратного стихотворения с case_when() и / или ifelse() операторов, но я не могу правильно отключить логи c. Это пример тестового набора данных, мои фактические данные имеют> 20 столбцов. Вот почему я хотел бы распределить заголовки столбцов по групповым символам.

Открыто для любых предложений.

Ответы [ 2 ]

2 голосов
/ 18 апреля 2020

Я предлагаю "pivot", case_when, и "join" дает вам ваши результаты.

library(dplyr)
# library(tidyr) # pivot_longer

df <- data.frame(a_b_c = c(1,3,5,0,0), a_b=c(0,0,4,0,0), a_b_c_d=c(1,2,2,3,0),
                 b_d=c(0,0,3,2,3), a_c = c(1,5,1,0,0)) %>%
  mutate(row = row_number())

df %>%
  tidyr::pivot_longer(-row) %>%
  group_by(row) %>%
  summarize(
    category = case_when(
      all(value > 0)                     ~ "Shared all",
      sum(value > 0) == 1L               ~ "Appears once",
      all(value == 0 | grepl("c", name)) ~ "Shared c",
      all(value == 0 | grepl("d", name)) ~ "Shared d",
      TRUE                               ~ "Other"
    )
  ) %>%
  left_join(df, ., by = "row")
#   a_b_c a_b a_b_c_d b_d a_c row     category
# 1     1   0       1   0   1   1     Shared c
# 2     3   0       2   0   5   2     Shared c
# 3     5   4       2   3   1   3   Shared all
# 4     0   0       3   2   0   4     Shared d
# 5     0   0       0   3   0   5 Appears Once

Я должен добавить столбец row, чтобы быть уверенным, что категория будет обратно в исходную строку, так как в противном случае строки не идентифицируются однозначно (за исключением полной уникальности, на которую я не рассчитывал). Я pivot сделал так, чтобы мы не полагались на указанные c имена столбцов или на существование ровно пяти столбцов (это одинаково хорошо работает с 3 и 300, дайте или возьмите ваши логические c правила. Наконец, использование !grepl(...) | value>0 - это заданная c инверсия, гарантирующая, что все имена c, включая (и d), имеют значение выше 0, она легко расширяема, хотя в зависимости от вашего фактического варианта использования может потребоваться более сильное регулярное выражение (например, границы слова).

0 голосов
/ 18 апреля 2020

В base R мы можем создать индекс нумерации c на основе логики c, а затем использовать этот индекс в качестве индекса позиции для изменения значений

i1 <- apply(df > 0, 1, function(x) {
      x1 <- x[x]
       c1 <- all(grepl('c', names(x1)))
       d1 <- all(grepl('d', names(x1)))
       all(x) + 2 * c1 + 4 * d1 +  8 * (length(x1) == 1)})
df$category <- c('Shared all', 'Shared c', 'Shared d',
            'Appears once', 'other')[as.integer(factor(i1))]
df$category
#[1] "Shared c"     "Shared c"     "Shared all"   "Shared d"     "Appears once"
...