以编程方式编辑,过滤并保存R中大文件列表中每个文本文件的数据?

时间:2018-03-17 23:01:20

标签: r datatable dplyr data-manipulation data-cleaning

我已经下载了德国的历史天气数据,这些数据总共存储在1080 txt个文件中(原始数据可在此ftp中找到:German weather historical data),其中每个气象站都有数据存储在各自的txt格式文件中。

然而,在我的研究案例中,我只需要在每个文件中保持01-01-1980 ~ 31-12-2014之间的天气数据记录,其中每个单独的文本文件包含超过上述指定日期间隔的天气数据(大约100年的天气数据) (不连续))。如果我手动编辑每个txt文件并且仅保留从01-01-198031-12-2014的天气数据记录,那将是非常低效和艰苦的工作。也许有一种方法可以编程方式编辑每个文本文件,只保留满足我指定日期范围的天气数据记录,同时必须删除其余的数据记录,并保存文件的原始格式和名称。

我以.txt格式下载了所有数据记录并将其加载到我的R会话中。我能读懂它们。但以编程方式编辑并保留我感兴趣的天气数据记录对我来说是未知的。如何在R中轻松实现这一点?在R中这样做是否可行?

以下是数据的样子:

> head(ClmData_files)
[1] "stella/data/germany_histData/produkt_klima_monat_17190101_20161231_00403.txt"
[2] "stella/data/germany_histData/produkt_klima_monat_17570301_19611130_01425.txt"
[3] "stella/data/germany_histData/produkt_klima_monat_17810101_20161231_02290.txt"
[4] "stella/data/germany_histData/produkt_klima_monat_17880101_20161231_05099.txt"
[5] "stella/data/germany_histData/produkt_klima_monat_17920101_19840731_04927.txt"
[6] "stella/data/germany_histData/produkt_klima_monat_18010101_19531231_03382.txt"
> tail(ClmData_files)
[1] "stella/data/germany_histData/produkt_klima_monat_20110901_20161231_00161.txt"
[2] "stella/data/germany_histData/produkt_klima_monat_20131101_20161231_15207.txt"
[3] "stella/data/germany_histData/produkt_klima_monat_20140901_20161231_15444.txt"
[4] "stella/data/germany_histData/produkt_klima_monat_20150801_20161231_01246.txt"
[5] "stella/data/germany_histData/produkt_klima_monat_20160501_20161231_15555.txt"
[6] "stella/data/germany_histData/produkt_klima_monat_20160901_20161231_01886.txt"
> length(ClmData_files)
[1] 1080

以下是Notepad++中每个单独文本文件的外观(仅前10行):

STATIONS_ID;MESS_DATUM_BEGINN;MESS_DATUM_ENDE;QN_4;MO_N;MO_TT;MO_TX;MO_TN;MO_FK;MX_TX;MX_FX;MX_TN;MO_SD_S;QN_6;MO_RR;MX_RS;eor
        403;17190101;17190131;    5;  -999;   2.8;   -999;   -999;-999;-999;-999;-999;-999;-999;-999;-999;eor
        403;17190201;17190228;    5;  -999;   1.1;   -999;   -999;-999;-999;-999;-999;-999;-999;-999;-999;eor
        403;17190301;17190331;    5;  -999;   5.2;   -999;   -999;-999;-999;-999;-999;-999;-999;-999;-999;eor
        403;17190401;17190430;    5;  -999;   9.0;   -999;   -999;-999;-999;-999;-999;-999;-999;-999;-999;eor
        403;17190501;17190531;    5;  -999;  15.1;   -999;   -999;-999;-999;-999;-999;-999;-999;-999;-999;eor
        403;17190601;17190630;    5;  -999;  19.0;   -999;   -999;-999;-999;-999;-999;-999;-999;-999;-999;eor
        403;17190701;17190731;    5;  -999;  21.4;   -999;   -999;-999;-999;-999;-999;-999;-999;-999;-999;eor
        403;17190801;17190831;    5;  -999;  18.8;   -999;   -999;-999;-999;-999;-999;-999;-999;-999;-999;eor
        403;17190901;17190930;    5;  -999;  13.9;   -999;   -999;-999;-999;-999;-999;-999;-999;-999;-999;eor
        403;17191001;17191031;    5;  -999;   9.0;   -999;   -999;-999;-999;-999;-999;-999;-999;-999;-999;eor

在我从本地驱动器上方的ftp服务器上下载所有天气数据后,在下面的R中读取它们:

lapply(ClmData_files, function(x) {
  read.table(x,
             sep="\t",
             fill=FALSE,
             strip.white=TRUE)
})

