2012-03-23 4 views
8

필자는 15 백만 개의 CSV 파일을 보유하고 있으며 각 파일에는 두 개의 열 (정수 및 부동 소수점)과 5 - 500 개의 행이 있습니다. 나는 모든 파일을 반복하고, 큰 목록에 각 파일을 가져 read.csv()를 사용하고, 현재R에서 수백만 개의 파일을 가져 오는 가장 빠른 방법은 무엇입니까?

3453,0.034 
31,0.031 
567,0.456 
... 

: 각 파일은 같이 보입니다. 여기에 단순화 된 버전입니다 :

allFileNames = Sys.glob(sprintf("%s/*/*/results/*/*", dir)) 

s$scores = list() 

for (i in 1:length(allFileNames)){ 
     if ((i %% 1000) == 0){ 
      cat(sprintf("%d of %d\n", i, length(allFileNames))) 
     } 

     fileName = allFileNames[i] 
     approachID = getApproachID(fileName) 
     bugID = getBugID(fileName) 

     size = file.info(fileName)$size 
     if (!is.na(size) && size > 0){ # make sure file exists and is not empty 
      tmp = read.csv(fileName, header=F, colClasses=c("integer", "numeric")) 
      colnames(tmp) = c("fileCode", "score") 
      s$scores[[approachID]][[bugID]] = tmp 
     } else { 
      # File does not exist, or is empty. 
      s$scores[[approachID]][[bugID]] = matrix(-1, ncol=2, nrow=1) 
     } 
    } 

