2010-06-08 5 views
2

저는 두 개의 CSV 파일에서 개별 행 사이의 다소 복잡한 diff를 시도하고 있습니다. 한 파일의 행이 다른 파일에 나타나지 않도록해야하지만 은 두 파일의 행의 순서를 보장하지 않습니다. 출발점으로, 행의 문자열 표현 (예 : Python 목록)의 해시를 비교하려고했습니다. 예 :파이썬 목록을 압축하고 비교하는 효율적이고 정확한 방법은 무엇입니까?

import csv 

hashes = [] 
for row in csv.reader(open('old.csv','rb')): 
    hashes.append(hash(str(row))) 

for row in csv.reader(open('new.csv','rb')): 
    if hash(str(row)) not in hashes: 
    print 'Not found' 

그러나 이것은 비참하게 실패합니다. 나는 변경할 수없는 인위적으로 부과 된 메모리 한계에 의해 제약을 받고 있으며 따라서 목록을 직접 저장하고 비교하는 대신 해시를 사용했습니다. 비교할 파일 중 일부는 수백 메가 바이트 크기 일 수 있습니다. 파이썬리스트를 정확하게 압축하는 방법에 대한 아이디어는 다른리스트와 단순한 평등의 관점에서 비교할 수 있습니까? 나는. 실제로 작동하는 해시 시스템? 보너스 포인트 : 왜 위의 방법이 효과가 없었습니까?

편집 : 모든 위대한 제안

감사합니다! 내가 몇 가지를 분명히하자. "Miserable failure"는 CSV.reader 개체에서 읽은 후 정확히 동일한 데이터를 가진 두 행이 목록 개체에서 str을 호출 한 후 동일한 값으로 해싱되지 않음을 의미합니다. 나는 아래의 몇 가지 제안에서 hashlib을 시도 할 것입니다. ,

1, 2.3, David S, Monday 
1, 2.3, "David S", Monday 

나는 이미 데이터를 균일하게 제거 문자열과 같은 일을하고있다 : 나는 또한 두 줄 아래 줄에 동일한 데이터,하지만 서로 다른 문자를 포함하기 때문에, 원시 파일의 해시를 할 수 없어 그러나 그것은 아무 소용이없는 것처럼 보인다. 나는 매우 똑똑한 diff 논리를 찾고 있지 않습니다. 즉 00.0과 같습니다.

EDIT 2 해결

문제. 기본적으로 작동하는 것은 정수 및 부동 소수점을 변환하는 것과 같은 좀 더 사전 형식화가 필요하다는 것입니다. 해시 함수를 변경해야했습니다. 이 두 가지 변화는 나를 위해 일하는 것처럼 보였다.

+2

어떻게 작동하지 않는지 더 자세히 말할 수 있습니까? –

+0

왜 세트를 사용하지 않습니까? 왜리스트인가? –

+0

@Ned 기본적으로 두 파일에서 두 weare가 동일하면 내 코드가 동일한 해시를 얻지 못했습니다.이유가 무엇인지, CSV에서 문자열 방식으로, 또는 독자가 파일을 다르게 읽는 방식에서 실패했을 수있는 많은 단계가 있는지 확신 할 수 없습니다. @ S.Lott 실제로 해시 행 쌍 사전을 사용하고 있었지만 샘플 코드를 더 간단하게 유지하려고했습니다. – daveslab

답변

4

제약 조건에 대한 자세한 내용을 알지 못해도 훌륭한 답을 제공하기는 어렵지만 각 파일의 각 줄마다 해시를 저장할 수 있다면 괜찮을 것입니다. 최소한 하나의 파일에 대한 해시 목록을 저장할 수 있어야합니다. 그러면 해시 목록을 디스크에 정렬 및 기록한 다음 두 개의 정렬 된 목록을 함께 실행할 수 있습니다.

해싱 함수가 주어진 입력에 대해 항상 동일한 출력을 제공하지는 않기 때문에 위와 같이 쓰지 않는 것이 상상할 수있는 유일한 이유는 것입니다. old.csv를 통해 두 번째 실행이 동일한 목록을 생성하는지 테스트 할 수 있습니다. 잘못된 대문자, 공백 대신 탭, 대소 문자가 다른 "자동

마인드와 관련이있을 수 있습니다. match (후보 행이 일치하는지 확인해야합니다.) (입력 파일에서 둘 이상의 행이 동일한 해시를 생성하는 상황이 발생할 수 있으므로이를 처리해야합니다.)

당신이 당신의 hashes 변수를 입력 한 후 사용자의 조회가 선형보다 더 빨리 할 수 ​​있도록

, 당신은 세트 (hashes = set(hashes))로 돌려 고려해야한다.

+0

+1을 사용하는 경우 +1. 또한 동일한 해시를 두 번 이상 저장하지 않아 메모리를 절약 할 수 있습니다. – intuited

+0

오, 사실 나는 그것을 잘못 읽었습니다. 처음부터'해시 '를 만드는 편이 낫지 않겠는가? 그는 시간이 아니라 메모리가 중요하다고 말합니다. – intuited

