이것은 님의 후속 질문입니다.대용량 CSV 파일(90GB)을 정렬하는 중, 디스크 할당량이 초과되었습니다.. 이제 file1.csv 및 file2.csv와 같이 정렬된 두 개의 CSV 파일이 있습니다. 각 CSV 파일에는 다음과 같은 4개의 열이 있습니다.
파일 1:
ID Date Feature Value
01 0501 PRCP 150
01 0502 PRCP 120
02 0501 ARMS 5.6
02 0502 ARMS 5.6
파일 2:
ID Date Feature Value
01 0501 PRCP 170
01 0502 PRCP 120
02 0501 ARMS 5.6
02 0502 ARMS 5.6
이상적으로는 두 파일의 두 행이 동일한 ID, 날짜 및 기능을 가지고 있지만 값이 다른 경우 출력은 다음과 같은 방식으로 두 파일을 비교하고 싶습니다.
ID Date Feature Value1 Value2
물론 이 요구사항이 다소 높을 수도 있습니다. 그것은 마치
ID1 Date1 Feature1 Value1 ID2 Date2 Feature2 Value2
또한 작동합니다. 위의 예에서 출력하고 싶습니다.
01 0501 PRCP 150 170
또는
01 0501 PRCP 150 01 0501 PRCP 150
이렇게 비교하는 방법과 csv 파일로 출력하는 방법이 가장 큰 문제인 것 같습니다. 감사해요.
Gilles의 답변 출력 예: comm의 출력은 다음과 같습니다.
$ head -20 comm_output.txt ACW00011604,19490101,PRCP,0 AE000041196,20070402,TAVG,239 AE000041196,20070402,TAVG,244 AE000041196,20080817,TMIN,282 AE000041196,20130909,TAVG,350 AE000041196,20130909,TMAX,438 AE000041196,20130909,TMIN,294 AE000041196,20130910,TAVG,339 AE000041196,20130910,TAVG,341 AE000041196,20150910,TAVG,344
awk의 출력은 다음과 같습니다.
$ head awk_output.csv , ACW00011604,19490101,PRCP,0,,, AE000041196,20070402,TAVG,239,,, AE000041196,20070402,TAVG,244,,, AE000041196,20080817,TMIN,282,,, AE000041196,20130909,TAVG,350,,, AE000041196,20130909,TMAX,438,,, AE000041196,20130909,TMIN,294,,, AE000041196,20130910,TAVG,339,,, AE000041196,20130910,TAVG,341,,, AE000041196,20150910,TAVG,344,,,
주장하는 경우 샘플 입력은 다음과 같습니다.
head file1.csv
ACW00011604,19490101,PRCP,0 ACW00011604,19490101,SNOW,0 ACW00011604,19490101,SNWD,0 ACW00011604,19490101,TMAX,289 ACW00011604,19490101,TMIN,217 ACW00011604,19490102,PRCP,30 ACW00011604,19490102,SNOW,0 ACW00011604,19490102,SNWD,0 ACW00011604,19490102,TMAX,289 ACW00011604,19490102,TMIN,228
head file2.csv
ACW00011604,19490101,SNOW,0 ACW00011604,19490101,SNWD,0 ACW00011604,19490101,TMAX,289 ACW00011604,19490101,TMIN,217 ACW00011604,19490102,PRCP,30 ACW00011604,19490102,SNOW,0 ACW00011604,19490102,SNWD,0 ACW00011604,19490102,TMAX,289 ACW00011604,19490102,TMIN,228 ACW00011604,19490102,WT16,1
답변1
두 파일을 한 줄씩 결합하는 도구를 검토해 보겠습니다.
- 반죽내용에 신경 쓰지 않고 두 파일을 한 줄씩 결합합니다.
- 의사소통정렬된 파일을 병합하고 동일한 줄을 기록합니다. 이렇게 하면 동일한 행을 지울 수 있지만 다른 행을 결합하려면 다른 도구가 필요합니다.
- 가입하다정렬된 파일을 결합하여 동일한 필드와 일치시킵니다.
- 유형두 개의 파일을 병합할 수 있습니다.
- awk는 사용자가 지정한 규칙에 따라 여러 파일을 결합할 수 있습니다. 그러나 이렇게 큰 파일의 경우 범용 도구보다는 가장 적절한 전문 도구를 사용하면 최상의 성능을 얻을 수 있습니다.
중복이 없다고 가정합니다. 즉, 동일한 ID, 날짜 및 기능을 가진 두 개의 행이 하나의 파일에 존재하지 않습니다. 중복 항목이 있는 경우 처리 방법은 처리 방법에 따라 달라집니다. 또한 파일이 정렬되어 있다고 가정합니다. 나는 또한 당신의 껍질이프로세스 교체, 일반 sh 대신 bash 또는 ksh와 같으며 GNU coreutils가 있습니다(포함되지 않은 Linux 및 Cygwin의 경우).
구분 기호가 공백인지 탭인지 모르겠습니다. 공백이 있다고 가정합니다. 구분 기호가 항상 정확하게 탭인 경우 탭을 구분 기호( cut -d $'\t'
, join -t $'\t'
, sort -t $'\t'
)로 선언하고 대신 \t를 사용하면 [ \t]\+
성능이 약간 저하됩니다.
LC_ALL=C
멀티바이트 문자와 관련된 성능 저하를 방지하려면 로케일을 일반 ASCII( )로 설정하십시오 .
행은 하나의 필드를 기준으로만 결합할 수 있으므로 join
1~3번 필드를 단일 필드로 정리해야 합니다. 이렇게 하려면 구분 기호를 1과 2 사이, 2와 3 사이, 3과 4 사이로 변경하세요. 공백을 대체하기 위해 1-3을 변경하겠습니다 ;
. 이렇게 하면 동일한지 여부에 관계없이 모든 라인 조합을 얻을 수 있습니다. 그런 다음 sed를 사용하여 동일한 값을 가진 행을 삭제할 수 있습니다.
join -a 1 -a 2 <(sed 's/[ \t]\+/;/; s/[ \t]\+/;/' file1.csv) <(sed 's/[ \t]\+/;/; s/[ \t]\+/;/' file2.csv) |
sed '/[ \t]\(.*\)[ \t]\+\1$/d' |
tr ';' '\t'
페어링할 수 없는 행은 4열 행으로 끝나며 해당 행이 파일 1에 있는지 아니면 파일 2에 있는지 표시되지 않습니다. 페어링할 수 없는 모든 회선을 억제하려면 제거하세요 -a 1 -a 2
.
대부분 동일한 행이 있는 경우 이를 연결하고 지우는 데 시간이 낭비됩니다. 또 다른 방법은 를 comm -3
사용하여 동일한 행을 지우는 것입니다. 이렇게 하면 행이 순서대로 정렬되어 있지만 파일 2의 행에는 선행 탭이 있는 출력 스트림이 생성됩니다. 그런 다음 awk를 사용하여 동일한 필드 1-3이 있는 두 파일의 연속 행을 병합할 수 있습니다. 여기에는 awk가 포함되므로 다른 줄이 많으면 느려질 수 있습니다.
comm -3 file1.csv file2.csv |
awk '
$1 "\t" $2 "\t" $3 == k { if ($4 != v) print k "\t" v "\t" $4; next; }
{ print k "\t" v }
{ k=$1 "\t" $2 "\t" $3; v=$4; }
'
답변2
100만 줄이 포함된 2개의 파일을 빠르게 비교하는 방법을 찾았습니다. 내 필요는 두 파일이 동일해야한다는 것입니다. diff 명령은 느리지만 더 빠르게 하려면 파일을 비교하기 전에 정렬하면 됩니다.
그래서 기본적으로:
sort file01.txt > file01_sorted.txt
sort file02.txt > file02_sorted.txt
그런 다음 diff 명령을 실행합니다.
diff file01_sorted.txt file02_sorted.txt
또는 정렬된 파일에 대해 md5sum을 수행할 수 있습니다.
md5sum file01_sorted.txt
md5sum file02_sorted.txt
답변3
편집: 이 답변은 주변에 있는 누구에게나 적합할 수 있습니다.시스템에 200GB의 RAM을 사용할 수 있습니다.. 이런.
diff --side-by-side --suppress-common-lines file1.csv file2.csv
기본값은 이며 |
130자의 넓은 줄 구분 기호(필요한 경우 줄 바꿈 포함)입니다. 입력 형식과 동일하지 않은 것 같습니다.
다음과 같은 것을 시도해 볼 수 있습니다.
diff --old-line-format="%l$(printf '\t')" --new-line-format="%L" --unchanged-line-format="" file1.csv file2.csv