2016-07-15 3 views
1

큰 파일 (1GB)을 큰 data.frame (또는 data.table)으로 저장하여 만든 경우 작은 행의 하위 집합을 그 파일? 선명도에 대한 추가은 saveRDS()로 저장 한 data.frame에서 신속하게 행의 하위 집합을로드합니다.

(:. 런타임이 전체 데이터 세트의 크기는 약 추출 된 메모리의 양에 비례하지만 일정해야 즉 내가 빨리 mmap로 뭔가를 의미하는 "데이터를 건너 뛰는"기본적으로 가지고 있어야 제로 비용. 직렬화 형식에 따라 매우 쉽거나 불가능하거나 중간에있는 것이 될 수 있습니다.)

R serialization 형식을 사용하면 파일을 통해 파일의 관련 부분으로 건너 뛸 .

gzip은 압축 파일을 처음부터 모든 압축을 풀 필요가 있기 때문에 간단합니다.

saveRDS(object, file = "", ascii = FALSE, version = NULL, 
     compress = TRUE, refhook = NULL) 

하지만 바이너리 압축 (ascii=F) (compress=F) 같은 것을 허용 할 수 있습니다 희망하고있다. 파일에 mmap을 사용한 다음 관심있는 행과 열로 빠르게 건너 뛰십시오. 나는 그것을 바라고 있어요

이미 완료되었거나이 가능하고 내가 gdbm 같은 것들을 사용했습니다

R.

에서 잘 지원되는 다른 형식 (합리적으로 공간 효율)이 있습니다 (파이썬에서) 심지어 특정 데이터 구조에 대한 Rcpp의 사용자 정의 시스템을 구현했지만이 중 어느 것에도 만족하지 않습니다.

게시 한 후 패키지 ff (CRAN)으로 약간의 작업을했는데 매우 인상적이었습니다 (그래도 character 벡터는별로 지원하지 않음).

답변

3

암을 나는 바로이 압축 파일 불가능할 것이라는 가정에서, 단순히 GZIP는 시작하는 에 이르기까지 모든 것을 압축을 필요로하기 때문에? 같은 것을 할 것

AAAAVVBABBBC GZIP : 분명히 4A2VBA3BC

당신이 읽지 않고 파일에서 모든 A을 추출 할 수 없습니다

실제로 짧은 설명의가 출발점으로 일부 더미 방법을 보자 끝 부분에 A이 있는지 당신이 짐작할 수없는 것처럼 모두 말입니다.

다른 질문에 대해서는 "저장된 파일의 일부를로드 중입니다"내 머리 위에 해결 방법이 표시되지 않습니다. write.csvread.csv (또는 data.table 패키지의 fwritefread)과 skipnrows 매개 변수를 사용할 수 있습니다.

즉, 이미 읽은 파일의 함수를 사용하면 필터링 전에 파일 전체를 메모리에로드하는 것이므로 파일을 읽은 다음 메모리에서 부분 집합하는 것보다 시간이 더 걸리지는 않습니다.

Rcpp에서 메모리에로드하지 않고 데이터를 읽는 스트림을 활용할 수 있지만 보관해야하는지 여부를 결정하기 전에 각 항목을 읽고 파싱해도 실제 처리량이 향상되지는 않습니다.

saveDRS 예는 datas의 직렬화 된 버전을 저장한다 :

> myvector <- c("1","2","3"). 
> serialize(myvector,NULL) 
[1] 58 0a 00 00 00 02 00 03 02 03 00 02 03 00 00 00 00 10 00 00 00 03 00 04 00 09 00 00 00 01 31 00 04 00 09 00 00 00 01 32 00 04 00 09 00 00 
[47] 00 01 33 

그 코스의 파싱이지만, 포맷에 따라 바이트 당 읽기 바이트를 의미한다. 한편

, 당신이 (더 복잡한 데이터 또는 write.table) CSV로 작성하고 라인을 따라 뭔가를 읽기 전에 외부 도구를 사용할 수 있습니다

z <- tempfile() 
write.table(df, z, row.names = FALSE) 
shortdf <- read.table(text= system(command = paste0("awk 'NR > 5 && NR < 10 { print }'" ,z))) 

당신이 가진 리눅스 시스템이 필요합니다 몇 밀리 초 안에 수백만 라인을 파싱하거나 윈도우 컴파일 된 버전 을 분명히 사용할 수 있습니다.

주요 이점은 이 정규식 또는 다른 조건에서 각 데이터 행을 필터링 할 수 있다는 것입니다.

> str(ex) 
'data.frame': 3 obs. of 2 variables: 
$ a: chr "one" "five" "Whatever" 
$ b: num 1 2 3 

: data.frame의 케이스

보완하는 data.frame은 벡터 (단순한 경우) 우리가 dataframe 같은 그래서 만약리스트가 순차적으로 저장되며 더 이하인 목록 그건 직렬화는 다음과 같습니다