因为每个txt文件都有近100年的天气数据,但我只对近35年来利用回归模型研究未来气候变化趋势感兴趣。现在我需要以编程方式访问每个txt文件,并根据自定义的日期间隔编辑和过滤天气数据记录,并将它们保存在当前的R会话中。有没有办法在动态R编程中实现这一点?有什么想法吗?

更新

我们只需要在每个文件中使用MESS_DATUM_BEGINN (begin date);MESS_DATUM_ENDE (end date)列,并且只保留日期间隔为1980-01-01 ~ 2014-12-31的天气数据记录,并将其保存为csv格式,此类操作必须应用并扩展到所有txt文件(总共1080个文件)。如何在R中以编程方式实现这一点?任何的想法?感谢

更新2

现在我可以使用rdwd软件包下载德国的所有历史天气数据,以下是获取R会话中所有数据的代码:

install.packages("rdwd")
library(rdwd)
ftpURL <- selectDWD(name = "", exactmatch = TRUE, 
                    res="monthly", 
                    var="kl", per="historical", current = TRUE)
ftpFile <- dataDWD(file = ftpURL, dir = "stella/input/",sleep = 0)
rowData <- readDWD(ftpFile, fread = FALSE)

现在各自的历史天气数据都在飞行中:german historical weather data

1 个答案:

答案 0 :(得分:4)

您有多种选择,但它们都是从知道如何正确读取表格开始的。正如评论中提到的那样,你试图使用制表符是分隔符,当数据显然是以分号分隔时,所以尽管可能是那里的标签,你很可能无意中得到了多个列。

所以让我们先在一个文件中阅读。请注意,我使用的是text='...',而您应该使用file='...' ...它只是速记可重现的SO答案。

x <- read.table(text = 'STATIONS_ID;MESS_DATUM_BEGINN;MESS_DATUM_ENDE;QN_4;MO_N;MO_TT;MO_TX;MO_TN;MO_FK;MX_TX;MX_FX;MX_TN;MO_SD_S;QN_6;MO_RR;MX_RS;eor
        403;17190101;17190131;    5;  -999;   2.8;   -999;   -999;-999;-999;-999;-999;-999;-999;-999;-999;eor
        403;17190201;17190228;    5;  -999;   1.1;   -999;   -999;-999;-999;-999;-999;-999;-999;-999;-999;eor
        403;17190301;17190331;    5;  -999;   5.2;   -999;   -999;-999;-999;-999;-999;-999;-999;-999;-999;eor
        403;17190401;17190430;    5;  -999;   9.0;   -999;   -999;-999;-999;-999;-999;-999;-999;-999;-999;eor
        403;17190501;17190531;    5;  -999;  15.1;   -999;   -999;-999;-999;-999;-999;-999;-999;-999;-999;eor
        403;17190601;17190630;    5;  -999;  19.0;   -999;   -999;-999;-999;-999;-999;-999;-999;-999;-999;eor
        403;17190701;17190731;    5;  -999;  21.4;   -999;   -999;-999;-999;-999;-999;-999;-999;-999;-999;eor
        403;17190801;17190831;    5;  -999;  18.8;   -999;   -999;-999;-999;-999;-999;-999;-999;-999;-999;eor
        403;17190901;17190930;    5;  -999;  13.9;   -999;   -999;-999;-999;-999;-999;-999;-999;-999;-999;eor
        403;17191001;17191031;    5;  -999;   9.0;   -999;   -999;-999;-999;-999;-999;-999;-999;-999;-999;eor',
        sep = ';', header = TRUE)
str(x)
# 'data.frame': 10 obs. of  17 variables:
#  $ STATIONS_ID      : int  403 403 403 403 403 403 403 403 403 403
#  $ MESS_DATUM_BEGINN: int  17190101 17190201 17190301 17190401 17190501 17190601 17190701 17190801 17190901 17191001
#  $ MESS_DATUM_ENDE  : int  17190131 17190228 17190331 17190430 17190531 17190630 17190731 17190831 17190930 17191031
#  $ QN_4             : int  5 5 5 5 5 5 5 5 5 5
#  $ MO_N             : int  -999 -999 -999 -999 -999 -999 -999 -999 -999 -999
#  $ MO_TT            : num  2.8 1.1 5.2 9 15.1 19 21.4 18.8 13.9 9
#  $ MO_TX            : int  -999 -999 -999 -999 -999 -999 -999 -999 -999 -999
#  $ MO_TN            : int  -999 -999 -999 -999 -999 -999 -999 -999 -999 -999
#  $ MO_FK            : int  -999 -999 -999 -999 -999 -999 -999 -999 -999 -999
#  $ MX_TX            : int  -999 -999 -999 -999 -999 -999 -999 -999 -999 -999
#  $ MX_FX            : int  -999 -999 -999 -999 -999 -999 -999 -999 -999 -999
#  $ MX_TN            : int  -999 -999 -999 -999 -999 -999 -999 -999 -999 -999
#  $ MO_SD_S          : int  -999 -999 -999 -999 -999 -999 -999 -999 -999 -999
#  $ QN_6             : int  -999 -999 -999 -999 -999 -999 -999 -999 -999 -999
#  $ MO_RR            : int  -999 -999 -999 -999 -999 -999 -999 -999 -999 -999
#  $ MX_RS            : int  -999 -999 -999 -999 -999 -999 -999 -999 -999 -999
#  $ eor              : Factor w/ 1 level "eor": 1 1 1 1 1 1 1 1 1 1

