Вычисление средневзвешенных значений с использованием циклов во фрейме данных

#r #tidyverse

Вопрос:

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

В качестве примера предположим, что у меня есть следующий фрейм данных:

 library(stringi)

set.seed(200)

df <- cbind.data.frame(id = stri_rand_strings(6, 3, pattern = "[A-Za-z0-9]"),
                        year = 2005 ,
                        australia = runif(6, min=0, max=100) ,
                        austria = runif(6, min=0, max=100) ,
                        weight = runif(6, min=0, max=100) )
 

дающий

    id year australia   austria   weight
1 Xaa 2005 92.217757 31.942681 26.37486
2 gfq 2005 64.632962 26.532429 16.60537
3 i5W 2005 46.036069 71.736956 48.30747
4 ESe 2005  9.874701 38.033536 32.57277
5 9eN 2005 20.659381  3.062094 92.53639
6 JZ8 2005 92.233983 52.141938 56.05588
 

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

 weighted.mean(df$australia , df$weight)
weighted.mean(df$austria , df$weight)
 

но это было бы чрезвычайно громоздко при наличии более 30 переменных такого value типа. Есть ли способ автоматизировать это?

Комментарии:

1. У вас есть конкретные колонки? Есть ли способ их индексировать? то df[, 3:4] есть, например?

Ответ №1:

Ты имеешь в виду вот так?

dplyr

 library(dplyr)
mycols <- c("australia", "austria")
df %>%
#   mutate(across(mycols, list(wavg = ~ weighted.mean(., weight))))
   id year australia austria weight australia_wavg austria_wavg
# 1 Xaa 2005   92.2178 31.9427 26.375         48.203       33.744
# 2 gfq 2005   64.6330 26.5324 16.605         48.203       33.744
# 3 i5W 2005   46.0361 71.7370 48.307         48.203       33.744
# 4 ESe 2005    9.8747 38.0335 32.573         48.203       33.744
# 5 9eN 2005   20.6594  3.0621 92.536         48.203       33.744
# 6 JZ8 2005   92.2340 52.1419 56.056         48.203       33.744
 

или резюмируя это с

 df %>%
  summarize(across(mycols, list(wavg = ~ weighted.mean(., weight))))
#   australia_wavg austria_wavg
# 1         48.203       33.744
 

основание R

 mycols <- c("australia", "austria")
lapply(subset(df, select = mycols), weighted.mean, df$weight)
# $australia
# [1] 48.203
# $austria
# [1] 33.744
 

Комментарии:

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

2. Ваш код не будет работать, если имена переменных имеют другой шаблон

3. Разве вы заранее не знаете названия столбцов? Если вы это сделаете, то ваш вопрос спорен, используйте dplyr::one_of вместо starts_with или select=c(myvars) в базе R.

4. Смотрите мою правку, в ней больше не используются ваши value* имена.

Ответ №2:

Вы можете использовать любое из следующих:

 > colSums(df[, 3:4] * prop.table(df[, 'weight']))
australia   austria
 48.20293  33.74373 

> sapply(df[, 3:4], weighted.mean, df[, 'weight'])
australia   austria 
 48.20293  33.74373