Найти пропорцию значений для двух уровней, которые имеют общий уровень - PullRequest
0 голосов
/ 01 сентября 2018

У меня есть датафрейм, который выглядит так:

group <- c('a', 'b', 'a', 'b')
year <- c(1990, 1990, 2000, 2000)
freq <- c(100, 120, 130, 170)
df <- data.frame(group, year, freq)

Для каждого отдельного года я хотел бы найти значение freq для строки с группой a, разделенной на значение freq для строки с группой b, и добавить эти значения пропорции в кадр данных. Результирующий кадр данных должен выглядеть следующим образом:

group <- c('a', 'b', 'c', 'a', 'b', 'c')
year <- c(1990, 1990, 1990, 2000, 2000, 2000)
freq <- c(100, 120, 100/120, 130, 170, 130/170)
df <- data.frame(group, year, freq)

Я пытался привести это в движение с помощью самых уродливых петель внизу, но снял поезд с рельсов. Если кто-нибудь может помочь показать мне, как выполнить эту элементарную задачу в R, я был бы благодарен!

for (year in unique(df$year)) {
  a = df[ which(df$group == 'a' & df$year == year), ]
  b = df[ which(df$group == 'b' & df$year == year), ]
  proportion = a$freq / b$freq
  row = c('c', year, proportion)
  rbind(df, row)
}

Ответы [ 3 ]

0 голосов
/ 01 сентября 2018

Разделить оригинал по году с помощью функции split (результат - список).

foo <- split(df, df$year)

Для каждой записи в списке foo связать исходную запись x с новым data.frame, который вычислил freq

bar <- lapply(foo, function(x)
              rbind(x, data.frame(group = "c", 
                                  year = x$year[1], 
                                  freq = x$freq[1] / x$freq[2])))

# Bind back final result as it's a list (lapply result)
do.call(rbind, bar)
0 голосов
/ 01 сентября 2018

Вот опция, использующая data.table. Преобразуйте «data.frame» в «data.table» (setDT(df)), сгруппированный по «year», объедините «group» с «c», а также «freq» с соотношением элементов «freq» соответственно

library(data.table)
setDT(df)[, .(group = c(group, 'c'), freq = c(freq, freq[1]/freq[2])), .(year)]
#   year group        freq
#1: 1990     a 100.0000000
#2: 1990     b 120.0000000
#3: 1990     c   0.8333333
#4: 2000     a 130.0000000
#5: 2000     b 170.0000000
#6: 2000     c   0.7647059

или rbind обобщенный набор данных с оригинальным

rbind(setDT(df), df[, .(freq = Reduce(`/`, freq), group = 'c'), .(year)])

Или используя tidyverse

library(tidyverse)
df %>% 
   group_by(year) %>% 
   summarise(group = list(c(group, 'c')), 
            freq = list(c(freq, freq[1]/freq[2]))) %>% 
   unnest
# A tibble: 6 x 3
#   year group    freq
#  <dbl> <chr>   <dbl>
#1  1990 a     100    
#2  1990 b     120    
#3  1990 c       0.833
#4  2000 a     130    
#5  2000 b     170    
#6  2000 c       0.765

данные

df <- structure(list(group = c("a", "b", "a", "b"), year = c(1990, 
1990, 2000, 2000), freq = c(100, 120, 130, 170)), row.names = c(NA, 
-4L), class = "data.frame")
0 голосов
/ 01 сентября 2018

Вот вариант tidyverse

library(tidyverse)
df %>%
    spread(group, freq) %>%
    mutate(c = a / b) %>%
    gather(group, freq, -year) %>%
    arrange(year, group)
#  year group        freq
#1 1990     a 100.0000000
#2 1990     b 120.0000000
#3 1990     c   0.8333333
#4 2000     a 130.0000000
#5 2000     b 170.0000000
#6 2000     c   0.7647059

Объяснение: Мы spread данных от длинных до широких, добавляем столбцы c = a / b и gather данных от широких до длинных перед переупорядочением строк для воспроизведения ожидаемого результата.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...