用循环将R中的大文件分割成更小的文件

问题描述 投票:0回答:4

我有一个包含 12,626,756 行的 csv 文件,我需要将其拆分为更小的文件,以便同事可以在 Excel 中打开它们。我想创建一个循环,将文件拆分为适合 Excel 行限制的文件,并将它们导出为 CSV 文件,直到到达末尾(它应该生成 13 个文件)

#STEP 1: load data
data <- read.csv(".../Desktop/Data/file.csv", header = TRUE)

#STEP 2: count rows
totalrows <- nrow(data)

#STEP 3: determine how many splits you need 
excelrowlimit <- 1048576 - 5
filesrequired <- ceiling(totalrows/ excelrowlimit)

例如:

csvfile 1 should contain rows 1:1048571
csvfile 2 should contain rows 1048572:2097143
csvfile 3 should contain rows 2097144:3145715
csvfile 4 should contain rows 3145716:4194287
... and so on

如何编写一个循环语句,(1) 按所需文件数量进行分割,(2) 为每个 csv 导出提供不同的文件名?

r loops csv large-files
4个回答
1
投票

这是扩展我上面评论的解决方案。这应该比任何其他解决方案具有更小的内存需求,因为它不需要复制全部或部分原始数据帧。

library(tidyverse)

rowCount <- 1048571
data %>% 
  mutate(Group = ceiling((row_number()) / rowCount)) %>% 
  group_by(Group) %>% 
  group_walk(
    function(.x, .y) {
      write.csv(.x, file = paste0("file", .y$Group, ".csv"))
    }
  )


0
投票

这是如何实现此目的的示例,您可以使用

split_at
设置所需的文件大小。

在最后一部分中,您当然可以根据需要更改 write_csv 参数,例如设置路径、分隔符等

library(tidyverse)

split_at <- 5

data.frame(x = 1:19) %>%
  mutate(group = (row_number() - 1) %/% !! split_at) %>%
  group_split(group) %>%
  map(.f = ~write_csv(.x, file = paste0('file ', unique(.x$group), '.csv')))

0
投票

我假设每500行分割数据。您可以将一列变异为标签组。然后放入for循环根据该列写出csv。

#STEP 1: load data
data <- read.csv(".../Desktop/Data/file.csv", header = TRUE)

# mutate a column to lable the group
data <- data %>% mutate(Group = ceiling(1:nrow(.)/500))

# write out csv by group
for(i in unique(data$Group)){
  data %>% filter(Group == i) %>% select(-Group) %>%
    write.csv(paste0("/your/path/",i,".csv"))
}

0
投票

这将确定 csv 的长度,然后一次只读取所需的块以进行写入。这是为了潜在地避免较大文件/内存不足的内存问题。每个文件都将具有相同的标头,并在相同的文件名后附加一个数字。 Excel 行限制可能略高于 1m,因此使用它作为行大小


inputFile <- 'yourFile.csv'

library(data.table)

rowsDone <- 0
counter <- 0

# number of rows per file
chunkSize = 1000000

totalRows <- nrow(fread(inputFile, header = F, select = 1L))
header <- names(fread(inputFile, nrows = 0))

while (rowsDone < totalRows)
{
    chunkSize <- min(totalRows - rowsDone, chunkSize)
    print(paste0('writing rows: ', rowsDone + 1, ' to ', rowsDone + chunkSize))
    tempDF <- fread(inputFile, nrows = chunkSize, skip = rowsDone, header = F) # ignores header   
    names(tempDF) <- header
    if (counter == 0) tempDF <- tempDF[-1]
    rowsDone <- rowsDone + chunkSize
    counter <- counter + 1
    fwrite(tempDF, paste0(sub('.csv', '', inputFile), '_', counter, '.csv'))
}
© www.soinside.com 2019 - 2024. All rights reserved.