Хобрук: Ваш путь к мастерству в программировании

Взвешенная сумма нескольких столбцов в R с использованием tidyverse

Я пытаюсь получить взвешенную сумму по уровням факторов. У меня четыре столбца данных:

col1 = surface area
col 2 = dominant
col 3 = codominant
col 4 = sub

1    2    3     4
125  A    NA    NA
130  A    NA    B
150  C    B     NA
160  B    NA    NA
90   B    A     NA
180  C    A     B
  • Если заполнен только столбец 2, значение получает полный объем столбца 1.
  • Если столбцы 2 и 3 заполнены, значение в столбце 1 делится пополам.
  • Если столбцы 2, 3 и 4 заполнены, значение в столбце 1 разделяется на три.
  • Если столбцы 2 и 4 заполнены, значение в столбце 1 делится как 75/25.

Итак, для вывода приведенного выше примера мой новый фрейм данных будет:

1    2
A    326.9
B    331.4
C    134.4

Я возился с ifelse и получил что-то вроде (для двух столбцов в этом примере):

     df1 <- df %>% 
            mutate(weighted_dominant = ifelse(!is.na(dominant) & is.na(codominant), Surface_Area, 
            Surface_Area/2),
                   weighted_codominant = ifelse(!is.na(codominant), Surface_Area/2, NA )

Теперь я изолирую столбцы интересета:

df2 <- df1 %>% select(dominant, weighted_dominant) %>% 
               group by (dominant) %>%
               summarise (sum = sum(weighted_dominant) 

также выполните это для кодоминантного столбца, свяжите строки двух новых фреймов данных и снова выполните функцию суммирования.

Это выполняет свою работу, но также требует около 50 строк кода и, на мой взгляд, не очень чисто.

Мой вопрос: есть ли лучшие (tidyverse) способы сделать такое взвешенное обобщение?


  • Я не уверен, что понимаю случай, когда заполнены столбцы 1 и 4, значение в столбце 1 делится как 75/25. Что дает 75, а что 25? Разве в этой ситуации не только одно значение (столбец 4)? Не могли бы вы уточнить? 20.11.2020
  • Привет, Бен, с моей стороны это была грубая ошибка. Это должно быть col2 вместо col1. Итак, столбцы 2 и 4 заполнены, столбец 2 получает col1 * 0.75, а столбец 4 получает col1 * 0.25. 20.11.2020
  • Я также отредактировал свой предыдущий код, используя !is.na() вместо == "" 20.11.2020

Ответы:


1

С tidyverse вы можете рассмотреть следующий подход.

Включите номера строк в отдельный столбец, чтобы вы могли оценивать каждую строку. pivot_longer поместит ваши данные в длинный формат.

После группировки по номеру строки вы можете определить значения для A, B и C в зависимости от того, какие столбцы отсутствуют. Это предполагает, что всегда есть доминирующий столбец (в противном случае вы можете настроить логику здесь).

Затем удалите свой NA и просуммируйте взвешенные значения для A, B и C.

df %>%
  mutate(rn = row_number()) %>%
  pivot_longer(cols = c(dominant, codominant, sub)) %>%
  group_by(rn) %>%
  mutate(weight = case_when(
    is.na(value[name == "codominant"]) & is.na(value[name == "sub"]) ~ as.numeric(Surface_Area),
    is.na(value[name == "codominant"]) & name == "dominant" ~ Surface_Area * .75,
    is.na(value[name == "codominant"]) & name == "sub" ~ Surface_Area * .25,
    is.na(value[name == "sub"]) ~ Surface_Area / 2,
    TRUE ~ Surface_Area / 3
  )) %>%
  drop_na() %>%
  group_by(value) %>%
  summarise(total = sum(weight))

Вывод

  value total
  <chr> <dbl>
1 A      328.
2 B      372.
3 C      135 
20.11.2020
  • Большое спасибо, это был ответ, который я искал. Мне нужно немного подправить его, так как мой фрейм данных является шейп-файлом, но это сработает. Спасибо, что показали мне аккуратный способ! 20.11.2020

  • 2

    Это то, что вы ищете:

    # your data
    df <- read.table(text = "
    125  A    NA    NA
    130  A    NA    B
    150  C    B     NA
    160  B    NA    NA
    90   B    A     NA
    180  C    A     B", header = FALSE)
    names(df) <- c("surface_area", "dominant", "codominant", "sub")
    
    
    # make a matrix out of the last 3 columns
    m <- as.matrix(df[2:4])
    
    
    # get a logical matrix of non-NA
    x <- !is.na(m)
    
    
    # calculate as follow:
    # 2  NA  NA  ->  1    0    0
    # 2   3  NA  ->  1/2  1/2  0
    # 2  NA   4  ->  1/2  0    1/2
    # 2   3   4  ->  1/3  1/3  1/3
    x <- x * (1/rowSums(x))
    
    
    # correct
    # 2  NA   4  ->  0.75  0  0.25
    x[apply(x, 1, identical, c(dominant=0.5,codominant=0,sub=0.5)),] <- c(dominant=0.75,codominant=0,sub=0.25)
    
    
    # multiply by surface_area
    x <- x * df$surface_area
    
    
    # get unique letters
    l <- sort(unique(c(m)))
    l <- l[!is.na(l)]
    
    
    # sum by each letter
    r <- sapply(l, function(i) sum(x[m==i], na.rm = TRUE))
    
    
    # create final dataframe
    data.frame(X1 = names(r), X2 = unname(r))
    #>   X1    X2
    #> 1  A 327.5
    #> 2  B 372.5
    #> 3  C 135.0
    

    Окончательные цифры не совпадают, я неправильно понял ваше объяснение? Мне это не совсем понятно.

    20.11.2020
  • Выглядит отлично! Спасибо за помощь, это действительно ответ на мой вопрос в стиле Base R, но прежде чем я приму его, я также хочу подробно ознакомиться с его ответом Бена. 20.11.2020
  • Новые материалы

    ВЫ РЕГРЕСС ЭТО?
    Чтобы понять, когда использовать регрессионный анализ, мы должны сначала понять, что именно он делает. Вот простой ответ, который появляется, когда вы используете Google: Регрессионный..

    Не зря же это называют интеллектом
    Стек — C#, Oracle Опыт — 4 года Работа — Разведывательный корпус Мне пора служить Может быть, я немного приукрашиваю себя, но там, где я живу, есть обязательная военная служба на 3..

    LeetCode Проблема 41. Первый пропущенный положительный результат
    LeetCode Проблема 41. Первый пропущенный положительный результат Учитывая несортированный массив целых чисел, найдите наименьшее пропущенное положительное целое число. Пример 1: Input:..

    Расистский и сексистский робот, обученный в Интернете
    Его ИИ основан на предвзятых данных, которые создают предрассудки. Он словно переходит из одного эпизода в другой из серии Черное зеркало , а вместо этого представляет собой хронику..

    Управление состоянием в микрофронтендах
    Стратегии бесперебойного сотрудничества Микро-фронтенды — это быстро растущая тенденция в сфере фронтенда, гарантирующая, что удовольствие не ограничивается исключительно бэкэнд-системами..

    Декларативное и функциональное программирование в стиле LINQ с использованием JavaScript с использованием каррирования и генератора ...
    LINQ - одна из лучших функций C #, которая обеспечивает элегантный способ написания кода декларативного и функционального стиля, который легко читать и понимать. Благодаря таким функциям ES6,..

    Структуры данных в C ++ - Часть 1
    Реализация общих структур данных в C ++ C ++ - это расширение языка программирования C, которое поддерживает создание классов, поэтому оно известно как C с классами . Он используется для..