我想在列名称中由模式定义的不同列集上按行计算累积平均值。
示例数据,两组列分别以a
和b
开头:
a1 = c(1, 2, 3)
a2 = c(4, 5, 6)
a3 = c(7, 8, 9)
a4 = c(10, 11, 12)
b1 = c(10, 20, 30)
b2 = c(40, 50, 60)
b3 = c(70, 80, 90)
b4 = c(100, 110, 120)
df = data.frame(a1, a2, a3, a4, b1, b2, b3, b4)
> df
a1 a2 a3 a4 b1 b2 b3 b4
1 1 4 7 10 10 40 70 100
2 2 5 8 11 20 50 80 110
3 3 6 9 12 30 60 90 120
第一组计算在名称以< code>a开头的列中执行:
a1_2
是a1
和a2
。
a1_3
是 a1、a2
和 a3
的平均值。
< code>a1_4是< code>a1 、< code>a2 、< code>a3和< code>a4的平均值。
同样,我想对“< code>b列”执行相同的计算:< code>b1_2 、< code>b1_3和< code>b1_4的计算方式与< code>a1_2 、< code>a1_3和< code>a1_4完全相同。
我可以用以下代码生成a1_2
到b1_4
。但在实际情况中,我有太多类似的变量要生成。
library(dplyr)
df %>%
rowwise() %>%
mutate(a1_2 = mean(c(a1, a2)),
a1_3 = mean(c(a1, a2, a3)),
a1_4 = mean(c(a1, a2, a3, a4)),
b1_2 = mean(c(b1, b2)),
b1_3 = mean(c(b1, b2, b3)),
b1_4 = mean(c(b1, b2, b3, b4))) %>%
ungroup()
a1 a2 a3 a4 b1 b2 b3 b4 a1_2 a1_3 a1_4 b1_2 b1_3 b1_4
1 1 4 7 10 10 40 70 100 2.5 4 5.5 25 40 55
2 2 5 8 11 20 50 80 110 3.5 5 6.5 35 50 65
3 3 6 9 12 30 60 90 120 4.5 6 7.5 45 60 75
如何更高效地执行这些计算,而不必手动逐个生成?这些生成的变量有一个模式,该模式用于计算多个变量的平均值。
我查了一个与我相关的问题(需要同时使用R中的Cross()创建多个新变量)。但是在这个问题中,作者生成的新变量与数据帧中的其他变量不相关,这与我遇到的问题不一样。
这是基本R中的另一种方法:
rowMeans
应用于以变量 v
开头的列集。“a”和“
b
”将原始 data.frame 与包装器的输出绑定(在具有许多不同变量名称的情况下,这可以推广)。rowMeansAcc <- function(df, v) {
m <- as.matrix(df[, grep(v, colnames(df))])
m_mean <- sapply(1:ncol(m), \(i) rowMeans(m[, 1:i, drop = FALSE]))[, -1, drop = FALSE]
colnames(m_mean) <- sprintf("%s1_%d", v, 2:ncol(m))
m_mean
}
cbind(df, rowMeansAcc(df, "a"), rowMeansAcc(df, "b"))
#> a1 a2 a3 a4 b1 b2 b3 b4 a1_2 a1_3 a1_4 b1_2 b1_3 b1_4
#> 1 1 4 7 10 10 40 70 100 2.5 4 5.5 25 40 55
#> 2 2 5 8 11 20 50 80 110 3.5 5 6.5 35 50 65
#> 3 3 6 9 12 30 60 90 120 4.5 6 7.5 45 60 75
注意:我们可以稍微修改包装器函数,使其直接用于例如 mutate()
调用,
rowMeansAcc2 <- function(...) {
m <- cbind(...)
m_mean <- sapply(1:ncol(m), \(i) rowMeans(m[, 1:i, drop = FALSE]))[, -1, drop = FALSE]
colnames(m_mean) <- sprintf("1_%d", 2:ncol(m))
m_mean
}
mutate(df, "a" = rowMeansAcc2(a1, a2, a3, a4), "b" = rowMeansAcc2(b1, b2, b3, b4))
#> a1 a2 a3 a4 b1 b2 b3 b4 a.1_2 a.1_3 a.1_4 b.1_2 b.1_3 b.1_4
#> 1 1 4 7 10 10 40 70 100 2.5 4.0 5.5 25 40 55
#> 2 2 5 8 11 20 50 80 110 3.5 5.0 6.5 35 50 65
#> 3 3 6 9 12 30 60 90 120 4.5 6.0 7.5 45 60 75
这里是一个管道中的<code>dplyr</code>选项(感谢@jav的出色方法):
library(dplyr)
library(tidyr)
df %>%
mutate(id = row_number()) %>%
pivot_longer(cols = -id) %>%
mutate(group = sub("^([[:alpha:]]*).*", "\\1", name),
number = gsub(".*?([0-9]+).*", "\\1", name)) %>%
group_by(id, group) %>%
mutate(avg_value = cummean(value),
col_name := paste0(group, min(number), "_", number)) %>%
filter(number != 1) %>%
pivot_wider(id_cols = id, names_from = col_name, values_from = avg_value) %>%
group_by(id) %>%
fill(everything(), .direction = "downup") %>%
slice(1) %>%
merge(df %>% mutate(id = row_number()), ., by = 'id') %>%
select(-id)
#> a1 a2 a3 a4 b1 b2 b3 b4 a1_2 a1_3 a1_4 b1_2 b1_3 b1_4
#> 1 1 4 7 10 10 40 70 100 2.5 4 5.5 25 40 55
#> 2 2 5 8 11 20 50 80 110 3.5 5 6.5 35 50 65
#> 3 3 6 9 12 30 60 90 120 4.5 6 7.5 45 60 75
创建于 2022-09-18,使用reprex v2.0.2
我不知道如何使用突变
来解决这个问题,但我可以向您展示一种使用data.table的方法
。
首先,我将解释我处理这个问题的方法:
>
首先,对于以a
开头的列,您要查找(a1, a2)
的平均值、的平均值(a1, a2, a3)
等。我将简化为仅调用这些(1,2)
的平均值、(1,2,3)
的平均值等。从表面上看,我们可以重新措辞,因为您需要跨列分组的累积平均值
。
我们可以尝试按组使用 cummean
,但这仅适用于行。
因此,我们只需将数据集重设为长格式,执行<code>cummean
导入包:
library(data.table)
library(dplyr)
将您的数据帧转换为data.table
格式:
setDT(df)
向数据框添加行号:
df[, row_id := .I]
重新调整为长格式:
df2 = melt.data.table(df, id.vars = "row_id")
此时,您的数据如下所示:
row_id variable value
1: 1 a1 1
2: 2 a1 2
3: 3 a1 3
4: 1 a2 4
5: 2 a2 5
6: 3 a2 6
7: 1 a3 7
8: 2 a3 8
9: 3 a3 9
10: 1 a4 10
11: 2 a4 11
12: 3 a4 12
13: 1 b1 10
14: 2 b1 20
15: 3 b1 30
16: 1 b2 40
17: 2 b2 50
18: 3 b2 60
19: 1 b3 70
20: 2 b3 80
21: 3 b3 90
22: 1 b4 100
23: 2 b4 110
24: 3 b4 120
让我们从数字中分离出字母,以便我们可以按字母创建组:
df2[, group := substr(variable, 1, 1)]
df2[, number := as.numeric(gsub("[[:alpha:]]", "", variable))]
在这一点上,我们有:
row_id variable value group number
1: 1 a1 1 a 1
2: 2 a1 2 a 1
3: 3 a1 3 a 1
4: 1 a2 4 a 2
5: 2 a2 5 a 2
6: 3 a2 6 a 2
7: 1 a3 7 a 3
8: 2 a3 8 a 3
9: 3 a3 9 a 3
10: 1 a4 10 a 4
11: 2 a4 11 a 4
12: 3 a4 12 a 4
13: 1 b1 10 b 1
14: 2 b1 20 b 1
15: 3 b1 30 b 1
16: 1 b2 40 b 2
17: 2 b2 50 b 2
18: 3 b2 60 b 2
19: 1 b3 70 b 3
20: 2 b3 80 b 3
21: 3 b3 90 b 3
22: 1 b4 100 b 4
23: 2 b4 110 b 4
24: 3 b4 120 b 4
现在,我们可以通过row_id
和分组
来获取累积值
均值:
df2[, avg_val :=cummean(value), by=c("row_id", "group")]
然后我们创建您的列命名约定,如下所示:
df2[, col_name := paste0(group, min(number), "_", number)]
在这一点上,我们有:
row_id variable value group number avg_val col_name
1: 1 a1 1 a 1 1.0 a1_1
2: 2 a1 2 a 1 2.0 a1_1
3: 3 a1 3 a 1 3.0 a1_1
4: 1 a2 4 a 2 2.5 a1_2
5: 2 a2 5 a 2 3.5 a1_2
6: 3 a2 6 a 2 4.5 a1_2
7: 1 a3 7 a 3 4.0 a1_3
8: 2 a3 8 a 3 5.0 a1_3
9: 3 a3 9 a 3 6.0 a1_3
10: 1 a4 10 a 4 5.5 a1_4
11: 2 a4 11 a 4 6.5 a1_4
12: 3 a4 12 a 4 7.5 a1_4
13: 1 b1 10 b 1 10.0 b1_1
14: 2 b1 20 b 1 20.0 b1_1
15: 3 b1 30 b 1 30.0 b1_1
16: 1 b2 40 b 2 25.0 b1_2
17: 2 b2 50 b 2 35.0 b1_2
18: 3 b2 60 b 2 45.0 b1_2
19: 1 b3 70 b 3 40.0 b1_3
20: 2 b3 80 b 3 50.0 b1_3
21: 3 b3 90 b 3 60.0 b1_3
22: 1 b4 100 b 4 55.0 b1_4
23: 2 b4 110 b 4 65.0 b1_4
24: 3 b4 120 b 4 75.0 b1_4
我们可以去掉number=1
的行,因为它们代表原始数据。从那里,我们可以将其转换为宽格式,并合并回原始数据:
df2 = df2[number != 1]
result = dcast.data.table(df2, row_id ~ col_name, value.var = "avg_val")
result = merge(df, result, by = "row_id")
result[, row_id := NULL]
最终的结果是:
a1 a2 a3 a4 b1 b2 b3 b4 a1_2 a1_3 a1_4 b1_2 b1_3 b1_4
1: 1 4 7 10 10 40 70 100 2.5 4 5.5 25 40 55
2: 2 5 8 11 20 50 80 110 3.5 5 6.5 35 50 65
3: 3 6 9 12 30 60 90 120 4.5 6 7.5 45 60 75
问题内容: 我正在尝试使用下面的代码来计算用户输入的一组值的平均值,并将其显示在中,但它无法正常工作。假设用户输入7、4和5,该程序在应显示5.3时显示平均值。 代码有什么问题? 问题答案: 当您拥有增强的for循环时,为什么还要对索引使用笨拙的for循环?
我试图使用下面的代码来计算用户输入的一组值的平均值,并将其显示在中,但它不能正常工作。例如,用户输入7、4和5,程序显示1作为平均值,而它应该显示5.3
我有一个由66个变量的10299个观测值组成的数据框。其中一些变量共享一个通用的列名,我想计算每个观测值的这些变量的平均值。 具有以下矩阵,列名: 我想得到: 我尝试了循环,命令,但没有得到所需的结果。 抱歉,如果这个问题看起来太基本了,我已经在谷歌上查过可能的解决方案,但没有找到任何解决方案。
问题内容: Y1961 Y1962 Y1963 Y1964 Y1965 Region 0 82.567307 83.104757 83.183700 83.030338 82.831958 US 1 2.699372 2.610110 2.587919 2.696451 2.846247 US 2 14.131355 13.690028 13.599516 13.649176 13.649046
问题内容: 任何人都知道如何计算这些列之一的平均值(在Linux上)? 例如:mean(第2栏) 问题答案: Awk: 读为: 对于每一行,将第2列添加到变量“总计”中。 在文件末尾,打印“总计”除以记录数。
我们的教授在一个文本文件中给了我们一份982个数字的列表,我们已经阅读了文件中的文本,并打印出了一些关于数字的信息。到目前为止,除了奇数的总数之外,我的一切都是正确的(她给了我们正确的答案)。我不知道如何得到奇数的平均值,即48201.56。 我一直得到的结果是97354,这很奇怪,因为我用的方法和所有数字的平均值和偶数的平均值是一样的。 我想知道为什么“总平均数”的答案不是48201.56。谢谢