接下来,我们可以将所有日期解析为经典R Date对象,或者我们可以直接将它们作为现在的整数处理;比较可能会以任何方式工作,但为了代码清晰(因为我怀疑你可能想要进行进一步的分析/可视化与实际类似日期的标签)我将进行额外的步骤转换为正确的日期对象:

my_ymd <- function(a) as.Date(as.character(a), format='%Y%m%d')
x[c('MESS_DATUM_BEGINN','MESS_DATUM_ENDE')] <- lapply(x[c('MESS_DATUM_BEGINN','MESS_DATUM_ENDE')], my_ymd)
str(x[c('MESS_DATUM_BEGINN','MESS_DATUM_ENDE')])
# 'data.frame': 10 obs. of  2 variables:
#  $ MESS_DATUM_BEGINN: Date, format: "1719-01-01" "1719-02-01" "1719-03-01" "1719-04-01" ...
#  $ MESS_DATUM_ENDE  : Date, format: "1719-01-31" "1719-02-28" "1719-03-31" "1719-04-30" ...

(有几个软件包可以快速完成并且具有更强大的功能。随意使用它们中的任何一个,我提供了一个简单的基础R方法,鉴于我所看到的。)

从这里开始,过滤掉您想要的日期范围非常简单(请注意,我使用了不同的日期,因为您的示例不包含您要过滤的日期):

keep_ymd <- my_ymd(c("17190401", "17190701"))
keep_ymd
# [1] "1719-04-01" "1719-07-01"
x[keep_ymd[1] <= x$MESS_DATUM_BEGINN & x$MESS_DATUM_ENDE <= keep_ymd[2],,drop=FALSE]
#   STATIONS_ID MESS_DATUM_BEGINN MESS_DATUM_ENDE QN_4 MO_N MO_TT MO_TX MO_TN MO_FK MX_TX MX_FX MX_TN MO_SD_S QN_6 MO_RR MX_RS eor
# 4         403        1719-04-01      1719-04-30    5 -999   9.0  -999  -999  -999  -999  -999  -999    -999 -999  -999  -999 eor
# 5         403        1719-05-01      1719-05-31    5 -999  15.1  -999  -999  -999  -999  -999  -999    -999 -999  -999  -999 eor
# 6         403        1719-06-01      1719-06-30    5 -999  19.0  -999  -999  -999  -999  -999  -999    -999 -999  -999  -999 eor

因此,要使用lapply将其与初始代码相结合,我可能会执行以下操作:

rawdata <- lapply(ClmData_files, read.table, sep=';', header=TRUE)
filtered <- lapply(rawdata, function(x) {
  x[c('MESS_DATUM_BEGINN','MESS_DATUM_ENDE')] <- lapply(x[c('MESS_DATUM_BEGINN','MESS_DATUM_ENDE')], my_ymd)
  x[keep_ymd[1] <= x$MESS_DATUM_BEGINN & x$MESS_DATUM_ENDE <= keep_ymd[2],,drop=FALSE]
})

(我倾向于加载原始数据并保留它,直到我确信我的前几步是稳固的。)

修改

我认为(未经测试)以下dplyr(和朋友)管道可能有效:

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

data_frame(fname = ClmData_files) %>%
  mutate(data = map(fname, ~ read.table(., sep=':', header=TRUE))) %>%
  mutate_at(vars(MESS_DATUM_BEGINN, MESS_DATUM_ENDE), funs(my_ymd)) %>%
  unnest() %>%
  filter(
    between(MESS_DATUM_BEGINN, keep_ymd[1], keep_ymd[2]),
    between(MESS_DATUM_ENDE, keep_ymd[1], keep_ymd[2])
  )