[r] 대용량 (3.5GB) csv 파일을 트리밍하여 R로 읽어 오기

그래서 많은 세부 사항과 불완전한 행이있는 데이터 파일 (세미콜론으로 구분됨)이 있습니다 (Access 및 SQL이 질식하게 함). 40 년 동안 세그먼트, 하위 세그먼트 및 하위 하위 세그먼트 (총 ~ 200 개 요소)로 분류 된 카운티 수준 데이터 세트입니다. 요컨대, 그것은 거대하고 단순히 읽으려고하면 기억에 맞지 않을 것입니다.

그래서 내 질문은 이것이 내가 모든 카운티를 원하지만 단 1 년 (그리고 단지 최고 수준의 세그먼트 … 결국 약 100,000 개의 행으로 이어지는)을 고려할 때 가장 좋은 방법은 무엇일까요? 이 롤업은 R?

현재 저는 한 번에 한 줄씩 읽고 작업하여 파일 크기 제한을 극복하면서 Python으로 관련없는 해를 자르려고 노력하고 있지만 R 전용 솔루션 (CRAN 패키지 괜찮음)을 선호합니다. R에서 한 번에 한 조각 씩 파일을 읽는 비슷한 방법이 있습니까?

어떤 아이디어라도 대단히 감사하겠습니다.

최신 정보:

  • 제약
    • 머신 을 사용해야 하므로 EC2 인스턴스 없음
    • 가능한 한 R 전용입니다. 이 경우 속도와 자원은 문제가되지 않습니다 … 내 기계가 폭발하지 않는다면 …
    • 아래에서 볼 수 있듯이 데이터에는 나중에 작업해야하는 혼합 유형이 포함되어 있습니다.
  • 데이터
    • 데이터는 3.5GB이며 약 850 만 개의 행과 17 개의 열이 있습니다.
    • 2 천 개의 행 (~ 2k)이 형식이 잘못되어 17 개 대신 하나의 열만 있습니다.
      • 이는 전혀 중요하지 않으며 삭제할 수 있습니다.
    • 이 파일에서 ~ 100,000 행만 필요합니다 (아래 참조).

데이터 예 :

County; State; Year; Quarter; Segment; Sub-Segment; Sub-Sub-Segment; GDP; ...
Ada County;NC;2009;4;FIRE;Financial;Banks;80.1; ...
Ada County;NC;2010;1;FIRE;Financial;Banks;82.5; ...
NC  [Malformed row]
[8.5 Mill rows]

데이터를 R에 맞출 수 있도록 몇 개의 열을 잘라내어 사용 가능한 40 년 중 2 년 (2009-2010 년 1980-2020)을 선택하려고합니다.

County; State; Year; Quarter; Segment; GDP; ...
Ada County;NC;2009;4;FIRE;80.1; ...
Ada County;NC;2010;1;FIRE;82.5; ...
[~200,000 rows]

결과 :

모든 제안을 수정 한 후 JD와 Marek이 제안한 readLines가 가장 잘 작동하기로 결정했습니다. Marek이 샘플 구현을 제공했기 때문에 수표를주었습니다.

나는 strsplit과 cat을 사용하여 내가 원하는 열만 유지하면서 최종 답변을 위해 Marek의 구현을 약간 수정 한 버전을 재현했습니다.

또한 이것은 Python보다 훨씬 덜 효율적이라는 점에 유의해야합니다 . Python은 3.5GB 파일을 5 분 안에 처리하는 반면 R은 약 60 시간이 걸립니다 …하지만 R 만 있으면 이것이 티켓입니다.

## Open a connection separately to hold the cursor position
file.in <- file('bad_data.txt', 'rt')
file.out <- file('chopped_data.txt', 'wt')
line <- readLines(file.in, n=1)
line.split <- strsplit(line, ';')
# Stitching together only the columns we want
cat(line.split[[1]][1:5], line.split[[1]][8], sep = ';', file = file.out, fill = TRUE)
## Use a loop to read in the rest of the lines
line <- readLines(file.in, n=1)
while (length(line)) {
  line.split <- strsplit(line, ';')
  if (length(line.split[[1]]) > 1) {
    if (line.split[[1]][3] == '2009') {
        cat(line.split[[1]][1:5], line.split[[1]][8], sep = ';', file = file.out, fill = TRUE)
    }
  }
  line<- readLines(file.in, n=1)
}
close(file.in)
close(file.out)

접근 방식 별 실패 :

  • sqldf
    • 이것은 데이터가 잘 구성된 경우 향후 이러한 유형의 문제에 확실히 사용할 것입니다. 그러나 그렇지 않은 경우 SQLite가 질식합니다.
  • MapReduce
    • 솔직히 말해서, 문서는 이것에 대해 저를 약간 협박했기 때문에 나는 그것을 시도하지 않았습니다. 객체가 메모리에 있어야하는 것처럼 보 였는데, 그럴 경우 포인트를 무너 뜨릴 것입니다.
  • bigmemory
    • 이 접근 방식은 데이터에 명확하게 연결되어 있지만 한 번에 하나의 유형 만 처리 할 수 ​​있습니다. 결과적으로 내 모든 문자 벡터가 큰 테이블에 놓일 때 떨어졌습니다. 하지만 미래를 위해 대용량 데이터 세트를 설계해야하는 경우이 옵션을 유지하기 위해 숫자 만 사용하는 것을 고려합니다.
  • 주사
    • 스캔은 대용량 메모리와 유사한 유형 문제가있는 것처럼 보이지만 readLines의 모든 메커니즘이 있습니다. 간단히 말해 이번에는 청구서에 맞지 않았습니다.



