Быстрое чтение очень больших таблиц как данных


504

У меня есть очень большие таблицы (30 миллионов строк), которые я хотел бы загрузить в виде фреймов данных в R. read.table()Имеет много удобных функций, но, похоже, в реализации много логики, которая может замедлить работу. В моем случае, я предполагаю, что знаю типы столбцов заранее, таблица не содержит заголовков столбцов или имен строк и не имеет патологических символов, о которых мне нужно беспокоиться.

Я знаю, что чтение в таблице в виде списка scan()может быть довольно быстрым, например:

datalist <- scan('myfile',sep='\t',list(url='',popularity=0,mintime=0,maxtime=0)))

Но некоторые из моих попыток преобразовать это в фрейм данных, кажется, снижают производительность вышеупомянутого в 6 раз:

df <- as.data.frame(scan('myfile',sep='\t',list(url='',popularity=0,mintime=0,maxtime=0))))

Есть ли лучший способ сделать это? Или, может быть, совершенно другой подход к проблеме?

Ответы:


426

Обновление, несколько лет спустя

Этот ответ старый, и R перешел. Тонкая настройка read.tableнемного быстрее приносит мало пользы. Ваши варианты:

  1. Использование vroomиз пакета tidyverse vroomдля импорта данных из файлов с разделителями csv / tab непосредственно в таблицу T.

  2. Использование freadin data.tableдля импорта данных из файлов с разделителями csv / tab непосредственно в R. См . Ответ mnel .

  3. Использование read_tableв readr(на CRAN с апреля 2015 года). Это работает так же, как и freadвыше. Ридй в ссылке объясняет разницу между этими двумя функциями ( в readrнастоящее время утверждает, что «1.5-2x медленнее» , чем data.table::fread).

  4. read.csv.rawfrom iotoolsпредоставляет третий вариант для быстрого чтения CSV-файлов.

  5. Попытка хранить как можно больше данных в базах данных, а не в простых файлах. (Помимо того, что это лучший постоянный носитель данных, данные передаются в и из R в двоичном формате, что быстрее.) read.csv.sqlВ sqldfпакете, как описано в ответе Дж. Д. Лонга , импортируются данные во временную базу данных SQLite, а затем считывается их в R. Смотрите также: RODBCпакет, и обратная часть зависит от страницы DBIпакета . MonetDB.Rдает вам тип данных, который выглядит как фрейм данных, но на самом деле представляет собой MonetDB, что повышает производительность. Импортируйте данные со своей monetdb.read.csvфункцией. dplyrпозволяет работать непосредственно с данными, хранящимися в нескольких типах баз данных.

  6. Хранение данных в двоичных форматах также может быть полезно для повышения производительности. Используйте saveRDS/ readRDS(см. Ниже), h5или rhdf5пакеты для формата HDF5, или write_fst/ read_fstиз fstпакета.


Оригинальный ответ

Есть несколько простых вещей, которые вы можете попробовать, используете ли вы read.table или scan.

  1. Set nrows= количество записей в ваших данных ( nmaxв scan).

  2. Обязательно comment.char=""отключите интерпретацию комментариев.

  3. Явно определите классы каждого столбца, используя colClassesin read.table.

  4. Настройка multi.line=FALSEтакже может улучшить производительность при сканировании.

Если ничего из этого не работает, используйте один из пакетов профилирования, чтобы определить, какие строки замедляют работу. Возможно, вы можете написать сокращенную версию на read.tableоснове результатов.

Другой альтернативой является фильтрация ваших данных, прежде чем читать их в R.

Или, если проблема заключается в том, что вы должны регулярно читать его, затем используйте эти методы для чтения данных за один раз, а затем сохраните кадр данных в виде двоичного двоичного объекта с save saveRDSзатем в следующий раз вы сможете получить его быстрее с load readRDS,


4
Спасибо за советы Ричи. Я провел небольшое тестирование, и кажется, что прирост производительности при использовании параметров nrow и colClasses для read.table довольно скромный. Например, чтение таблицы строк ~ 7M занимает 78 секунд без параметров и 67 секунд с параметрами. (примечание: таблица имеет 1 символьный столбец, 4 целочисленных столбца, и я читаю, используя comment.char = '' и stringsAsFactors = FALSE). Использование save () и load (), когда это возможно, отличный совет - после сохранения с помощью save () эта же таблица загружается всего за 12 секунд.
айтан

