【问题标题】:R: How to aggregate several data frames into a txt file via for loop?R:如何通过for循环将多个数据帧聚合成一个txt文件?
【发布时间】:2019-10-24 22:27:02
【问题描述】:

我有几个包含日期和降水信息的 csv 文件。这是示例数据:

three csv files - sample data

目标:

我想一一读完,那么:

1- 将日期列分为年、月、日。

2- 从每个列中获取特定列。

3- 为从每个 csv 文件中提取的信息创建一个数据框。

4- 最后,将所有这些帧粘贴到一个 txt 文件中。

这是我的代码:

rm(list=ls())

## where is the main folder? 
setwd("C:/Users/Downloadspr_day_ECMWF")  

## reading all csv files:
list_csv_files <- basename(list.files(pattern = ".*_daily_results.*csv", recursive = TRUE))

## a loop here to read all csv files one by one and save their info in one txt file:
result <- list()
counter <- 1

for (i in 1:length(list_csv_files)){ 
  MyData <- read.csv(list_csv_files[[i]], header=TRUE, sep=",")
  head(MyData)

  ## separating year , month , date from the "Date.Precipitation_mm" column inside the csv file:
  date_column <- MyData$Date.Precipitation_mm  
  date_column

  year_date <- format(as.Date(date_column, format="%Y-%m-%d"),"%Y")
  month_date <- format(as.Date(date_column, format="%Y-%m-%d"),"%m")
  day_date <- format(as.Date(date_column, format="%Y-%m-%d"),"%d")

  ## reading Alberta columns in MyData :
  Alberta_column <- MyData$Alberta
  Alberta_column

  ## creating a data frame to put our data inside it:
  txt_file_data_frame <- data.frame(year_date, month_date, day_date, Alberta_column)

  ## a counter to save all data frames consecutively:
  for (j in 1:length(txt_file_data_frame)) {
    result[[counter]] <- txt_file_data_frame[j]
    counter <- counter + 1
  }

}

## write the txt file:
write.table(txt_file_data_frame, file = "myTXT.txt", row.names = FALSE, dec = ".", sep = "\t", quote = FALSE)

但生成的 txt 文件包含最后的 csv 文件信息!!像这样:

我想将所有数据帧保存在最终的 txt 文件中。

有人知道这个挑战的解决方案吗?

任何帮助或评论将不胜感激。

【问题讨论】:

  • 这是样本数据的精美“撕页”视图。虽然我很想知道你用什么来制作它......请不要发布代码/数据/错误的图像:它不能被复制或搜索(SEO),它会破坏屏幕阅读器,它可能不适合在一些移动设备上很好。参考:meta.stackoverflow.com/a/285557/3358272(和xkcd.com/2116)。请直接包含代码或数据(例如,dput(head(x))data.frame(...))。在相关说明中,当 (not if) 指向数据文件的链接失效时,问题变得无法重现,请给我们示例数据(dputdata.frame)。
  • 我建议不要在 for 循环中执行此操作并迭代地构建一个框架:虽然它在逻辑上工作,但要知道 R 将在每次向其中添加行时复制整个 data.frame,因此你不断添加文件它会显着减慢。最好将每个文件一次加载到list 中,然后一次将它们合并。例如,要问标题中的问题,可能是alldat &lt;- do.call(rbind, lapply(list.files(...), read.csv))
  • 一种选择是将write.table 移动到循环内并使用选项append=TRUEcol.names=F。如果您有很多文件,这是低效的,写入磁盘很耗时。
  • r2evans,感谢您的评论。我使用图片并分享玩具代码和示例数据的原因是为了让那些想要自己运行代码的人更直接。顺便说一句,很抱歉这可能导致失禁。至于撕裂的页面,我使用 Snagit 这样做。这是免费的。谷歌一下就行了。

标签: r csv dataframe


【解决方案1】:

使用tidyverse 包,您不需要for 循环。检查此解决方法是否是您所需要的。我试图解释 cmets 中的所有步骤。

# install required packages
if (!require("tidyverse")) install.packages("tidyverse")
#> Loading required package: tidyverse
if (!require("here")) install.packages("here")
#> Loading required package: here
#> here() starts at /tmp/RtmpRFktCG/reprex6c99164b38dd
if (!require("fs")) install.packages("fs")
#> Loading required package: fs

# create a new folder to save the data you shared
dir_create("csv-data")

# get the zip file
csv <- "https://www.dropbox.com/s/lyk5vvt7o7kxydj/csv_files.zip?dl=1"
zip_name <- "csv.zip"
download.file(url = csv, destfile = here("csv-data", zip_name))

# descompress the zip file
unzip(zipfile = here("csv-data", zip_name), exdir = here("csv-data"))

# get data
data <-
  # inform the folder
  here("csv-data") %>%
  # search for csv files
  dir_ls(regexp = "\\.csv") %>% 
  # read and bind the rows
  map_dfr(read_csv, .id = "source") %>% 
  # which files do the lines come from?
  mutate(source = basename(source)) %>% 
  # create date columns based on the previous one
  separate(
    col = Date, 
    into = c("year", "month", "day"), 
    sep = "-"
    ) %>% 
  # select columns 
  select(year, month, day, Alberta)
