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


87

그래서 많은 세부 사항과 불완전한 행이있는 데이터 파일 (세미콜론으로 구분됨)이 있습니다 (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의 모든 메커니즘이 있습니다. 간단히 말해 이번에는 청구서에 맞지 않았습니다.

3
기준이 충분히 간단하다면 직접 읽을 수있는 CSV의 잘린 버전을 사용 sed하거나 awk만들 수 있습니다. 이것은 답변보다 해결 방법에 가깝기 때문에 주석으로 남겨 두겠습니다.
Hank Gay

나는 행크 동의 - 당신이 작업에 적합한 도구를 사용해야하고 관련이없는 행을 제거하는 간단한 데이터 클리닝 /라면 / 열 라인 스트림 도구 같은 명령 종류 / SED / AWK 큰하고있을거야 방법을 적은 R보다 자원 집약적 또는 파이썬 - 당신이 파일의 샘플을 주면 우리가 아마 예를 들어 줄 수있는 포맷
아론 스테이트 햄

큰. 발견 한 것을 알려주십시오.
Shane

@Hank & Aaron : 저는 일반적으로 작업에 적합한 도구를 사용하고 있지만 이것이 작업중인 Windows 시스템에서 R을 배우고 있다는 점을 감안할 때 모범 사례보다 좋은 연습이 될 것이라고 생각했습니다. 가능하면 R 전용으로 시도하십시오.
FTWynn 2010 년

2
나중에 참조하려면 data.table R 패키지를 확인하세요. 이 fread기능은 read.table. 같은 x = fread(file_path_here, data.table=FALSE)것을 사용 하여 data.frame객체 로로드하십시오 .
paleo13

답변:


39

내 시도 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)

이것은 내가 방금 쓴 내용과 거의 동일합니다. 메모리 제약, 혼합 유형 및 잘못된 행을 고려할 때 이것이 최선의 대답이 될 것이라고 생각합니다.
FTWynn 2010-06-24

10

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

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

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


좋은 제안이지만 MapReduce와 그 ilk에 대한 경험이 많지 않습니다. 나는 그것을 읽어야 할 것이다.
FTWynn

bigmemory이 경우 먼저 시도하는 것이 더 쉬울 수 있습니다.
Shane

10

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

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

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

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


EC2 인스턴스를 염두에두고 있지만 지금은 데스크톱을 고수해야하며 2GB RAM입니다. sqldf는 확실히 내가 생각했던 것처럼 보입니다. 그러나 형식이 잘못된 행에서도 질식합니다 (17 개의 열이 있어야하지만 수천 개의 행에는 하나만 있음). 다른 전처리 방법이 필요합니까? 아니면 제가 놓친 옵션이 있습니까?
FTWynn




5

사용 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 줄만 있습니다.



3

MS Access 제한에서 벗어나기 위해 MySQL 또는 PostgreSQL로 마이그레이션 할 수 있습니다.

DBI (CRAN에서 사용 가능) 기반 데이터베이스 커넥터를 사용하여 R을 이러한 시스템에 연결하는 것은 매우 쉽습니다 .


더 나은 데이터베이스 도구를 사용하기 위해 손을 뻗었지만 관리가 번거롭기 때문에 (대기업의 관리 규정을 좋아해야 함) 내가 가진 것을 고수하려고합니다. 또한 내가받는 텍스트 파일간에 가능한 한 적은 변환을 목표로하고 있습니다.
FTWynn

3

scan ()에는 nlines 인수와 skip 인수가 모두 있습니다. 한 번에 한 줄씩 읽고 날짜를 확인하여 적절한 지 확인하는 데 사용할 수있는 이유가 있습니까? 입력 파일이 날짜순으로 정렬 된 경우 향후 프로세스 속도를 높이기 위해 건너 뛰기 및 n 라인이 무엇인지 알려주는 색인을 저장할 수 있습니다.


확인해 보겠습니다 만 날짜와 같은 도움이되는 파일로 정렬되어 있지 않습니다. 제공자는 특정 카운티가
속한

나는 당신이 그의 제안을 오해했다고 생각합니다. 파일 덩어리를 덩어리별로 읽고 각 덩어리에서 필요한 행만 추출하십시오. 파일을 주문할 필요가 없습니다.
Karl Forner

1

요즘 3.5GB는 그다지 크지 않습니다. Amazon 클라우드에서 244GB RAM (r3.8xlarge)을 사용하는 머신에 시간당 $ 2.80에 액세스 할 수 있습니다. 빅 데이터 유형 솔루션을 사용하여 문제를 해결하는 방법을 파악하는 데 몇 시간이 소요됩니까? 시간의 가치는 얼마입니까? 예, AWS를 사용하는 방법을 알아내는 데 한두 시간이 걸립니다.하지만 프리 티어에서 기본 사항을 배우고 데이터를 업로드 한 다음 R로 처음 10k 줄을 읽어서 작동하는지 확인한 다음 시작할 수 있습니다. r3.8xlarge와 같은 큰 메모리 인스턴스를 읽고 모두 읽어보세요! 내 2c.


0

이제 2017 년에는 spark와 sparkR을 사용하는 것이 좋습니다.

  • 구문은 dplyr과 유사한 방식으로 간단하게 작성할 수 있습니다.

  • 작은 메모리에 아주 잘 맞습니다 (2017 년 의미에서 작음)

그러나 시작하는 것은 위협적인 경험 일 수 있습니다 ...


-3

나는 DB로 가서 DBI를 통해 필요한 샘플을 추출하기 위해 몇 가지 쿼리를 할 것입니다.

3,5GB csv 파일을 SQLite로 가져 오지 마십시오. 또는 적어도 HUGE db가 SQLite 제한에 맞는지 다시 확인 하십시오. http://www.sqlite.org/limits.html

당신이 가지고있는 엄청나게 큰 DB입니다. 속도가 필요하면 MySQL을 선택하겠습니다. 그러나 가져 오기가 완료 될 때까지 많은 시간을 기다려야합니다. 틀에 얽매이지 않는 하드웨어가 있거나 미래에서 글을 쓰고 있지 않는 한 ...

Amazon의 EC2는 R 및 MySQL을 실행하는 서버를 인스턴스화하는 데에도 좋은 솔루션이 될 수 있습니다.

내 겸손한 두 동전 가치.


18
sqlite의 3.5Gb는 얼마나 큽니까? 당신이 적절한 파일 시스템을 사용하는만큼 문제가 없을 것 (I 정기적으로 사용하고 있습니다> 단일 사용자 애플리케이션을위한 30GB SQLite는 DBS)
아론 스테이트 햄
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.