2
Пакет «пера» имеет новый двоичный формат, который хорошо
сочетается с

4
Я думаю, может быть, вам нужно обновить свой пост снова в отношении пакета feather. Для чтения данных featherгораздо быстрее, чем fread. Например, в только что загруженном наборе данных объемом 4 ГБ read_featherскорость была примерно в 4,5 раза выше fread. Для сохранения данных fwriteвсе еще быстрее. blog.dominodatalab.com/the-r-data-io-shootout
Z-бозон

2
Но размеры файлов для пера намного больше, чем с RDS. Я не думаю, что это поддерживает сжатие. Файл RDS составляет 216 МБ, а файл пера - 4 ГБ. Так featherбыстрее для чтения, но он использует гораздо больше места для хранения.
Z бозон

@Zboson Если вам нужно хранить фрейм данных в файле, к которому можно получить доступ как из R, так и из Python, то featherэто хороший вариант. Если вас интересует только возможность прочитать ваши данные в R, rdsпредпочтительнее.
Ричи Коттон

279

Вот пример, который использует freadот data.table1.8.7

Примеры приведены на странице справки fread, где приведены временные параметры на моем Windows XP Core 2 Duo E8400.

library(data.table)
# Demo speedup
n=1e6
DT = data.table( a=sample(1:1000,n,replace=TRUE),
                 b=sample(1:1000,n,replace=TRUE),
                 c=rnorm(n),
                 d=sample(c("foo","bar","baz","qux","quux"),n,replace=TRUE),
                 e=rnorm(n),
                 f=sample(1:1000,n,replace=TRUE) )
DT[2,b:=NA_integer_]
DT[4,c:=NA_real_]
DT[3,d:=NA_character_]
DT[5,d:=""]
DT[2,e:=+Inf]
DT[3,e:=-Inf]

стандартный read.table

write.table(DT,"test.csv",sep=",",row.names=FALSE,quote=FALSE)
cat("File size (MB):",round(file.info("test.csv")$size/1024^2),"\n")    
## File size (MB): 51 

system.time(DF1 <- read.csv("test.csv",stringsAsFactors=FALSE))        
##    user  system elapsed 
##   24.71    0.15   25.42
# second run will be faster
system.time(DF1 <- read.csv("test.csv",stringsAsFactors=FALSE))        
##    user  system elapsed 
##   17.85    0.07   17.98

оптимизированный read.table

system.time(DF2 <- read.table("test.csv",header=TRUE,sep=",",quote="",  
                          stringsAsFactors=FALSE,comment.char="",nrows=n,                   
                          colClasses=c("integer","integer","numeric",                        
                                       "character","numeric","integer")))


##    user  system elapsed 
##   10.20    0.03   10.32

Fread

require(data.table)
system.time(DT <- fread("test.csv"))                                  
 ##    user  system elapsed 
##    3.12    0.01    3.22

sqldf

require(sqldf)

system.time(SQLDF <- read.csv.sql("test.csv",dbname=NULL))             

##    user  system elapsed 
##   12.49    0.09   12.69

# sqldf as on SO

f <- file("test.csv")
system.time(SQLf <- sqldf("select * from f", dbname = tempfile(), file.format = list(header = T, row.names = F)))

##    user  system elapsed 
##   10.21    0.47   10.73

фф / ффдф

 require(ff)

 system.time(FFDF <- read.csv.ffdf(file="test.csv",nrows=n))   
 ##    user  system elapsed 
 ##   10.85    0.10   10.99

В итоге:

##    user  system elapsed  Method
##   24.71    0.15   25.42  read.csv (first time)
##   17.85    0.07   17.98  read.csv (second time)
##   10.20    0.03   10.32  Optimized read.table
##    3.12    0.01    3.22  fread
##   12.49    0.09   12.69  sqldf
##   10.21    0.47   10.73  sqldf on SO
##   10.85    0.10   10.99  ffdf

43
Отличный ответ, и сравнительный анализ имеет место в других контекстах. Просто прочитайте в файле 4 Гб в течение минуты с fread. Попытался прочитать его с помощью базовых функций R, и это заняло около 15 часов.
Ари Б. Фридман,