#> Warning: Missing column names filled in: 'X1' [1]
#> Parsed with column specification:
#> cols(
#>   X1 = col_character(),
#>   `Date/Precipitation_mm` = col_date(format = ""),
#>   Alberta = col_double(),
#>   Athabasca = col_double(),
#>   Beaver = col_double(),
#>   Hay_GreatSlave = col_double(),
#>   Milk = col_double(),
#>   NorthSaskatchewan = col_double(),
#>   Peace_Slave = col_double(),
#>   SouthSaskatchewan = col_double(),
#>   Date = col_date(format = "")
#> )
#> Warning: Missing column names filled in: 'X1' [1]
#> Parsed with column specification:
#> cols(
#>   X1 = col_character(),
#>   `Date/Precipitation_mm` = col_date(format = ""),
#>   Alberta = col_double(),
#>   Athabasca = col_double(),
#>   Beaver = col_double(),
#>   Hay_GreatSlave = col_double(),
#>   Milk = col_double(),
#>   NorthSaskatchewan = col_double(),
#>   Peace_Slave = col_double(),
#>   SouthSaskatchewan = col_double(),
#>   Date = col_date(format = "")
#> )
#> Warning: Missing column names filled in: 'X1' [1]
#> Parsed with column specification:
#> cols(
#>   X1 = col_character(),
#>   `Date/Precipitation_mm` = col_date(format = ""),
#>   Alberta = col_double(),
#>   Athabasca = col_double(),
#>   Beaver = col_double(),
#>   Hay_GreatSlave = col_double(),
#>   Milk = col_double(),
#>   NorthSaskatchewan = col_double(),
#>   Peace_Slave = col_double(),
#>   SouthSaskatchewan = col_double(),
#>   Date = col_date(format = "")
#> )

# check data
data
#> # A tibble: 1,096 x 4
#>    year  month day      Alberta
#>    <chr> <chr> <chr>      <dbl>
#>  1 1950  01    01    0.00131   
#>  2 1950  01    02    0.00170   
#>  3 1950  01    03    0.00142   
#>  4 1950  01    04    0.000156  
#>  5 1950  01    05    0.00105   
#>  6 1950  01    06    0.000792  
#>  7 1950  01    07    0.000622  
#>  8 1950  01    08    0.000267  
#>  9 1950  01    09    0.000339  
#> 10 1950  01    10    0.00000134
#> # … with 1,086 more rows

# save
data %>% 
  write_delim(path = here("csv-data", "myTXT.txt"), delim = "\t")

reprex package (v0.3.0) 于 2019 年 10 月 24 日创建

【讨论】:

  • 多么专业的方法。它完美地工作。但是,由于我在这里共享的玩具代码是一个巨大脚本的一部分,我会选择下一个答案,它对我的​​玩具代码做了一些改动。你是一个伟大的程序员卡罗。非常感谢您的宝贵时间。
【解决方案2】:

当你应该写出result时,你写出txt_file_data_frame

在不更改代码的情况下,只需将第二个 for 循环替换为您根本不需要的循环:

## creating a data frame to put our data inside it:   
txt_file_data_frame <- data.frame(year_date, month_date, day_date, Alberta_column)

result[[i]] <- txt_file_data_frame
} # end of for loop

然后写出你的文件,将你的结果绑定在一起并写入磁盘

txt_out <- do.call(rbind, result)

## write the txt file:
write.table(txt_out, file = "myTXT.txt", row.names = FALSE, dec = ".", sep = "\t", quote = FALSE)

您也可以删除counter,因为它不需要。

【讨论】:

  • 非常感谢 MxblsdI。这对我很有效。然而,我们只需要这样一个简单的位移:txt_out &lt;- do.call(rbind, result)
  • 哎呀。编辑以反映@Canada2015 评论。我总是把那个功能倒过来。
【解决方案3】:

目前,您只将txt_file_data_frame 的最后一次迭代(在每个循环中重新分配)写入文件,而从不使用results 对象。只需分配给列表,外部循环绑定所有行,然后写入文件。也不需要counter,因为您可以使用for 迭代器i

## reading all csv files:
list_csv_files <- list.files(pattern = ".*_daily_results.*csv", recursive = TRUE)

## INITIALIZE LIST WITH LENGTH
df_list <- vector(mode=list, length=length(list_csv_files))

for (i in 1:length(list_csv_files)){ 
  MyData <- read.csv(list_csv_files[[i]], header=TRUE, sep=",")
  head(MyData)

  ## separating year , month , date from the "Date.Precipitation_mm" column
  date_column <- MyData$Date.Precipitation_mm  
  date_column

  ## creating a data frame to put our data inside it:
  txt_file_data_frame <- data.frame(
                year_date = format(as.Date(date_column, format="%Y-%m-%d"),"%Y"),
                month_date = format(as.Date(date_column, format="%Y-%m-%d"),"%Y"),
                day_date = format(as.Date(date_column, format="%Y-%m-%d"),"%d"),
                Alberta_column = MyData$Alberta
  )

  ## a counter to save all data frames consecutively:      
  df_list[[i]] <- txt_file_data_frame      
}

# BIND ALL DFs TO ONE    
final_df <- do.call(rbind, df_list)

## write the txt file:
write.table(final_df, file = "myTXT.txt", row.names = FALSE, 
            dec = ".", sep = "\t", quote = FALSE)

【讨论】:

  • 你太棒了。我希望我能像你一样编写高级代码。如上所述,我接受了第二个答案。但是,您的方法效果很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-05-29
  • 1970-01-01
  • 1970-01-01
  • 2021-10-15
  • 2021-08-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多