Агрегировать или суммировать, чтобы получить соотношения - PullRequest
5 голосов
/ 03 декабря 2010

Ниже приведена проблема с игрушкой, которая демонстрирует мой вопрос.

У меня есть фрейм данных, который содержит группу сотрудников; для каждого работника у него есть имя, зарплата, пол и штат.

aggregate(salary ~ state)  # Returns the average salary per state
aggregate(salary ~ state + gender, data, FUN = mean)  # Avg salary per state/gender

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

aggregate(salary ~ state + gender, data, FUN = sum)  

возвращает общую заработную плату, полученную женщинами (и мужчинами) в каждом штате, но мне действительно нужен salary_w / salary_total на уровне штата. Я могу написать цикл for и т. Д., Но мне интересно, есть ли способ использовать агрегат для этого.

Ответы [ 6 ]

8 голосов
/ 03 декабря 2010

Другой вариант будет использовать plyr. ddply() ожидает data.frame в качестве ввода и возвращает data.frame в качестве вывода. Второй аргумент - как вы хотите разделить фрейм данных. Третий аргумент - это то, что мы хотим применить к чанкам, здесь мы используем summarise для создания нового data.frame из существующего data.frame.

library(plyr)

#Using the sample data from kohske's answer above

> ddply(d, .(state), summarise, ratio = sum(salary[gender == "Woman"]) / sum(salary))
  state     ratio
1     1 0.5789860
2     2 0.4530224
3 голосов
/ 03 декабря 2010

вероятно, изменение формы или изменение формы2 помогут вашей работе.

Вот пример сценария:

library(reshape2) # from CRAN

# sample data
d <- data.frame(expand.grid(state=gl(2,2),gender=gl(2,1, labels=c("Men","Wemon"))),
  salaly=runif(8))

d2 <- dcast(d, state~gender, sum)
d2$frac <- d2$Wemon/(d2$Men+d2$Wemon)
2 голосов
/ 03 декабря 2010

Другое решение заключается в использовании xtabs и prop.table:

prop.table(xtabs(salary ~ state + gender,data),margin=1)
2 голосов
/ 03 декабря 2010

Функция ave хороша для подобных проблем.

Data$ratio <- ave(Data$salary, Data$state, Data$gender, FUN=sum) /
              ave(Data$salary, Data$state, FUN=sum)
1 голос
/ 03 декабря 2010

Поскольку вам нужны результаты для каждого штата, tapply может быть тем, что вы хотите.

Чтобы проиллюстрировать, давайте сгенерируем некоторые произвольные данные для воспроизведения:

set.seed(349)   # For replication
n <- 20000      # Sample size
gender <- sample(c('M', 'W'), size = n, replace = TRUE) # Random selection of gender
state <- c('AL','AK','AZ','AR','CA','CO','CT','DE','DC','FL','GA','HI',
           'ID','IL','IN','IA','KS','KY','LA','ME','MD','MA','MI','MN',
           'MS','MO','MT','NE','NV','NH','NJ','NM','NY','NC','ND','OH',
           'OK','OR','PA','RI','SC','SD','TN','TX','UT','VT','VA','WA',
           'WV','WI','WY')      # All US states
state <- sample(state, size = n, replace = TRUE)  # Random selection of the states

state_index <- tapply(state, state)     # Just for the data generatino part ...
gender_index <- tapply(gender, gender)

# Generate salaries
salary <- runif(length(unique(state)))[state_index]     # Make states different
salary <- salary + c(.02, -.02)[gender_index]           # Make gender different
salary <- salary + log(50) + rnorm(n)                   # Add mean and error term
salary <- exp(salary)                                   # The variable of interest

ЧтоВы просили, сумма зарплат для женщин в каждом штате и общая сумма зарплат в каждом штате:

salary_w <- tapply(salary[gender == 'W'], state[gender == 'W'], sum)
salary_total <- tapply(salary, state, sum)

Или, если она находится в кадре данных:

salary_w <- with(myData, tapply(salary[gender == 'W'], state[gender == 'W'], sum))
salary_total <- with(myData, tapply(salary, state, sum))

Тогда ответ:

> salary_w / salary_total
       AK        AL        AR        AZ        CA        CO        CT        DC 
0.4667424 0.4877013 0.4554831 0.4959573 0.5382478 0.5544388 0.5398104 0.4750799 
       DE        FL        GA        HI        IA        ID        IL        IN 
0.4684846 0.5365707 0.5457726 0.4788805 0.5409347 0.4596598 0.4765021 0.4873932 
       KS        KY        LA        MA        MD        ME        MI        MN 
0.5228247 0.4955802 0.5604342 0.5249406 0.4890297 0.4939574 0.4882687 0.5611435 
       MO        MS        MT        NC        ND        NE        NH        NJ 
0.5090843 0.5342312 0.5492702 0.4928284 0.5180169 0.5696885 0.4519603 0.4673822 
       NM        NV        NY        OH        OK        OR        PA        RI 
0.4391634 0.4380065 0.5366625 0.5362918 0.5613301 0.4583937 0.5022793 0.4523672 
       SC        SD        TN        TX        UT        VA        VT        WA 
0.4862358 0.4895377 0.5048047 0.4443220 0.4881062 0.4880047 0.5338397 0.5136393 
       WI        WV        WY 
0.4787588 0.5495602 0.5029816 
1 голос
/ 03 декабря 2010

Как правило, не рекомендуется называть ваши наборы данных "data", поэтому я немного изменю проблему, чтобы назвать набор данных "dat1".

       with( subset(dat1, gender="Female"), aggregate(salary, state, sum )/ 
 # should return a vector
       with( data=dat1,                   aggregate(salary,  state, sum ) 
             # using R's element-wise division

Я думаю, что вы также используете attach, и есть веские причины пересмотреть это решение, несмотря на то, что вы могли бы прочитать в Crawley.

...