1
Мой тест показывает еще большие преимущества для read.csv в data.table. обратите внимание, что data.table не является стандартным R, но (к сожалению) «просто» приятно делится его создателями в CRAN. он даже не считается достаточно стандартным для составления общего списка пакетов R, и гораздо менее квалифицируется как замена для фреймов данных. у этого есть много преимуществ, но также и некоторые очень противоречивые аспекты. Вы можете использовать as.data.frame (fread.csv ("test.csv")) с пакетом, чтобы вернуться в стандартный мир фреймов данных R.
Иво Уэлч

3
@mnel Не могли бы вы еще раз запустить тест и включить readr?
Джангорецки

2
Второй @jangorecki. Кроме того, учитывая, что сейчас freadесть некоторые реальные конкуренты, может быть полезно добавить тесты для оптимизированного freadиспользования - указание colClassesи т. Д.
MichaelChirico

1
@jangorecji @ MichaelChirico приведенный код полностью воспроизводим, поэтому просто смоделировать readr ... повторный запуск кода, на моей машине истекшее время вдвое, если не больше, для большинства результатов, хотя я запускаю его по сети (и хорошо обновленные версии, как это уже давно) ... и с readr я нахожусь на 7 с, но и на секунду, когда я запускаю второй раз (0,66 с), я подозреваю, что в сети есть какое-то кеширование или некоторое узкое место. fread для самого быстрого решения, показанного здесь, находится на 2 с для моей стороны для сравнения (впервые работает на 8,69 с) по какой-то причине медленнее)
R. Prost

249

Сначала я не видел этот вопрос и через несколько дней задал похожий вопрос. Я собираюсь снять свой предыдущий вопрос, но я решил добавить сюда ответ, чтобы объяснить, как я sqldf()это делал.

Там было немного дискуссий о том, как лучше всего импортировать 2 ГБ или более текстовых данных во фрейм данных R. Вчера я написал сообщение в блоге о том, sqldf()как импортировать данные в SQLite в качестве промежуточной области, а затем сосать их из SQLite в R. Это очень хорошо работает для меня. Мне удалось получить 2 ГБ (3 столбца, 40 мм строки) данных за <5 минут. В отличие от этого read.csvкоманда выполнялась всю ночь и никогда не выполнялась.

Вот мой тестовый код:

Настройте тестовые данные:

bigdf <- data.frame(dim=sample(letters, replace=T, 4e7), fact1=rnorm(4e7), fact2=rnorm(4e7, 20, 50))
write.csv(bigdf, 'bigdf.csv', quote = F)

Я перезапустил R перед запуском следующей процедуры импорта:

library(sqldf)
f <- file("bigdf.csv")
system.time(bigdf <- sqldf("select * from f", dbname = tempfile(), file.format = list(header = T, row.names = F)))

Я позволил следующей строке работать всю ночь, но она так и не завершилась:

system.time(big.df <- read.csv('bigdf.csv'))

1
Привет. Как вы будете использовать его в качестве входных данных для других пакетов, таких как zoo, предназначенных для одновременного использования со всеми данными?
Скан

@skan конечный объект является фреймом данных. Таким образом, вы должны преобразовать его в объект зоопарка, чтобы использовать его с зоопарком. Посмотрите на примеры в документах зоопарка для иллюстраций.
JD Long

@JD Long. Привет, проблема в том, что когда вы конвертируете его в объект зоопарка, он пытается поместить его в память. Если он слишком велик, выдает ошибку. И если результат объекта zoo (например, агрегация двух рядов) также слишком велик, то он также должен быть объектом sql или ff.
Скан

Я не знаю, что не так с sqldf. Я создал простой 1 ГБ файл на диске (с 2 числовыми столбцами) и использовал DTSQL <- read.csv.sql ("f2.txt", dbname = tempfile ()), и он пытается загрузить все данные в память. Завтра вместо этого попробую ff и revoscaler.
Скан

1
@ Что м тысяча, так мм мм тысяча или миллион. Я, вероятно, должен был использовать его как ММ. Но я считаю, что почти любая миллионная аббревиатура может кого-то сбить с толку, если у вас достаточно разнообразная аудитория. В моей попытке быть слишком многословным, я сожалею, что сделал это более запутанным! accountingcoach.com/blog/what-does-m-and-mm-stand-for
JD Long

73

Как ни странно, никто не отвечал на нижнюю часть вопроса в течение многих лет, даже если это важный вопрос - data.frameэто просто списки с правильными атрибутами, поэтому если у вас есть большие данные, которые вы не хотите использовать as.data.frameили похожие для списка. Гораздо быстрее просто «превратить» список в фрейм данных на месте:

attr(df, "row.names") <- .set_row_names(length(df[[1]]))
class(df) <- "data.frame"

Это не делает копию данных, поэтому это немедленно (в отличие от всех других методов). Предполагается, что вы уже установили names()в списке соответственно.

[Что касается загрузки больших данных в R - лично я дам их по столбцам в двоичные файлы и использую readBin()- это, безусловно, самый быстрый метод (кроме mmapping), который ограничен только скоростью диска. Анализ файлов ASCII по своей сути медленен (даже в C) по сравнению с двоичными данными.]


6
Использование tracmemподсказывает, что attr<-и class<-делать копии внутри. bit::setattrили data.table::setattrне будет.
mnel

6
Может быть, вы использовали неправильный порядок? Там нет копии, если вы используете df=scan(...); names(df)=...; attr...; class...- см. tracemem()(Проверено в R 2.15.2)
Simon Urbanek

3
Можете ли вы рассказать о том, как вы выгружаете большие данные по столбцам в двоичные файлы?
Дабсинг

32

Раньше об этом спрашивали в R-Help , так что стоит посмотреть.

Одно из предложений заключалось в том, чтобы использовать, readChar()а затем выполнять строковые операции с результатом strsplit()и substr(). Вы можете видеть, что логика readChar намного меньше, чем read.table.

Я не знаю, является ли здесь проблема с памятью, но вы также можете взглянуть на пакет HadoopStreaming . При этом используется Hadoop , который представляет собой инфраструктуру MapReduce, предназначенную для работы с большими наборами данных. Для этого вы бы использовали функцию hsTableReader. Это пример (но у него есть кривая обучения для изучения Hadoop):

str <- "key1\t3.9\nkey1\t8.9\nkey1\t1.2\nkey1\t3.9\nkey1\t8.9\nkey1\t1.2\nkey2\t9.9\nkey2\"
cat(str)
cols = list(key='',val=0)
con <- textConnection(str, open = "r")
hsTableReader(con,cols,chunkSize=6,FUN=print,ignoreKey=TRUE)
close(con)

Основная идея здесь - разбить импорт данных на куски. Вы могли бы даже пойти так далеко, чтобы использовать одну из параллельных сред (например, Snow) и запустить импорт данных параллельно, сегментируя файл, но, скорее всего, для больших наборов данных, которые не помогут, поскольку вы столкнетесь с ограничениями памяти, именно поэтому карта-сокращение является лучшим подходом.


Я только что сделал быстрый тест, и readChar, кажется, намного быстрее, чем даже readLines по какой-то необъяснимой причине. Тем не менее, он все еще медленный как грех по сравнению с простым тестом C. При простой задаче чтения 100 мегабайт R примерно в 5-10 раз медленнее, чем C
Джонатан Чанг

1
Не понимаю твою точку зрения. Задача Hadoop - обрабатывать очень большие данные, о чем и был вопрос.
Шейн

1
Несмотря на название, hsTableReader не имеет ничего общего с Hadoop как таковым, он предназначен для обработки больших данных по частям. Он читает из con, порцию строк одновременно, и передает каждую порцию как data.frame в FUN для обработки. С ignoreKey = FALSE он выполняет некоторую дополнительную группировку по ключу (запись в первом столбце), что относится к подходам Map / Reduce.
DavidR

Привет. Как бы вы использовали эти данные Hadoop в качестве входных данных для других пакетов, таких как zoo, предназначенных для одновременного использования со всеми данными?
Скан

10

Альтернативой является использование vroomпакета. Теперь на CRAN. vroomне загружает весь файл, он индексирует, где находится каждая запись, и читается позже, когда вы его используете.

Платите только за то, что вы используете.

См. Введение в vroom , Начало работы с vroom и тесты vroom .

Основной обзор заключается в том, что первоначальное чтение огромного файла будет намного быстрее, а последующие изменения данных могут быть немного медленнее. Таким образом, в зависимости от того, что вы используете, это может быть лучшим вариантом.

Посмотрите упрощенный пример из тестов vroom ниже, ключевые моменты, которые нужно увидеть, - это супер быстрое время чтения, но немного ускоряющие операции, такие как агрегирование и т. Д.

