从向量提供的变量名称和权重创建一个均值变量

Creating a mean variable, from variable names and weights supplied by vectors

假设我想基于两个向量在给定的数据框中创建一个均值变量,一个指定要使用的变量的名称,另一个指定这些变量进入均值变量的权重:

vars <- c("a", "b", "c","d"))
weights <- c(0.5, 0.7, 0.8, 0.2))
df <- data.frame(cbind(c(1,4,5,7), c(2,3,7,5), c(1,1,2,3), 
                       c(4,5,3,3), c(3,2,2,1), c(5,5,7,1)))
colnames(df) <- c("a","b","c","d","e","f")

如何使用 dplyr::mutate() 创建一个使用 varsweights 计算行分数的均值变量? mutate() 应该专门使用 vars 提供的变量 结果基本上应该是这样的:

df <- df %>% 
  rowwise() %>% 
  mutate(comp = mean(c(vars[1]*weights[1], vars[2]*weights[2], ...)))

写出:

df2 <- df %>% 
  rowwise() %>% 
  mutate(comp = mean(c(0.5*a, 0.7*b, 0.8*c, 0.2*d)))

我不知道该怎么做,因为虽然 vars 包含我想在我的 df 中用于变异的确切变量名称,但在 vars 中它们是字符串。我如何才能让 mutate() 理解 vars 包含的字符串与我的 df 中的列相关?如果您知道另一个不使用 mutate() 的程序,那也没关系。谢谢!

行操作在 tidyverse 中可能有点棘手。在这种情况下,一些基本的 R 知识可以非常方便。例如,您可以使用 apply 在一行中完成此操作(请注意,我更正了创建 weights 的行中的拼写错误并删除了没有权重的列 e 和 f):

vars <- c("a", "b", "c","d")
weights <- c(0.5, 0.7, 0.8, 0.2)
df <- data.frame(cbind(c(1,4,5,7), c(2,3,7,5), c(1,1,2,3), 
                       c(4,5,3,3), c(3,2,2,1), c(5,5,7,1)))
colnames(df) <- c("a","b","c","d","e","f")

df$weighted.mean <- apply(df %>% select(-e, -f), 1, weighted.mean, weights)

  a b c d e f weighted.mean
1 1 2 1 4 3 5      1.590909
2 4 3 1 5 2 5      2.681818
3 5 7 2 3 2 7      4.363636
4 7 5 3 3 1 1      4.545455

如果您真的想在 tidyverse 中这样做,这应该可以帮助您入门:

library(tidyverse)

df.weights <- data.frame(vars, weights)

df.new <- df %>% 
  mutate(row.num = 1:n()) %>% 
  gather(variable, value, -row.num) %>% 
  left_join(df.weights, by = c(variable = 'vars')) %>% 
  filter(variable %in% vars) %>% 
  group_by(row.num) %>% 
  mutate(weighted.mean = weighted.mean(value, weights))

您可以使用

df %>% mutate(wmean = apply(.[vars], 1, weighted.mean, weights))
#   a b c d e f     mean
# 1 1 2 1 4 3 5 1.590909
# 2 4 3 1 5 2 5 2.681818
# 3 5 7 2 3 2 7 4.363636
# 4 7 5 3 3 1 1 4.545455

但是 tidyverse 没有太多收获,因为基础 R 方法几乎相同并且最终更短:

df$wmean <- apply(df[vars], 1, weighted.mean, weights)

或以下之一:

df$wmean <- colSums(t(df[vars]) * weights) / sum(weights)
df$wmean <- as.matrix(df[vars]) %*% weights / sum(weights)
df$wmean <- rowSums(sweep(df[vars], 2, weights, `*`)) / sum(weights)

应该有一个使用 pmaptidyverse 解决方案,但它让我望而却步。这是另一种使用 tidyverse 包 purrrtibble

的方法
library(tidyverse)

vars <- c("a", "b", "c", "d")
weights <- c(0.5, 0.7, 0.8, 0.2)
df <- data.frame(cbind(c(1,4,5,7), c(2,3,7,5), c(1,1,2,3), 
                       c(4,5,3,3), c(3,2,2,1), c(5,5,7,1)))
colnames(df) <- c("a","b","c","d","e","f")

df %>% 
 transpose() %>% 
  simplify_all() %>% 
  map_dbl(~weighted.mean(.x[vars], weights)) %>% 
  add_column(df, wmean = .)
#>   a b c d e f    wmean
#> 1 1 2 1 4 3 5 1.590909
#> 2 4 3 1 5 2 5 2.681818
#> 3 5 7 2 3 2 7 4.363636
#> 4 7 5 3 3 1 1 4.545455

reprex package (v0.2.1)

创建于 2018-11-24