tmp = read.csv(fileName, header=F, colClasses=c("integer", "numeric") 

나중에 내 코드에서, 나는 목록의 각 매트릭스를 통해 돌아가서, 일부 통계를 계산합니다.

이 가져 오기 프로세스를 시작한 후 완료하는 데 3-5 일이 걸리는 것처럼 보입니다. 이 작업을 수행하는 더 빠른 방법이 있습니까?

수정 : 내 코드에 대한 자세한 내용을 추가했습니다.

+1

[신속 R dataframes에서 매우 큰 테이블을 판독]의 중복 가능성 (http://stackoverflow.com/questions/1727772/quickly-reading-very-large-tables-as-dataframes-in-r) – joran

+1

무엇을하려고합니까? 모든 데이터가 포함 된 단일 행렬을 작성하거나 각 행렬을 별도로 읽고 처리합니다. –

+0

많은 파일을 한꺼번에로드하는 것과 관련이 있습니다. http://stackoverflow.com/questions/3764292/ – Ben

답변

6

:

scan(fileName, what=list(0L,0.0), sep=",", dec=".", quiet=TRUE) 

주요 차이점은 두 개의 요소와 read.csv 반환 data.framescan 반환 목록이.

+0

'List [[1]] <- 행렬 (scan (fileName, what = 0, sep = ","), ncol = 2, byrow = TRUE)'같은 것을 생각했다. –

+1

감사합니다. 다른 주석에서 언급했듯이 "tmp <- matrix (scan (fileName, what = 0, sep =", "quiet = T), ncol = 2, byrow = TRUE)''로 전환하면 내 코드는 다음과 같습니다. 약 2 배 빠르게 달리고 있습니다. ''system.time()''을 수행 한 후에는 필요한 시간의 대부분이 IO로 표시되는 것처럼 보입니다. 그래서 조금 기다려야 할 것입니다. – stepthom

7

나는 당신의 목표에 분명 아니지만, 당신은 하나의 R 데이터 구조로 이러한 모든 파일을 읽으려고하는 경우에, 나는 두 가지 주요 성능 문제를 참조하십시오

  1. 파일 액세스 시간을 - read.csv를 요청한 순간부터 복잡한 프로세스가 컴퓨터에서 시작됩니다. 파일이 있는지, 메모리 또는 디스크에있는 파일의 위치를 ​​찾은 다음 (필요할 경우 메모리에 데이터를 읽음) R 내에서 데이터 해석하기. 수백만 개의 파일을 읽을 때 거의 일정한 속도 저하가 일어날 것으로 예상됩니다.
  2. 새로운 파일을 읽을 때마다 단일 데이터 구조가 확장됩니다. 행렬에 행을 몇 개 추가하려고 할 때마다 더 큰 행렬을 저장하기 위해 비슷한 크기의 메모리 덩어리를 다시 할당해야 할 수 있습니다. 배열을 1,500 만 번 늘리면 성능이 느려집니다. 이 문제로 더 많은 파일을 읽으면 성능이 점차 악화됩니다.

빠른 프로파일 링을 수행하고 읽는 시간을 확인하십시오. 더 많은 파일을 읽을 때 점진적으로 느려지면 문제 # 2에 집중합시다. 끊임없이 느린 것이라면 문제 # 1에 대해 걱정 해 봅시다.

에 관한 솔루션, 난 당신이 두 가지로 시작할 수 말할 것 :

  1. 다른 프로그래밍 언어에서 CSV 파일을 결합합니다. 간단한 셸 스크립트는 파일을 반복하면서 하나의 큰 파일로 연결하는 경우 작업을 수행 할 가능성이 높습니다. Joshua와 Richie가 아래에서 언급했듯이보다 효율적인 scan() 또는 readlines() 함수를 사용하여 다른 언어로 변경하지 않고도이를 최적화 할 수 있습니다.
  2. 미리 크기가 조정 된 데이터 구조. 예를 들어, 행렬을 사용하는 경우 행 수를 1,500 만 x 100으로 설정하십시오. 그러면이 객체에 대한 메모리 공간을 한 번만 확인해야하며 나머지 작업은 데이터를 삽입합니다 사전 크기의 매트릭스에 넣습니다.

코드의 세부 정보 (목록의 용도는 무엇입니까?)를 추가하면 더 도움이 될 수 있습니다.

+3

또한 데이터가 모두 숫자로 저장 될 수 있기 때문에'scan'은'read.csv'보다 더 적절합니다. –

+0

OP가 단지 하나의 파일로 결합하기를 원한다면'readLines' +'writeLines'도 가능합니다. –

+0

@ 제프 -이 답변을 주셔서 감사합니다. 이후의 분석을 위해 분리해야하기 때문에 모든 파일을 하나의 큰 파일로 결합 할 수 있다고는 생각하지 않습니다. (각 파일은 내 실험의 실행을 나타냅니다.) 내 데이터 구조를 미리 할당하는 방법으로 내 목록의 크기를 미리 할당하는 방법이 있습니까 (''$ scores'')? BTW- 나는 속도가 점점 악화되는 것을 보지 못하기 때문에 성능이 디스크 IO에 의해 좌우된다고 생각합니다. – stepthom

0

제프가 언급했듯이 오랜 시간이 걸릴 수있는 몇 가지 사항이 있습니다. 문제는 파일 액세스, 파일 읽기 또는 RAM에 1,500 만 개의 데이터 프레임이있을 때 메모리 부족 문제 일 수 있습니다.문제를 복합화하려면 시스템의 사양에 따라 병목 현상이 달라질 수 있습니다 (예 : 느린 하드 드라이브는 파일 읽기 속도를 늦추고 파일 수가 많으면 RAM 부족이 문제가됩니다). 문제를 파악하려면 프로파일 링을해야합니다.

처음에는 10000 개 정도의 파일을 읽은 다음 system.time을 호출하거나 더 많은 시간을 들여 rbenchmark을 사용하여 가장 많은 시간이 걸리는 것을 확인하십시오.

그런 다음 joran의 링크

Quickly reading very large tables as dataframes in R

보고 기술의 어떤이 당신을하는 데 도움이되는지 확인합니다. scan (주석 조슈아 상태로) 빨리 될 수있다 (3-4 번)를 사용하여

2

이 일반적인 워크 플로우는 어떻습니까? 하지만 테스트되지 않았습니다.

my.list.of.files <- list.files(pattern = ".txt") # char vector of filenames 
my.data <- sapply(my.list.of.files, FUN = function(x) { 
      # read file using scan, craft the output to two columns 
     }) # result is merged 

#or if you use simplify= FALSE 
my.data <- sapply(my.list.of.files, FUN = function(x) { 
      # read file using scan (or some other method), craft the output to two columns 
     }, simplify = FALSE) #you get a list 
my.data <- do.call("rbind", my.data) 
+0

이 파일은 템플릿에 불과하지만 한 디렉토리에 1500 만 개의 파일이 모두있는 경우 성능 문제가 발생할 수 있습니다. –

+1

'sapply'는 조금 느리다. 왜냐하면 R이 출력을 단순화하는 방법을 알아 내야하기 때문이다. ''apply' 계열 중에서 'lapply'가 가장 빠르기 때문에 여기에 더 적합 할 것입니다. – flodel

+0

@Jeff, 이것은 우리가 설명 할 수있는 것이 아닙니다. @flodel,'simplify = FALSE'라고 지정해도? –

관련 문제