如何从前面的其他列中减去特定列的平均值?

问题描述 投票:0回答:4

我想从数据集中前 3 列的每个值中减去每个“空白”列的平均值,如下所示:

df <- data.frame(da=1:5, d2=6:10, dd=2:6, 
                blank...1=c(0.1, 0.1, 0.4, 0.2, 0.1), d5=2:6, dg=7:11, 
                di=3:7, blank...2=c(0.2, 0.2, 0.4, 0.1, 0.1), dm=21:25, 
                h4=5:9, d7=26:30, blank...3=c(0.1, 0.3, 0.4, 0.4, 0.1))

df
#   da d2 dd blank...1 d5 dg di blank...2 dm h4 d7 blank...3
# 1  1  6  2       0.1  2  7  3       0.2 21  5 26       0.1
# 2  2  7  3       0.1  3  8  4       0.2 22  6 27       0.3
# 3  3  8  4       0.4  4  9  5       0.4 23  7 28       0.4
# 4  4  9  5       0.2  5 10  6       0.1 24  8 29       0.4
# 5  5 10  6       0.1  6 11  7       0.1 25  9 30       0.1

换句话说,我想将 blank...1 的平均值减去 dad2dd 列的每个值;然后将 blank...2 的平均值减去 d5dgdi 等列的每个值。实际数据集实际上有 15 个空白,需要从前面的 11 列中减去。

我已经使用

colMeans
生成了向量中所有“空白”列的平均值,但我不知道如何编写函数来指示哪个值用于哪些列。

如何通过函数来实现这一点?

r function loops calculated-columns
4个回答
2
投票

这是一种更详细的 tidyverse 方法。首先,我将数据弄长,跟踪原始行以及每列应使用哪组“空白”。

library(tidyverse)
df_long <- df |>
  mutate(row = row_number()) |>
  pivot_longer(-row) |>
  mutate(group = cumsum(lag(name |> str_detect("blank"), 1, 0)), .by = row)

然后我可以更改每个值以减去相关的“空白”平均值(通过减去名称包含“空白”的组中的值的平均值)并再次重新调整宽度。

df_long |>
  mutate(value = if_else(name |> str_detect("blank"), value, 
                         value - mean(value[name |> str_detect("blank")])), 
         .by = group) |>
  select(-group) |>
  pivot_wider(names_from = name, values_from = value)

结果

# A tibble: 5 × 13
    row    da    d2    dd blank...1    d5    dg    di blank...2    dm    h4    d7 blank...3
  <int> <dbl> <dbl> <dbl>     <dbl> <dbl> <dbl> <dbl>     <dbl> <dbl> <dbl> <dbl>     <dbl>
1     1  0.82  5.82  1.82       0.1   1.8   6.8   2.8       0.2  20.7  4.74  25.7       0.1
2     2  1.82  6.82  2.82       0.1   2.8   7.8   3.8       0.2  21.7  5.74  26.7       0.3
3     3  2.82  7.82  3.82       0.4   3.8   8.8   4.8       0.4  22.7  6.74  27.7       0.4
4     4  3.82  8.82  4.82       0.2   4.8   9.8   5.8       0.1  23.7  7.74  28.7       0.4
5     5  4.82  9.82  5.82       0.1   5.8  10.8   6.8       0.1  24.7  8.74  29.7       0.1

1
投票

这是受 jpsmith 启发的另一种基本 R 方法:

blanks = grep("blank", names(df))   # find the blank columns
blank_means = colMeans(df[blanks])  # get their means

## subtract blanks means from the non-blank columns
## this relies on having exactly 3 non-blank columns per blank column
df[-blanks] = Map("-", df[-blanks], rep(blank_means, each = 3))
df
#     da   d2   dd blank...1  d5   dg  di blank...2    dm   h4    d7 blank...3
# 1 0.82 5.82 1.82       0.1 1.8  6.8 2.8       0.2 20.74 4.74 25.74       0.1
# 2 1.82 6.82 2.82       0.1 2.8  7.8 3.8       0.2 21.74 5.74 26.74       0.3
# 3 2.82 7.82 3.82       0.4 3.8  8.8 4.8       0.4 22.74 6.74 27.74       0.4
# 4 3.82 8.82 4.82       0.2 4.8  9.8 5.8       0.1 23.74 7.74 28.74       0.4
# 5 4.82 9.82 5.82       0.1 5.8 10.8 6.8       0.1 24.74 8.74 29.74       0.1

1
投票

我确信有一个更优雅的解决方案,但在基本 R 中,您可以首先识别名称中带有“空白”的那些(

blnknms
),然后使用
lapply
迭代这些列并减去该列的平均值来自前三列:

# get columns with "blank" in the name
blnknms <- grep("blank", names(df))

df[,-blnknms] <- unlist(lapply(blnknms, \(x){
  df[,(x-3):(x-1)] - mean(df[,x])
}), recursive = FALSE)

输出:

#     da   d2   dd blank...1  d5   dg  di blank...2    dm   h4    d7 blank...3
# 1 0.82 5.82 1.82       0.1 1.8  6.8 2.8       0.2 20.74 4.74 25.74       0.1
# 2 1.82 6.82 2.82       0.1 2.8  7.8 3.8       0.2 21.74 5.74 26.74       0.3
# 3 2.82 7.82 3.82       0.4 3.8  8.8 4.8       0.4 22.74 6.74 27.74       0.4
# 4 3.82 8.82 4.82       0.2 4.8  9.8 5.8       0.1 23.74 7.74 28.74       0.4
# 5 4.82 9.82 5.82       0.1 5.8 10.8 6.8       0.1 24.74 8.74 29.74       0.1

0
投票

如果您

rep
吃每个
colMeans
的次数与相应非空白切片的列数相同,则只需从整个切片中减去结果向量即可。请注意,要从列中减去向量,我们需要
t
转置并重新
t
转置。

> bl <- grepl('^blank', names(df))
> df[!bl] <- t(t(df[!bl]) - rep(colMeans(df[bl]), each=which.max(bl) - 1L))
> df
    da   d2   dd blank...1  d5   dg  di blank...2    dm   h4    d7 blank...3
1 0.82 5.82 1.82       0.1 1.8  6.8 2.8       0.2 20.74 4.74 25.74       0.1
2 1.82 6.82 2.82       0.1 2.8  7.8 3.8       0.2 21.74 5.74 26.74       0.3
3 2.82 7.82 3.82       0.4 3.8  8.8 4.8       0.4 22.74 6.74 27.74       0.4
4 3.82 8.82 4.82       0.2 4.8  9.8 5.8       0.1 23.74 7.74 28.74       0.4
5 4.82 9.82 5.82       0.1 5.8 10.8 6.8       0.1 24.74 8.74 29.74       0.1
© www.soinside.com 2019 - 2024. All rights reserved.