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 中的值,因为 df2df3 中只有 7 行。

【问题讨论】:

强烈建议:如果您的数据是月度数据,则将月份放入数据中。虽然您可能“知道”每一帧都从第 1 个月(或第 0 个月)开始,但最好以编程方式删除该静默假设并将其明确包含在数据中。这将启用许多其他流程和方法,这些流程和方法对您在此处尝试的操作来说不那么脆弱,并且可以防止稍后在您的数据管道中出现大的“错误”。 查看在线文档中的 rm.na = TRUE。 我不是说要对实际日期进行编码,而是说要对您在每一行中假设的月份数进行编码。接受或离开它,但当数据的顺序在处理过程中无意(无声地)改变时,我已经浪费了很多时间来调试推断的时间线。 (我犯了同样的错误,在我的研究生论文数据争论上辛苦了一个多月。)对你来说,我觉得不明确“时间”会使你的数据变得脆弱。 @r2evans 两点都很好。我永远得到rmna 错误的方式。关于未提及平均功能也是如此。但我觉得这是一个合理的假设。顺便说一句:我一直很重视你的贡献。 “我在当前数据格式中使用均值时遇到问题”。从而挂了一个故事。我了解到,如果我发现自己沿着这些思路思考,那么问题的根源很可能是我的数据格式,我应该退后一步。 @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 的 length 也说明了该统计的“强度”(即弱)。

【讨论】:

【参考方案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?

具有不同行数的 Scikit Learn 特征联合

Python Pandas - 连接两个具有不同行数和列数的数据框

如何计算不同数据框的列之间的数值差异?

删除具有任意行数的数据框中的最后 N 行

如何在限制行数的同时拆分 Pyspark 数据帧?