如何汇总几个.csv文件(具有145行和140列的网格数据“单元”)以获取具有相同尺寸的csv文件

时间:2019-06-03 17:46:21

标签: r

我有几个从csv文件提取的文件(NetCDF格式)。它是我下载的在线数据(月降水量网格数据“单元”有145行和139列) 我需要对每年(超过60年)的每月.csv文件进行求和,而不是对60次求和进行平均。

[出发!我曾经回答过的问题(不是最聪明的回答,而是我与之合作过的回答) PS:您可以创建一个包含日期和汇总的数据框,以非常快速地运行(如果您有大量数据,则以某种方式!)

1-第一步,我通过使用“数据”字段为每年创建“曲目”来组织我的所有数据,这虽然很长,但是很有效! ,

2-然后,我为每个月创建一个数据框,这里是1940年第一个月

 df1<-read.csv2(file= "./1940-01-01.csv", sep="," , dec="." )
 df2<-read.csv2(file=   "./1940-02-01.csv", sep="," , dec="." ) 
    ...
 df12<- read.csv2(file=   "./1940-12-01.csv", sep="," , dec="." )

您的数据框将在全局环境中可见

3-我对所有数据帧(每个单元格)求和,结果得到一个具有145(ROWS)和(141 COLUMNS)[相同尺寸]的数据帧

对于1940年

 df_1940_sum <-df1+df2+df3+df4+df5+df6+df7+df8+df9+df10+df11+df12 

4-我在我的曲目中将结果作为输出(csv文件)

write.table(df_sum, file="df_1940.csv", sep= ",")

1 个答案:

答案 0 :(得分:1)

三种可能的解决方案,取决于您的严格需求。

从您的df开始,我们创建三个列表。既然有这么多列,我将只关注少数几个列,但是所有其他列的计算都已完成。

dflst <- list(df, df, df)
df[, c("X", "V1", "V20", "V21", "V34")]
#   X V1   V20   V21   V34
# 1 1 NA 63.06 36.64 11.69
# 2 2 NA 38.49 31.73    NA

TL,DR::我认为“ 案例3 ”可能是给定一些假设中三个案例中最好的(最灵活,最可靠),在这种情况下,您可以跳过这种“列名条件”和情况1-2,然后直接跳到底部。


预处理:帧条件

在某些情况下的一个假设是,所有框架的尺寸均相同,并且所有列的顺序相同。如果始终都是这样,那么您可以跳过此“调节”步骤。

但是,如果这不是一个安全的假设,则可以从某种意义上“调节”它们。我将用三个伪造的框架列表进行演示,所有伪造的框架都略有不同:

somelst <- list(data.frame(x=1,y=2), data.frame(y=3, x=4), data.frame(x=5, z=6))
some_names <- names(somelst[[1]])
somelst <- lapply(somelst, `[`, some_names)
# Error in `[.data.frame`(X[[i]], ...) : undefined columns selected

要解决此问题,我们只需要使用通用名称即可。请注意,如果发生这种情况,则下一步将 静默丢弃 非标准列。

somelst <- lapply(somelst, function(l) l[, intersect(some_names, names(l)), drop=FALSE])
somelst
# [[1]]
#   x y
# 1 1 2
# [[2]]
#   x y
# 1 4 3
# [[3]]
#   x
# 1 5

列的顺序现在是标准的,但是(与下面的情况1-2有关),我们缺少列。修复:

somelst <- lapply(somelst, function(l) { l[, setdiff(some_names, names(l))] <- NA; l; })
somelst
# [[1]]
#   x y
# 1 1 2
# [[2]]
#   x y
# 1 4 3
# [[3]]
#   x  y
# 1 5 NA

(最后一步只是为缺少的列添加全{NA值。)

因此,我将其应用于我们的数据(尽管我们知道这里没有操作,因为所有列表元素都是相同的框架):

df_names <- names(dflst[[1]])
dflst <- lapply(dflst, function(l) l[, intersect(df_names, names(l)), drop=FALSE])
dflst <- lapply(dflst, function(l) { l[, setdiff(df_names, names(l))] <- NA; l; })

情况1:X是数据

我认为这不太可能,但是为了完整起见,我将其包括在内,以防最简单的情况确实是预期的:

out <- Reduce(`+`, dflst)
out[, c("X", "V1", "V20", "V21", "V34")]
#   X V1    V20    V21   V34
# 1 3 NA 189.18 109.92 35.07
# 2 6 NA 115.47  95.19    NA

情况2:X是密钥

在这种情况下,我们只是将所有内容加在一起,而没有更改X id。

注意:这假定所有ID均以相同顺序出现在所有帧中。。

out <- df # really just need "X" and the right number of columns
          # ... none of the other values are used
out[,-1] <- Reduce(`+`, lapply(dflst, `[`, -1))
out[, c("X", "V1", "V20", "V21", "V34")]
#   X V1    V20    V21   V34
# 1 1 NA 189.18 109.92 35.07
# 2 2 NA 115.47  95.19    NA

一个人可以通过以下方式验证这一假设:

identical(df$X, Reduce(function(a, b) if (identical(a,b)) a else FALSE, lapply(dflst, `[[`, "X")))
# [1] TRUE

任何区别都将表明造成更多(不是那么简单)的调节或案例3 (这仍然是我的总体建议)的原因。


情况3:变量(但仍然很重要)列名

在这种情况下,我们不必像对列名和顺序进行规范化那样对数据进行预处理,因为它是自然而然的。它确实假设列名是重要且标准的,这意味着如果在一个框架中看到"V22",则意味着在所有框架中都显示"V22",并且其他与"V22"相同。

但是,不是不会假设一帧中的所有名称都在另一帧中,因此可以轻松处理缺少列的情况。如果它们都以相同的顺序存在(就像人们从自动化数据集中所期望的那样),那么它也同样有效。

这可以在base-R和data.table中完成,但是我发现dplyr(和家庭)的识字形式最容易证明:

library(dplyr)
library(purrr)
library(tidyr)

out <- map(dflst, ~ gather(., k, v, -X)) %>%
  bind_rows(.) %>%
  group_by(X, k) %>%
  summarize(v = if (all(is.na(v))) NA_real_ else sum(v, na.rm = TRUE)) %>%
  spread(k, v)
out[, c("X", "V1", "V20", "V21", "V34")]
# # A tibble: 2 x 5
# # Groups:   X [2]
#       X    V1   V20   V21   V34
#   <int> <dbl> <dbl> <dbl> <dbl>
# 1     1    NA  189. 110.   35.1
# 2     2    NA  115.  95.2  NA  

(这是一个tibble,其在控制台上的表示与原始帧有一些显着差异。值得注意的是"V20"的值看起来有所不同,尽管在这种情况下,这只是tibble这是使事情保持“整洁”的有效数字的好方法。如果您改为as.data.frame(out[, c("X", "V1", "V20", "V21", "V34")]),则会看到结果相同。)

说明:

  • map(dflst, ...)对列表中的每个帧执行某事
  • gather(., k, v, -X)正在从“宽”格式转换为“长”格式,在这种格式下,单帧会这样:

    gather(df, k, v, -X) %>% head(.)
    #   X  k  v
    # 1 1 V1 NA
    # 2 2 V1 NA
    # 3 1 V2 NA
    # 4 2 V2 NA
    # 5 1 V3 NA
    # 6 2 V3 NA
    
  • bind_rows(.)正在将一帧帧组合成一个行级联的帧

  • group_by(X, k) %>% summarize(...)进行按ID和按(原始)列的聚合,因此将所有X==1k=="V1"合并为一行,等等。
  • if (all(is.na(v))) NA_real_ else sum(v, na.rm = TRUE)有点骇人听闻;通常我会做 just sum(v, na.rm = TRUE)(否if),但是其他情况下,将全{NA字段保留为NA,其中{ {1}}将其转换为sum。我认为保持“该字段从未有过数据”这一想法很重要,因此,如果全部为0,则保留为NA,否则给出所有非NA的总和字段。
  • NA从“长”格式转换为“宽”格式。