R의 데이터 프레임으로로드 할 매우 큰 테이블 (3 천만 행)이 있습니다. 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))))
더 좋은 방법이 있습니까? 아니면 문제에 대한 완전히 다른 접근법일까요?
답변
몇 년 후 업데이트
이 답변은 오래되었으며 R은 계속 진행했습니다. read.table
조금 더 빨리 달리기 만해도 약간의 이점이 있습니다. 옵션은 다음과 같습니다.
-
csv / tab으로 구분 된 파일에서 R 티 블로 직접 데이터를 가져 오기 위해
vroom
tidyverse 패키지에서 사용vroom
. -
사용
fread
에data.table
직접 R. 페이지로 CSV / 탭으로 구분 된 파일에서 데이터를 가져 오기위한 mnel의 대답 . -
사용
read_table
에readr
(4 월 2015 크랑에). 이것은fread
위와 매우 유사 합니다. 링크 의 readme 는 두 기능의 차이점을 설명합니다 (readr
현재는 “1.5-2 배 느리다”고 주장합니다data.table::fread
). -
read.csv.raw
fromiotools
은 CSV 파일을 빠르게 읽을 수있는 세 번째 옵션을 제공합니다. -
플랫 파일이 아닌 데이터베이스에 최대한 많은 데이터를 저장하려고합니다. (더 나은 영구 저장 매체 일뿐만 아니라 JD Long의 답변에 설명 된대로 패키지
read.csv.sql
에서 데이터가 R에 이진 형식으로 R로 전달되는 속도가 빠릅니다.) 임시 SQLite 데이터베이스로 데이터를 가져온 다음 읽습니다. 참조 : 패키지 및 그 반대는 패키지 페이지의 섹션에 따라 다릅니다 . 는 데이터 프레임 인 것처럼 보이지만 실제로는 MonetDB 인 데이터 유형을 제공하여 성능을 향상시킵니다. 기능이있는 데이터를 가져옵니다 . 여러 유형의 데이터베이스에 저장된 데이터로 직접 작업 할 수 있습니다.sqldf
RODBC
DBI
MonetDB.R
monetdb.read.csv
dplyr
-
이진 형식으로 데이터를 저장하면 성능을 향상시키는 데 유용 할 수 있습니다. 사용
saveRDS
/readRDS
(아래 참조)h5
또는rhdf5
HDF5 형식, 또는에 대한 패키지write_fst
/read_fst
로부터fst
패키지로 제공된다.
원래 답변
read.table을 사용하든 scan을 사용하든 몇 가지 간단한 시도가 있습니다.
-
설정
nrows
= 데이터의 레코드 수 (nmax
inscan
) -
comment.char=""
주석 해석을 해제 해야합니다 . -
colClasses
in을 사용하여 각 열의 클래스를 명시 적으로 정의하십시오read.table
. -
설정하면
multi.line=FALSE
스캔 성능도 향상 될 수 있습니다.
이 중 어느 것도 작동하지 않으면 프로파일 링 패키지 중 하나를 사용하여 속도를 늦추는 라인을 결정하십시오. 아마도 read.table
결과 에 따라 컷 다운 버전을 작성할 수 있습니다 .
다른 대안은 데이터를 R로 읽기 전에 필터링하는 것입니다.
또는 문제가 정기적으로 데이터를 읽어야하는 경우 이러한 방법을 사용하여 데이터를 한 번에 읽은 다음 데이터 프레임을 이진 blob으로 저장하십시오. save
saveRDS
다음에 더 빨리 검색 할 수 있습니다. load
readRDS
.
답변
다음은 1.8.7 fread
부터 활용하는 예입니다.data.table
예제는 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]
표준 판독 테이블
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
최적화 된 읽기 테이블
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
펼치다
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
ff / ffdf
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
답변
처음에는이 질문을 보지 못했고 며칠 후에 비슷한 질문을했습니다. 이전 질문을 중단하려고했지만 여기에 어떻게 사용했는지 설명하기 위해 여기에 답변을 추가 할 것이라고 생각 sqldf()
했습니다.
2GB 이상의 텍스트 데이터를 R 데이터 프레임으로 가져 오는 가장 좋은 방법 에 대해서는 약간의 논의 가있었습니다 . 어제 나는 스테이징 영역으로 SQLite로 데이터를 가져오고 SQLite에서 R로 데이터를 가져 오는 데 사용 하는 블로그 게시물을 작성했습니다 sqldf()
. <5 분 안에 2GB (3 열, 40mm 행)의 데이터를 가져올 수있었습니다. 대조적으로, 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'))
답변
이상하게도 중요한 질문이지만 몇 년 동안 질문의 맨 아래 부분에 아무도 대답하지 못했습니다. data.frame
s 단순히 올바른 속성을 가진 목록이므로 큰 데이터 as.data.frame
가있는 경우 목록에 사용 하거나 유사한 것을 원하지 않습니다 . 목록을 데이터 프레임으로 간단히 “전환”하는 것이 훨씬 빠릅니다.
attr(df, "row.names") <- .set_row_names(length(df[[1]]))
class(df) <- "data.frame"
이것은 데이터의 복사본을 만들지 않으므로 다른 모든 방법과 달리 즉시 있습니다. names()
그에 따라 목록에 이미 설정 되어 있다고 가정합니다 .
[대량의 데이터를 R에 개인적으로로드하는 경우 개인적으로 열별로 이진 파일로 덤프하여 사용합니다 readBin()
. 즉, mmapping 이외의 가장 빠른 방법이며 디스크 속도에 의해서만 제한됩니다. ASCII 파일 구문 분석은 이진 데이터에 비해 본질적으로 느립니다 (C에서도).]
답변
이것은 이전 에 R-Help 에서 요청 되었으므로 검토 할 가치가 있습니다.
한 가지 제안 사용할 수 있었다 readChar()
다음에 결과에 문자열 조작을 strsplit()
하고 substr()
. readChar에 관련된 논리가 read.table보다 훨씬 적다는 것을 알 수 있습니다.
여기서 메모리가 문제인지 는 모르겠지만 HadoopStreaming 패키지를 살펴볼 수도 있습니다 . 여기 에는 대용량 데이터 세트를 처리하기 위해 설계된 MapReduce 프레임 워크 인 Hadoop 이 사용 됩니다. 이를 위해 hsTableReader 함수를 사용합니다. 이것은 예입니다 (그러나 하둡을 배우기위한 학습 곡선이 있습니다).
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)
여기서 기본 아이디어는 데이터 가져 오기를 청크로 분할하는 것입니다. 병렬 프레임 워크 (예 : 스노) 중 하나를 사용하여 파일을 분할하여 병렬로 데이터 가져 오기를 실행할 수도 있지만 메모리 제약 조건이 발생하여 큰 도움이되지 않는 대규모 데이터 세트의 경우, 그렇기 때문에 map-reduce가 더 나은 방법입니다.
답변
대안은 vroom
패키지 를 사용하는 것 입니다. 이제 CRAN에 있습니다.
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
답변
언급 할 가치가있는 약간의 추가 사항. 파일이 매우 큰 경우 다음을 사용하여 행 수 (헤더가없는 경우)를 즉시 계산할 수 있습니다 (여기서 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