package                 read    print   sample   filter  aggregate   total
read.delim              1m      21.5s   1ms      315ms   764ms       1m 22.6s
readr                   33.1s   90ms    2ms      202ms   825ms       34.2s
data.table              15.7s   13ms    1ms      129ms   394ms       16.3s
vroom (altrep) dplyr    1.7s    89ms    1.7s     1.3s    1.9s        6.7s

5

Незначительные дополнительные моменты стоит упомянуть. Если у вас очень большой файл, вы можете на лету рассчитать количество строк (если нет заголовка), используя (гдеbedGraph имя вашего файла в вашем рабочем каталоге):

>numRow=as.integer(system(paste("wc -l", bedGraph, "| sed 's/[^0-9.]*\\([0-9.]*\\).*/\\1/'"), intern=T))

Затем вы можете использовать что либо read.csv, read.table...

>system.time((BG=read.table(bedGraph, nrows=numRow, col.names=c('chr', 'start', 'end', 'score'),colClasses=c('character', rep('integer',3)))))
   user  system elapsed 
 25.877   0.887  26.752 
>object.size(BG)
203949432 bytes

4

Часто я думаю, что это хорошая практика - хранить большие базы данных внутри базы данных (например, Postgres). Я не использую ничего слишком большого, чем (nrow * ncol) ncell = 10M, что довольно мало; но я часто нахожу, что хочу, чтобы R создавал и содержал графики, интенсивно использующие память, только когда я выполняю запросы из нескольких баз данных. В будущем 32-ГБ ноутбуки некоторые из этих типов проблем с памятью исчезнут. Но привлекательность использования базы данных для хранения данных и последующего использования памяти R для получения результатов запроса и графиков все еще может быть полезной. Некоторые преимущества:

(1) Данные остаются загруженными в вашу базу данных. Вы просто переподключаетесь в pgadmin к нужным базам данных, когда снова включаете свой ноутбук.

(2) Это правда, что R может выполнять намного больше изящных статистических и графических операций, чем SQL. Но я думаю, что SQL лучше подходит для запросов больших объемов данных, чем R.

# Looking at Voter/Registrant Age by Decade

library(RPostgreSQL);library(lattice)

con <- dbConnect(PostgreSQL(), user= "postgres", password="password",
                 port="2345", host="localhost", dbname="WC2014_08_01_2014")

Decade_BD_1980_42 <- dbGetQuery(con,"Select PrecinctID,Count(PrecinctID),extract(DECADE from Birthdate) from voterdb where extract(DECADE from Birthdate)::numeric > 198 and PrecinctID in (Select * from LD42) Group By PrecinctID,date_part Order by Count DESC;")

Decade_RD_1980_42 <- dbGetQuery(con,"Select PrecinctID,Count(PrecinctID),extract(DECADE from RegistrationDate) from voterdb where extract(DECADE from RegistrationDate)::numeric > 198 and PrecinctID in (Select * from LD42) Group By PrecinctID,date_part Order by Count DESC;")

with(Decade_BD_1980_42,(barchart(~count | as.factor(precinctid))));
mtext("42LD Birthdays later than 1980 by Precinct",side=1,line=0)

with(Decade_RD_1980_42,(barchart(~count | as.factor(precinctid))));
mtext("42LD Registration Dates later than 1980 by Precinct",side=1,line=0)

3

Я очень быстро читаю данные, используя новый arrowпакет. Похоже, на довольно ранней стадии.

В частности, я использую паркетный столбчатый формат. Это преобразует обратно в a data.frameв R, но вы можете получить еще более быстрое ускорение, если вы этого не сделаете. Этот формат удобен тем, что его можно использовать и в Python.

Мой основной сценарий использования этого - довольно ограниченный сервер RShiny. По этим причинам я предпочитаю хранить данные, прикрепленные к приложениям (то есть вне SQL), и поэтому требую небольшой размер файла и скорость.

Эта связанная статья обеспечивает сравнительный анализ и хороший обзор. Я привел некоторые интересные моменты ниже.

https://ursalabs.org/blog/2019-10-columnar-perf/

Размер файла

То есть файл Parquet вдвое меньше, чем даже сжатый CSV. Одна из причин, по которой файл Parquet такой маленький, заключается в кодировке словаря (также называемой «сжатие словаря»). Сжатие по словарю может дать значительно лучшее сжатие, чем использование байтового компрессора общего назначения, такого как LZ4 или ZSTD (которые используются в формате FST). Паркет был разработан для производства очень маленьких файлов, которые быстро читаются.

