2010-02-17 5 views
2

매우 일반적인 제목을 위해 유감스럽게 생각하지만 가능한 구체적으로하려고 노력할 것입니다.파이썬에서 사전 병합하기

저는 텍스트 마이닝 응용 프로그램을 만들고 있습니다. 나는 여러 개의 파이썬 사전 (튜플 -> int)에 저장하고있는 ((워드, 코퍼스) -> occurence_count) (모든 것은 정수이다.) 형식의 키 값 쌍을 많이 가지고있다. 이 값은 디스크의 여러 파일에 분산되어 있습니다 (절임). 데이터를 이해하려면 이러한 사전을 집계해야합니다 기본적으로 모든 사전에있는 특정 키의 모든 항목을 찾아 총계를 계산하는 방법을 찾아야합니다.

한 번에 두 개 이상의 사전을로드하는 경우 메모리가 부족하여 처음부터 분리해야했습니다. 시도 할 때 성능 문제가 발생했습니다. mysql은 행 레벨 잠금을 제공하기 때문에 DB (mysql)에 값을 저장하려고합니다. mysql은 행 레벨 잠금을 제공하기 때문에 (이 작업을 병렬화 할 수 있음을 의미하므로) 좋지 않습니다. 삽입 검색어)

내 옵션에는 어떤 것들이 있습니까? 내가 한 번에 하나씩 dicts를 처리 할 수 ​​있도록 부분적으로 디스크 기반 사전을 작성하는 것이 좋은 생각입니까? LRU 교체 전략이 있습니까? 내가 완전히 잊어 버린 어떤 것이 있는가?

감사합니다.

+0

"큰 숫자"를 정의하십시오. "나는 추억이 없다". 정말? 사전에있는 요소의 수와 같은 세부 정보가 없으면 이해하기 힘듭니다. "시도 할 때 성능 문제가 발생했습니다." 뭐라 구요? –

+0

"모든 것이 정수입니다"라고 말하면 단어와 코퍼스는 단어와 코퍼스의 정수 ID입니까? 단어 ID는 전체에서 일관성이 있습니까? – forefinger

+0

모두에게 감사드립니다! 나는 그것을 해결하기 위해 문제를 조금 재정의했다. – fsm

답변

0

이런 식으로 뭔가, 내가 당신의 질문을 이해한다면 제대로

from collections import defaultdict 
import pickle 

result = defaultdict(int) 
for fn in filenames: 
    data_dict = pickle.load(open(fn)) 
    for k,count in data_dict.items(): 
     word,corpus = k 
     result[k]+=count 
2

디스크 기반 사전 같은 존재 - shelve 모듈을 참조하십시오. 선반에있는 키는 문자열이어야하지만, 동등한 문자열 키를 얻기 위해 튜플에 str을 간단하게 사용할 수 있습니다. 더하기, 나는 당신이 단지 word을 키로 원한다는 것을 의미하는 것으로 당신의 질문을 읽었습니다. 그래서 더 쉬울 것입니다 (str- 또는 어휘가 < 4 GB이면 struct.pack - 괜찮을 것입니다).

좋은 관계형 엔진 (특히 PostgreSQL)은 사용자에게 도움이되지만 한 번에 하나의 사전을 처리하여 모든 단어에 대한 전체 자료를 shelf 객체로 집계하는 것은 OK 여야합니다 (빠르기는 어렵지 만 코드는 더 간단합니다). shelfdict과 매우 유사하기 때문에 [[및 변경 가능한 값에 대한 경고가 있지만 값은 int이므로 걱정할 필요가 없습니다. 내가 제대로 질문을 이해하고 단어와 말뭉치에 대한 정수 ID를하는 경우

0
  1. 는, 당신은, 심지어 더 나은 NumPy와 배열을 목록에 딕셔너리로 ​​전환하여 일부 성능을 얻을, 또는 수 있습니다. 이것은 귀찮을 수 있습니다!

    기본적으로 튜플을 newid라고하는 단일 정수로 바꿔야합니다. 모든 신입 사원이 단어, 코퍼스 쌍에 해당하기를 원합니다. 그래서 각 코퍼스의 단어를 세어 각 코퍼스에 대해 시작 뉴이 드를 갖습니다. newid of (word, corpus)는 단어 + start_newid [corpus]가됩니다.

    내가 당신에게 오해하고 그런 ID를 가지고 있지 않다면이 조언이 여전히 유용하다고 생각하지만 데이터를 int 형식의 튜플로 가져와야합니다.

  2. 데이터를 다시 채취하는 것이 좋습니다.

    이 몬스터 중 오직 1.1 개만 메모리에 저장할 수 있다고 가정 해 보겠습니다. 그런 다음 하나를로드하고 (단어, 코퍼스) 쌍의 처음 10 %에만 해당하는 더 작은 dict 또는 배열을 만들 수 있습니다.로드 된 dict을 스캔하고 처음 10 %에있는 것을 처리 할 수 ​​있습니다. 완료되면 결과를 디스크에 다시 쓰고 두 번째 10 %에 대해 다른 패스를 수행 할 수 있습니다. 이것은 10 패스가 필요하지만, 그것은 당신을 위해 괜찮을 수도 있습니다.

    메모리에 맞는 것을 기준으로 이전 청크를 선택한 경우 이전 dicts를 임의로 절반으로 나누어야 메모리에서 결과 dict/array를 보유 할 수 있습니다.

관련 문제