R中具有不同行数的数据帧之间的算术
Posted
技术标签:
【中文标题】R中具有不同行数的数据帧之间的算术【英文标题】:Arithmetic between dataframes with varying numbers of rows in R 【发布时间】:2021-08-13 23:07:15 【问题描述】:我有包含植物生长月度数据的对象。每个对象是固定数量的列,行数等于植物存活的月数。我想取这些对象的平均值,以便平均值只考虑在给定时间步长存活的植物。这是示例数据:
df1 <- data.frame(GPP = 1:10, NPP = 1:10)
df2 <- data.frame(GPP = 2:8, NPP = 2:8)
df3 <- data.frame(GPP = 3:9, NPP = 3:9 )
在这种情况下,最大时间步长为 10,而第 2 和第 3 株植物没有存活这么久。取平均值,我最初的想法是用NA
替换空白空间以使尺寸相同,例如:
na <- matrix( , nrow = 3, ncol = 2)
colnames(na) <- c("GPP","NPP")
df2 <- rbind(df2, na)
df3 <- rbind(df3, na)
这是不可取的,因为NA
并没有像我希望的那样简单地忽略该值,而是使该字段无效,导致所有算术输出与NA
变为NA
,例如:
(df1 + df2 + df3) / 3
GPP NPP
1 2 2
2 3 3
3 4 4
4 5 5
5 6 6
6 7 7
7 8 8
8 NA NA
9 NA NA
10 NA NA
我不能只用 0 填充 na
,因为我想查看在给定时间步长内存活的每株植物的平均值,而完全忽略那些已经死亡的植物。用 0 代替会扭曲均值,而无法实现这一点。对于我在这里的示例数据,这是期望的结果
(df1 + df2 + df3) / 3
GPP NPP
1 2 2
2 3 3
3 4 4
4 5 5
5 6 6
6 7 7
7 8 8
8 8 8
9 9 9
10 10 10
这里第 8-10 行被替换为 df1
中的值,因为 df2
和 df3
中只有 7 行。
【问题讨论】:
强烈建议:如果您的数据是月度数据,则将月份放入数据中。虽然您可能“知道”每一帧都从第 1 个月(或第 0 个月)开始,但最好以编程方式删除该静默假设并将其明确包含在数据中。这将启用许多其他流程和方法,这些流程和方法对您在此处尝试的操作来说不那么脆弱,并且可以防止稍后在您的数据管道中出现大的“错误”。 查看在线文档中的 rm.na = TRUE。 我不是说要对实际日期进行编码,而是说要对您在每一行中假设的月份数进行编码。接受或离开它,但当数据的顺序在处理过程中无意(无声地)改变时,我已经浪费了很多时间来调试推断的时间线。 (我犯了同样的错误,在我的研究生论文数据争论上辛苦了一个多月。)对你来说,我觉得不明确“时间”会使你的数据变得脆弱。 @r2evans 两点都很好。我永远得到rm
和na
错误的方式。关于未提及平均功能也是如此。但我觉得这是一个合理的假设。顺便说一句:我一直很重视你的贡献。
“我在当前数据格式中使用均值时遇到问题”。从而挂了一个故事。我了解到,如果我发现自己沿着这些思路思考,那么问题的根源很可能是我的数据格式,我应该退后一步。 @Zulkifli 似乎给了你一个合理的解决方案。
【参考方案1】:
我将重申我的评论:在您做任何其他事情之前,在原始数据中编码月份通常会更安全;它是明确的,并且将使您免受管道中稍后可能无意中更改行顺序的错误的影响(这完全破坏了您希望获得的任何有效意义)。此外,由于我将建议将所有数据放入一帧中,因此我们也将植物编号编码(即使我们在这里不立即使用它)。
为此,那么:
df1 <- data.frame(plant = "A", month = 1:10, GPP = 1:10, NPP = 1:10)
df2 <- data.frame(plant = "B", month = 1:7, GPP = 2:8, NPP = 2:8)
df3 <- data.frame(plant = "C", month = 1:7, GPP = 3:9, NPP = 3:9)
因此,我非常喜欢将所有数据都放在一个帧中。 https://***.com/a/24376207/3358227 对此非常了解,其中一个前提是,如果您要对一堆帧做同样的事情,它应该是一个帧列表或一个组合帧(保留源id 编码):
dfs <- do.call(rbind, list(df1, df2, df3))
### just a sampling, for depiction
dfs[c(1:2, 10:12, 17:19),]
# plant month GPP NPP
# 1 A 1 1 1
# 2 A 2 2 2
# 10 A 10 10 10
# 11 B 1 2 2
# 12 B 2 3 3
# 17 B 7 8 8
# 18 C 1 3 3
# 19 C 2 4 4
基础 R
aggregate(cbind(GPP, NPP) ~ month, data = dfs, FUN = mean, na.rm = TRUE)
# month GPP NPP
# 1 1 2 2
# 2 2 3 3
# 3 3 4 4
# 4 4 5 5
# 5 5 6 6
# 6 6 7 7
# 7 7 8 8
# 8 8 8 8
# 9 9 9 9
# 10 10 10 10
dplyr
library(dplyr)
dfs %>%
group_by(month) %>%
summarize(across(c(GPP, NPP), mean))
# # A tibble: 10 x 3
# month GPP NPP
# <int> <dbl> <dbl>
# 1 1 2 2
# 2 2 3 3
# 3 3 4 4
# 4 4 5 5
# 5 5 6 6
# 6 6 7 7
# 7 7 8 8
# 8 8 8 8
# 9 9 9 9
# 10 10 10 10
旁白:您在此摘要中“丢失”的两个数据是数据的大小和每个月的可变性。您可以将它们包括在:
dfs %>%
group_by(month) %>%
summarize(across(c(GPP, NPP), list(mu = ~ mean(.), sigma = ~ sd(.), len = ~ length(.))))
# # A tibble: 10 x 7
# month GPP_mu GPP_sigma GPP_len NPP_mu NPP_sigma NPP_len
# <int> <dbl> <dbl> <int> <dbl> <dbl> <int>
# 1 1 2 1 3 2 1 3
# 2 2 3 1 3 3 1 3
# 3 3 4 1 3 4 1 3
# 4 4 5 1 3 5 1 3
# 5 5 6 1 3 6 1 3
# 6 6 7 1 3 7 1 3
# 7 7 8 1 3 8 1 3
# 8 8 8 NA 1 8 NA 1
# 9 9 9 NA 1 9 NA 1
# 10 10 10 NA 1 10 NA 1
在这种情况下,8
的平均值可能是有意义的,但注意到它是 1 的 len
gth 也说明了该统计的“强度”(即弱)。
【讨论】:
【参考方案2】:library(dplyr)
df1 <- data.frame(month = 1:10, GPP = 1:10, NPP = 1:10)
df2 <- data.frame(month = 1:7, GPP = 2:8, NPP = 2:8)
df3 <- data.frame(month = 1:7, GPP = 3:9, NPP = 3:9 )
df <- rbind(df1, df2, df3)
df %>%
group_by(month) %>%
summarise(GPP = mean(GPP),
NPP = mean(NPP))
month GPP NPP
<int> <dbl> <dbl>
1 1 2 2
2 2 3 3
3 3 4 4
4 4 5 5
5 5 6 6
6 6 7 7
7 7 8 8
8 8 8 8
9 9 9 9
10 10 10 10
【讨论】:
你是用 dplyr 做的吗? 哦,我的错。是的 group_by 和 summarise 是 dplyr 中的函数【参考方案3】:使用data.table
library(data.table)
rbindlist(mget(ls(pattern = '^df\\d+$')))[, lapply(.SD, mean), month]
【讨论】:
以上是关于R中具有不同行数的数据帧之间的算术的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI:如何创建具有相同行数和列数的 LazyGrid?