답변

내 시도 readLines. 이 코드 조각은 csv선택한 연도로 생성 됩니다.

file_in <- file("in.csv","r")
file_out <- file("out.csv","a")
x <- readLines(file_in, n=1)
writeLines(x, file_out) # copy headers

B <- 300000 # depends how large is one pack
while(length(x)) {
    ind <- grep("^[^;]*;[^;]*; 20(09|10)", x)
    if (length(ind)) writeLines(x[ind], file_out)
    x <- readLines(file_in, n=B)
}
close(file_in)
close(file_out)


답변

저는 이것에 대한 전문가는 아니지만 MapReduce 를 사용해 볼 수도 있습니다 . 이것은 기본적으로 “분할 및 정복”접근 방식을 취하는 것을 의미합니다. R에는 다음과 같은 몇 가지 옵션이 있습니다.

  1. mapReduce (순수 R)
  2. RHIPE ( Hadoop 사용 ) 파일 서브 세트의 예 는 문서의 예 6.2.2 참조하십시오.

또는 R은 메모리 외부 (디스크로)로 이동하는 대용량 데이터를 처리하기위한 여러 패키지를 제공합니다. 전체 데이터 세트를 bigmemory객체에 로드하고 R 내에서 완전히 축소 할 수 있습니다.이를 처리하는 도구 세트는 http://www.bigmemory.org/ 를 참조 하십시오 .


답변

R에서 한 번에 한 조각 씩 파일을 읽는 비슷한 방법이 있습니까?

예. readChar () 기능은 널 종료되었다고 가정없이 문자 블록에 판독한다. 한 번에 한 줄의 데이터를 읽으려면 readLines ()를 사용할 수 있습니다 . 블록이나 라인을 읽고 작업을 한 다음 데이터를 쓰면 메모리 문제를 피할 수 있습니다. Amazon의 EC2에서 대용량 메모리 인스턴스를 실행하려는 경우 최대 64GB의 RAM을 얻을 수 있습니다. 이는 파일과 데이터를 조작 할 수있는 충분한 공간을 확보해야합니다.

더 빠른 속도가 필요하다면 Shane의 Map Reduce를 사용하는 것이 매우 좋습니다. 그러나 EC2에서 대용량 메모리 인스턴스를 사용하는 경로로 이동하는 경우 머신의 모든 코어를 사용하기위한 멀티 코어 패키지를 살펴 봐야합니다.

구분 된 많은 데이터를 R로 읽고 싶다면 적어도 R에서 sqldf로 직접 가져온 다음 R 내에서 데이터를 조작 할 수있는 sqldf 패키지를 조사해야합니다. sqldf가 하나라는 것을 알았습니다. 이전 질문 에서 언급했듯이 몇 기가 바이트의 데이터를 R로 가져 오는 가장 빠른 방법 입니다.


답변

거대한 텍스트 파일에서 원하는 변수 만 읽을 수있는 colbycol이라는 새로운 패키지가 있습니다.

http://colbycol.r-forge.r-project.org/

read.table에 모든 인수를 전달하므로 조합을 사용하면 하위 집합을 매우 밀접하게 사용할 수 있습니다.


답변

ff패키지는 대용량 파일을 처리 할 수있는 투명한 방법입니다.

패키지 웹 사이트 및 / 또는 이에 대한 프레젠테이션을 볼 수 있습니다 .

이게 도움이 되길 바란다


답변

당신은 할 수 SQLite는 데이터베이스에 데이터를 가져 오기 한 후 사용 RSQLite을 하위 집합을 선택할 수 있습니다.


답변

사용 readrread_*_chunked가족은 어떻습니까?

따라서 귀하의 경우 :

testfile.csv

County; State; Year; Quarter; Segment; Sub-Segment; Sub-Sub-Segment; GDP
Ada County;NC;2009;4;FIRE;Financial;Banks;80.1
Ada County;NC;2010;1;FIRE;Financial;Banks;82.5
lol
Ada County;NC;2013;1;FIRE;Financial;Banks;82.5

실제 코드

require(readr)
f <- function(x, pos) subset(x, Year %in% c(2009, 2010))
read_csv2_chunked("testfile.csv", DataFrameCallback$new(f), chunk_size = 1)

이것은 적용됩니다 f 각 청크에 되며 열 이름을 기억하고 마지막에 필터링 된 결과를 결합합니다. 참고 ?callback이 예제의 소스이다.

결과는 다음과 같습니다.

# A tibble: 2 × 8
      County State  Year Quarter Segment `Sub-Segment` `Sub-Sub-Segment`   GDP
*      <chr> <chr> <int>   <int>   <chr>         <chr>             <chr> <dbl>
1 Ada County    NC  2009       4    FIRE     Financial             Banks   801
2 Ada County    NC  2010       1    FIRE     Financial             Banks   825

늘릴 수도 chunk_size있지만이 예에서는 4 줄만 있습니다.