> serialize(ex,NULL) 
    [1] 58 0a 00 00 00 02 00 03 02 03 00 02 03 00 00 00 03 13 00 00 00 02 00 00 00 10 00 00 00 03 00 04 00 09 00 00 00 03 6f 6e 65 00 04 00 09 00 
[47] 00 00 04 66 69 76 65 00 04 00 09 00 00 00 08 57 68 61 74 65 76 65 72 00 00 00 0e 00 00 00 03 3f f0 00 00 00 00 00 00 40 00 00 00 00 00 00 
[93] 00 40 08 00 00 00 00 00 00 00 00 04 02 00 00 00 01 00 04 00 09 00 00 00 05 6e 61 6d 65 73 00 00 00 10 00 00 00 02 00 04 00 09 00 00 00 01 
[139] 61 00 04 00 09 00 00 00 01 62 00 00 04 02 00 00 00 01 00 04 00 09 00 00 00 09 72 6f 77 2e 6e 61 6d 65 73 00 00 00 0d 00 00 00 02 80 00 00 
[185] 00 ff ff ff fd 00 00 04 02 00 00 00 01 00 04 00 09 00 00 00 05 63 6c 61 73 73 00 00 00 10 00 00 00 01 00 04 00 09 00 00 00 0a 64 61 74 61 
[231] 2e 66 72 61 6d 65 00 00 00 fe 

아이디어에 대한 ASCII로 번역 :

X 
    one five Whatever?ð@@ names a b  row.names 
ÿÿÿý class 
data.frameþ 

우리는이 파일의 헤더,리스트의 헤더, 그리고리스트를 구성하는 각각의 벡터. 캐릭터 벡터가 얼마나 많은 크기를 취할 것인지에 대한 단서가 없기 때문에 우리는 임의의 데이터로 건너 뛸 수 없다. 텍스트 데이터 직전의 바이트 수). 대응하는 정수를 얻는 것이 더 나빠진다면, 우리는 정수형 벡터 헤더로 가야합니다. 정수형 헤더는 각 문자 헤더를 파싱하고 합계하지 않고는 결정할 수 없습니다.

제 생각에는 무언가를 제작하는 것이 가능하지만 실제로 모든 개체를 읽는 것보다 훨씬 빠르지는 않을 것이며 저장 형식에 취약 할 것입니다 (R은 이미 개체를 저장하는 3 가지 형식을 가짐).

Some reference here

직렬화 아스키 형식으로 출력 (더 읽기가 어떻게 구성되어 있는지 얻을)와 같은

동일보기 :

> write(rawToChar(serialize(ex,NULL,ascii=TRUE)),"") 
A 
2 
197123 
131840 
787 
2 
16 
3 
262153 
3 
one 
262153 
4 
five 
262153 
8 
Whatever 
14 
3 
1 
2 
3 
1026 
1 
262153 
5 
names 
16 
2 
262153 
1 
a 
262153 
1 
b 
1026 
1 
262153 
9 
row.names 
13 
2 
NA 
-3 
1026 
1 
262153 
5 
class 
16 
1 
262153 
10 
data.frame 
254 
+0

* "하지만 읽고 그것을 유지해야하는지 여부를 결정하기 전에 각 항목을 분석 그렇지 않으면 실제 처리량이 향상되지 않습니다. "* 모든 것을 읽을 필요는 없습니다. 'fseek'는 일정 시간 동안 임의의 큰 데이터를 건너 뛸 수 있습니다. 진정한 질문은 형식을 통해 우리가 무시하고자하는 하위 데이터 구조의 정확한 크기 (디스크 상)를 알 수 있는지 여부입니다. –

+0

@AaronMcDaid 사실, 형식은 순차적입니다. data.frame을 읽는 것은 다소 목록을 읽는 것이고 코드는 [여기]입니다 (https://github.com/wch/r-source/blob/73e11b7c40d3630604855e8eee3d1f309e2c9a57/src/main/serialize.c#L1611-L1645). 내가 무슨 뜻인지 생각하고 싶다면. 간단히 말해서, 각 행에 대해 여러 fseek를 수행해야하기 때문에 N 행을 건너 뛸 수 없다는 것입니다. 이 답변에 대한 몇 가지 세부 정보를 추가하겠습니다. – Tensibai

+1

설명해 주셔서 감사합니다. 나는 너의 대답을 다시 읽을거야. 실제로, 나는 이것을 해결하기 위해 data.frame의 열을 일련의'bigmemory' 객체 [CRAN의 bigmemory]에 저장하는 코드를 작성했습니다. (https://cran.r-project.org /web/packages/bigmemory/index.html). 이렇게하면 임의의 행을 임의로 검색 할 수 있습니다. 'character' 벡터를 특별한 방법으로 저장해야만 했었지만 지금은 효과가 있습니다. –