Скорость чтения

При управлении по типу выходных данных (например, сравнивая все выходные данные R data.frame друг с другом), мы видим, что производительность Parquet, Feather и FST находится в относительно небольшом поле друг от друга. То же самое относится и к выводам pandas.DataFrame. data.table :: fread впечатляюще конкурирует с размером файла 1,5 ГБ, но уступает другим по 2,5 ГБ CSV.


Независимый тест

Я выполнил некоторые независимые тесты для имитированного набора данных из 1 000 000 строк. По сути, я перетасовал кучу вещей, пытаясь бросить вызов сжатию. Также я добавил короткое текстовое поле случайных слов и два имитируемых фактора.

Данные

library(dplyr)
library(tibble)
library(OpenRepGrid)

n <- 1000000

set.seed(1234)
some_levels1 <- sapply(1:10, function(x) paste(LETTERS[sample(1:26, size = sample(3:8, 1), replace = TRUE)], collapse = ""))
some_levels2 <- sapply(1:65, function(x) paste(LETTERS[sample(1:26, size = sample(5:16, 1), replace = TRUE)], collapse = ""))


test_data <- mtcars %>%
  rownames_to_column() %>%
  sample_n(n, replace = TRUE) %>%
  mutate_all(~ sample(., length(.))) %>%
  mutate(factor1 = sample(some_levels1, n, replace = TRUE),
         factor2 = sample(some_levels2, n, replace = TRUE),
         text = randomSentences(n, sample(3:8, n, replace = TRUE))
         )

Прочти и напиши

Написание данных легко.

library(arrow)

write_parquet(test_data , "test_data.parquet")

# you can also mess with the compression
write_parquet(test_data, "test_data2.parquet", compress = "gzip", compression_level = 9)

Чтение данных также легко.

read_parquet("test_data.parquet")

# this option will result in lightning fast reads, but in a different format.
read_parquet("test_data2.parquet", as_data_frame = FALSE)

Я проверил чтение этих данных по нескольким конкурирующим вариантам и получил немного другие результаты, чем в статье выше, что ожидается.

бенчмаркинг

Этот файл далеко не такой большой, как эталонная статья, так что, возможно, в этом и заключается разница.

тесты

  • выстр:rds test_data.rds (20,3 МБ)
  • parquet2_native: (14,9 МБ с более высоким сжатием иas_data_frame = FALSE )
  • parquet2: test_data2.parquet (14,9 МБ с более высоким сжатием)
  • паркет: test_data.parquet (40,7 МБ)
  • fst2: test_data2.fst (27,9 МБ с более высокой степенью сжатия)
  • FST:fst test_data.fst (76,8 МБ)
  • fread2: test_data.csv.gz (23,6 МБ)
  • Fread: test_data.csv (98,7 МБ)
  • feather_arrow: test_data.feather (157,2 МБ прочитано сarrow )
  • feather: test_data.feather (157,2 МБ прочитано с feather)

наблюдения

Для этого конкретного файла, freadна самом деле очень быстро. Мне нравится маленький размер файла из сильно сжатого parquet2теста. Я могу потратить время на работу с собственным форматом данных, а неdata.frame если мне действительно нужно ускорить работу.

Здесь fstтакже отличный выбор. Я бы использовал либо сильно сжатый fstформат, либо сильно сжатый, в parquetзависимости от того, нужна ли мне компромисс между скоростью или размером файла.


0

Вместо обычного read.table я чувствую, что fread - более быстрая функция. Задание дополнительных атрибутов, таких как выбор только необходимых столбцов, указание классов и строк в качестве факторов, уменьшит время, необходимое для импорта файла.

data_frame <- fread("filename.csv",sep=",",header=FALSE,stringsAsFactors=FALSE,select=c(1,4,5,6,7),colClasses=c("as.numeric","as.character","as.numeric","as.Date","as.Factor"))

0

Я перепробовал все выше и [readr] [1] сделал лучшую работу. У меня только 8гб оперативки

Цикл для 20 файлов, 5 ГБ каждый, 7 столбцов:

read_fwf(arquivos[i],col_types = "ccccccc",fwf_cols(cnpj = c(4,17), nome = c(19,168), cpf = c(169,183), fantasia = c(169,223), sit.cadastral = c(224,225), dt.sitcadastral = c(226,233), cnae = c(376,382)))
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.