+0

이 모든 것이 사실이지만 '{hashval : [row1, row2, ... rowN]}'이 저장되어 충돌 사례를 확인할 수 있으므로 해시 블록의 묵시적 집합을 키로 정의하는 순 효과가 있습니다. 그 딕트. 'rowN'은 무수히 많은 파일이 다시 돌아 오는 것을 피하기 위해'file_offsetN'으로 저장하는 것이 더 낫습니다. – msw

1

'비참하게 실패하는'것이 정확히 의미하는 것에 대한 자세한 정보가 필요합니다. 둘 사이의 올바른 비교를 얻지 못했다면 아마도 Hashlib이이를 해결할 수 있습니다.

내장 해시 라이브러리를 사용할 때 이전에 문제가 발생하여 해결되었습니다.

편집 : 누군가 다른 게시물에서 제안했듯이 두 파일이 각 행을 정확히 같게해야한다는 가정하에 문제가 발생할 수 있습니다. csv 필드를 구문 분석하고 해시를 계산하기 전에 공백을 제거하고 소문자를 사용하는 등의 동일한 서식을 사용하여 문자열에 추가 할 수 있습니다.

0

hash을 (잘못) 사용했을 때 문제 일 수 있습니다. this SO question; 거기에 대한 답변을 지적하면 아마도 hashlib을 원할 것입니다.

+1

파일을 읽는 것만으로도 데이터가 동일하지만 다르게 표현되는 두 행이 없다고 가정합니다. 즉, 다른 따옴표, 이스케이프, 공백 등을 사용합니다. – intuited

+0

@intuited 결과에 대해'str()'을 즉시 호출하면 읽기, 당신은 아직도 그 같은 문제로 달리고 있지 않습니까? –

+0

csv.reader()를 통해이를 제공하면 정규화됩니다. 편집 질문을보십시오. 예 :''> cr = csv.reader ([ '1, "2", 3', '1,2,3']); str (cr.next()) == str (cr.next())''True'를 주겠다 – intuited

2

을 느슨한 구문 definiti을 감안할 때 on CSV를 사용하면 어휘 적으로 다르지만 두 행이 의미 론적으로 동일 할 수 있습니다. 다양한 Dialect definitions은 2 개의 행이 개별적으로 잘 형성되지만 비교할 수없는 방법으로 몇 가지 단서를 제공합니다. 그리고이 예제는 같은 방언이 아닌 동일한 방언에 어떻게 쓰일 수 있는지를 보여줍니다 :

0, 0 
0, 0.0 

더 많은 정보를 얻으면 더 좋은 대답을 얻을 수 있습니다.

0

문제가 실제로 무엇인지 말할 필요가 있습니다. "한 파일의 행이 다른 파일에 나타나지 않도록해야합니다."라는 설명은 if hash(...) in hashes: print "Found (an interloper)"이 아닌 두 번째 루프 본문과 일치합니다.

우리는 "위의 방법이 효과가 없었던 이유"를 말할 수 없습니다. 왜냐하면 당신은 "비참하게 실패했습니다"와 "효과가 없었습니다"라는 증상이 무엇인지 알려주지 않았기 때문입니다.

1

나는 "실패한 비참한"라인은 현재 알고리즘이 O (N^2)가되어 파일이 얼마나 큰지에 대해 상당히 나쁘다는 것을 의미합니다. 언급 한 바와 같이 set을 사용하여이 문제를 해결할 수 있습니다 (O (N)이됩니다). 또는 어떤 이유로 든 할 수 없다면 해시 목록을 정렬하고 이진 검색을 사용할 수 있습니다 (O (N log N)도 가능합니다.) 이진 탐색 경로로 간다면 bisect 모듈을 사용할 수 있습니다.

또한 해시 충돌 문제가있을 수 있다고 언급되었습니다 : 줄이 정확히 같지 않을 때 같은 해시를 생성하는 두 줄이 있습니다.이 문제가 발생한 문제인 경우 해시에 해당하는 줄을 찾을 위치에 대한 각 해시 정보를 저장해야합니다. old.csv 파일을 찾은 다음 줄을 찾아 두 줄을 비교하십시오.

현재 방법의 대안은 사전에 두 파일을 정렬하는 것입니다 (일종의 병합 정렬을 디스크 또는 셸 정렬을 사용하여). 각 파일의 줄에 포인터를 유지하면서 두 줄을 비교합니다. 일치하는지 확인하고 일치하지 않는 경우 측정 된 선을 더 작게 전진하십시오. 이 알고리즘은 O (N log N) 메소드가 정렬에 사용되는 한 O (N log N)이기도합니다. 정렬은 또한 각 파일을 데이터베이스에 넣고 데이터베이스에서 정렬하여 수행 할 수 있습니다.

0

아마도 (가능한 경우) 정렬을 실행하는 것으로 간주 했습니까? 두 번 이상 진행해야하지만 mem 문제는 해결 될 수 있습니다.

관련 문제