Применить математические вычисления ко всем строкам DF по значениям столбцов - PullRequest
0 голосов
/ 14 января 2019

Я хочу применить математический расчет, который (Occ_1+1)/(Totl_1+Unique_words) , (Occ_2+1)/(Totl_2+Unique_words) и (Occ_3+1)/(Totl_3+Unique_words) и создайте новый столбец как Probability_1, Probability_2, Probability_3

Сейчас я делаю все расчеты отдельно и объединяю их вместе.

Пример: для (Occ_1+1) я делаю sapply(df$Occ_1, function(x){x+1}).

у меня почти 50 Occ_ и 50 Totl_, поэтому мой код становится очень длинным, если я делаю все вычисления отдельно.
Есть ли способ сделать все расчеты сразу.

образец DF до Occ_3 и Totl_3 только

 word        Occ_1  Occ_2  Occ_3  Totl_1 Totl_2 Totl_3 Unique_words
  <chr>      <int>  <int>  <int>  <int>  <int>  <int>        <int>
 1 car          0     1     0     11      9      7           17
 2 saturn       2     0     2     11      9      7           17
 3 survival     1     2     0     11      9      7           17
 4 baseball     1     1     0     11      9      7           17
 5 color        0     0     1     11      9      7           17
 6 muscle       0     1     0     11      9      7           17

Ответы [ 3 ]

0 голосов
/ 14 января 2019

Я бы просто собрал все столбцы Occ.., Tot.. вместе и выполнил необходимую арифметику

occ_cols <- grep("^Occ", names(df))
tot_cols <- grep("^Totl", names(df))

df[paste0("Probability_", 1:length(occ_cols))] <- 
      (df[occ_cols] + 1)/(df[tot_cols] + df$Unique_words)

df
#      word Occ_1 Occ_2 Occ_3 Totl_1 Totl_2 Totl_3 Unique_words Probability_1
#1      car     0     1     0     11      9      7           17    0.03571429
#2   saturn     2     0     2     11      9      7           17    0.10714286
#3 survival     1     2     0     11      9      7           17    0.07142857
#4 baseball     1     1     0     11      9      7           17    0.07142857
#5    color     0     0     1     11      9      7           17    0.03571429
#6   muscle     0     1     0     11      9      7           17    0.03571429

#  Probability_2 Probability_3
#1    0.07692308    0.04166667
#2    0.03846154    0.12500000
#3    0.11538462    0.04166667
#4    0.07692308    0.04166667
#5    0.03846154    0.08333333
#6    0.07692308    0.04166667

Однако убедитесь, что все ваши столбцы Occ.. и Tot.. расположены в одинаковом порядке. Для этого примера у нас есть Occ_1, Occ_2, Occ_3, за которыми следуют Totl_1, Totl_2 и Totl_3.

0 голосов
/ 14 января 2019

Я собираюсь предложить другой подход из двух других ответов. Я думаю, что вы работаете в неправильном формате данных здесь, а именно, ваши данные широки, когда они должны быть длинными. Если вы не знакомы с этими условиями, есть много объяснений в Интернете, которые вы должны проверить. На мой взгляд, лучшим будет этот .

Используя пакет tidyr, я бы решил вашу проблему следующим образом:

library(tidyverse)

Шаг первый - разделить столбцы Occ и Totl на 2 фрейма данных, которые мы собираемся объединить позже. Используя функцию gather, я конвертирую эти столбцы в пары ключ-значение. Мы извлекаем числовое значение из ключа, чтобы позже мы могли сопоставить Occ_1 с Totl_1.

df_occ <- df %>%
  gather(group, occ, contains("Occ")) %>%
  select(word, group, occ) %>%
  mutate(group = str_extract(group, "[0-9]") %>% as.integer())

df_totl <- df %>%
  gather(group, totl, contains("Totl")) %>%
  select(word, group, totl) %>%
  mutate(group = str_extract(group, "[0-9]") %>% as.integer())

