Joining data with weighted averages and multiple weights in R

戏子无情 提交于 2019-12-06 10:10:19

A solution using and . The idea is to convert the data frame, conduct the calculation, and transform back to the original format.

library(dplyr)
library(tidyr)

Joined <- bind_rows(RMS1, RMS2) %>%
  mutate(rowid = 1:n()) %>%
  gather(Column, Value, -id, -rowid) %>%
  extract(Column, into = c("Type", "Number"), 
          regex = "([A-Za-z]*)([0-9]*)", convert = TRUE) %>%
  spread(Type, Value) %>%
  group_by(id, Number) %>%
  summarise_at(vars(-rowid, -count), funs(weighted.mean(., count))) %>%
  gather(Type, Value, -id, -Number) %>%
  unite(Column, Type, Number, sep = "") %>%
  spread(Column, Value) %>%
  ungroup() %>%
  as.data.frame()
Joined
#    id freq1 freq2 sev1 sev2
# 1 111  0.00   1.0 2.00  2.0
# 2 222  1.25   5.2 3.25  5.6
# 3 333  4.00   3.0 5.00  2.0

DATA

RMS1 <- read.table(text = "id freq1 sev1 count1 freq2 sev2 count2
111 0    2    50     1     2    25
222 1    3    75     2     4    50
", header = TRUE)

RMS2 <- read.table(text = "id freq1 sev1 count1 freq2 sev2 count2
222 2    4    25     6     6    200
                   333 4    5    60     3     2    20
                   ", header = TRUE)

1) dplyr rbind the two input data frames together and then grouping by id perform a weighted mean on each required column:

library(dplyr)

RMS1 %>%
     rbind(RMS2) %>%
     group_by(id) %>%
     summarize(freq1 = weighted.mean(freq1, count1),
               sev1 = weighted.mean(sev1, count1),
               freq2 = weighted.mean(freq2, count2),
               sev2 = weighted.mean(sev2, count2)) %>%
     ungroup

giving:

# A tibble: 3 x 5
     id freq1  sev1 freq2  sev2
  <int> <dbl> <dbl> <dbl> <dbl>
1   111  0     2.00  1.00  2.00
2   222  1.25  3.25  5.20  5.60
3   333  4.00  5.00  3.00  2.00

2) sqldf An alternative using sql is:

library(sqldf)
sqldf("select id, 
              sum(count1 * freq1 + 0.0) / sum(count1) freq1,
              sum(count1 * sev1 + 0.0)  / sum(count1) sev1,
              sum(count2 * freq2 + 0.0) / sum(count2) freq2,
              sum(count2 * sev2 + 0.0)  / sum(count2) sev2
       from (select * from RMS1 union select * from RMS2)
       group by id", method = "raw")

giving:

   id freq1 sev1 freq2 sev2
1 111  0.00 2.00   1.0  2.0
2 222  1.25 3.25   5.2  5.6
3 333  4.00 5.00   3.0  2.0

Note

The input in reproducible form is:

Lines1 <- "
id freq1 sev1 count1 freq2 sev2 count2
111 0    2    50     1     2    25
222 1    3    75     2     4    50"
RMS1 <- read.table(text = Lines1, header = TRUE)

Lines2 <- "
id freq1 sev1 count1 freq2 sev2 count2
222 2    4    25     6     6    200
333 4    5    60     3     2    20"
RMS2 <- read.table(text = Lines2, header = TRUE)75 + 25)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!