Получив эти два фрейма данных, мы объединяем их вместе. Мы берем столбцы word и Unique_words из исходного фрейма данных, затем добавляем фрейм данных Occ и, наконец, фрейм данных Totl по группам. Наконец, мы можем выполнить необходимые вычисления с помощью одной строки кода.

df_merge <- df %>%
  select(word, Unique_words) %>%
  left_join(df_occ, by = 'word') %>%
  left_join(df_totl, by = c('word', 'group')) %>%
  mutate(prob = (occ + 1) / (totl + Unique_words))

Если вы хотите преобразовать это обратно в широкий формат, вы должны использовать обратную функцию gather, а именно spread.

df_wide <- df_merge %>%
  select(word, group, prob) %>%
  mutate(group = paste0("Prob_", group)) %>%
  spread(group, prob)

Преимущества этого подхода:

  1. Ваш код более разборчивый, каждая операция выполняется в отдельной строке и избегает квадратных скобок (которые часто создают код, который трудно читать).
  2. Ваш код показывает промежуточные шаги.
  3. Этот подход является более гибким и, надеюсь, также облегчает другие этапы обработки.
0 голосов
/ 14 января 2019

Это на самом деле то, что называется векторизацией функции, и это может значительно повысить производительность вашего кода.

Но сначала, просто чтобы вы знали о будущих вопросах, гораздо проще предоставить пример данных, используя dput

dput(df)

Тогда тот, кто хочет ответить на вопрос, может просто использовать вывод:

df <- dget(structure(list(word = structure(c(2L, 5L, 6L, 1L, 3L, 4L), .Label = c("baseball", 
"car", "color", "muscle", "saturn", "survival"), class = "factor"), 
    Occ_1 = c(0L, 2L, 1L, 1L, 0L, 0L), Occ_2 = c(1L, 0L, 2L, 
    1L, 0L, 1L), Occ_3 = c(0L, 2L, 0L, 0L, 1L, 0L), Totl_1 = c(11L, 
    11L, 11L, 11L, 11L, 11L), Totl_2 = c(9L, 9L, 9L, 9L, 9L, 
    9L), Totl_3 = c(7L, 7L, 7L, 7L, 7L, 7L), Unique_words = c(17L, 
    17L, 17L, 17L, 17L, 17L), Probability_1 = c(0.0357142857142857, 
    0.107142857142857, 0.0714285714285714, 0.0714285714285714, 
    0.0357142857142857, 0.0357142857142857), Probability_2 = c(0.0769230769230769, 
    0.0384615384615385, 0.115384615384615, 0.0769230769230769, 
    0.0384615384615385, 0.0769230769230769), Probability_3 = c(0.0416666666666667, 
    0.125, 0.0416666666666667, 0.0416666666666667, 0.0833333333333333, 
    0.0416666666666667)), row.names = c(NA, -6L), class = "data.frame"))

В любом случае, вот способ сделать то, что вы хотите:

df$Probability_1 <- (df$Occ_1 + 1) / (df$Totl_1 + df$Unique_words)
df$Probability_2 <- (df$Occ_2 + 1) / (df$Totl_2 + df$Unique_words)
df$Probability_3 <- (df$Occ_3 + 1) / (df$Totl_3 + df$Unique_words)

Или, если вы предпочитаете, dplyr:

library("dplyr")
df_new <- df %>% 
  mutate(
    Probability_1 = (Occ_1 + 1) / (Totl_1 + Unique_words),
    Probability_2 = (Occ_2 + 1) / (Totl_2 + Unique_words),
    Probability_3 = (Occ_3 + 1) / (Totl_3 + Unique_words)        
  )

Обновление

Я упустил суть вопроса. На самом деле речь идет о количестве Occ и Totl переменных. Я бы решил это с помощью цикла for, который все еще должен быть очень эффективным:

for(i in gsub("^Occ_", "", grep("^Occ_*", colnames(df), value = TRUE))) {
  df[paste0("Probability_", i)] <- 
    (df[paste0("Occ_", i)] + 1) / (df[paste0("Totl_", i)] + df$Unique_words)
}
...