탭으로 구분된 두 개의 큰 파일(>10GB)이 있고 정렬하면 해당 내용이 동일하다는 것을 알고 있습니다.
Source
그러나 동일한 "키"(여기서 키는 열을 기반 으로 Location
그룹화된 행 으로 정의됨)를 공유할 때 행의 순서와 교체된 행의 인덱스에 관심이 있습니다 .
즉, 이 두 파일 사이의 행은 동일한 그룹에 속해 있는 경우에만(즉, 동일한 소스와 위치를 공유하는 경우) 서로 비교되어야 합니다.
예를 들어, 아래 예에서 행 4, 5, 6은 file1.tsv
다음의 행 4, 5, 6과 비교되어야 합니다.file2.tsv
참고: 파일은 일반 TSV입니다. 더 나은 가시성을 위해 여기에 추가 공간을 추가하고 열을 중앙에 정렬하고 오른쪽으로 정렬하세요. 이 공백은 원본 파일의 일부가 아닙니다.
파일 1.tsv
Identifier Position Source Location
AY1:2301 87 ch1 14
BC1U:4010 105 ch1 14
AC44:1230 90 ch1 15
AJC:93410 83 ch1 16
ABYY:0001 101 ch1 16
ABC:01 42 ch1 16
HH:A9CX 413 ch1 17
LK:9310 2 ch1 17
JFNE:3410 132 ch1 18
MKASDL:11 14 ch1 18
MKDFA:9401 18 ch1 18
MKASDL1:011 184 ch2 50
LKOC:AMC02 18 ch2 50
POI:1100 900 ch2 53
MCJE:09HA 11 ch2 53
ABYCI:1123 15 ch2 53
MNKA:410 1 ch2 53
파일 2.tsv
Identifier Position Source Location
AY1:2301 87 ch1 14
BC1U:4010 105 ch1 14
AC44:1230 90 ch1 15
ABC:01 42 ch1 16
ABYY:0001 101 ch1 16
AJC:93410 83 ch1 16
HH:A9CX 413 ch1 17
LK:9310 2 ch1 17
MKASDL:11 14 ch1 18
JFNE:3410 132 ch1 18
MKDFA:9401 18 ch1 18
MKASDL1:011 184 ch2 50
LKOC:AMC02 18 ch2 50
MNKA:410 1 ch2 53
POI:1100 900 ch2 53
ABYCI:1123 15 ch2 53
MCJE:09HA 11 ch2 53
"diff"와 유사하지만 "그룹" 수준에서 수행하고 싶습니다(행이 Source
동일한 합계를 공유하는 경우에만 비교됨 Location
).
추출하고 싶어요원래동일한 "소스/위치" 내에서 줄의 순서가 "교환"되면 "줄 번호"그룹"(또는 키).
전체 줄의 내용이 일치해야 합니다.
하지만 어떻게 해야할지 모르겠습니다. 내가 생각할 수 있는 것은 for 루프를 작성하는 것뿐입니다. 이는 원래 데이터 세트에 수백만 개의 행이 있을 때 매우 비효율적입니다.
예상되는 결과:
Group_Source:Location df1.index df2.index
ch1:16 4 6
ch1:16 6 4
ch1:18 9 10
ch1:18 10 9
ch2:53 14 15
ch2:53 15 17
ch2:53 17 14
가정:
- 두 데이터 프레임 모두 동일한 수의 행을 갖습니다.
- 두 데이터프레임은 동일합니다(행 순서만 바뀌므로 둘 다 소스 기준, 위치 기준, 위치 기준, 식별자 기준으로 정렬된 경우 정확히 동일합니다).
- "교환된" 행은 항상 모든 열의 내용과 정확히 일치합니다.
답변1
입력 파일의 크기로 인해 이는 제가 사용할 수 있는 드문 경우 중 하나이므로 getline
>10G 대신 한 번에 몇 줄만 메모리에 유지합니다.
$ cat tst.awk
BEGIN {
OFS = "\t"
print "Group_Source:Location", "df1.index", "df2.index"
}
NR != FNR { exit }
{ srcLoc = $3 ":" $4 }
srcLoc != prevSrcLoc {
if ( NR > 1 ) {
diff()
}
prevSrcLoc = srcLoc
}
{
file1[$1,$2] = FNR - 1
if ( (getline < ARGV[2]) > 0 ) {
file2[$1,$2] = FNR - 1
}
}
END { diff() }
function diff( idPos) {
for ( idPos in file1 ) {
if ( file1[idPos] != file2[idPos] ) {
print prevSrcLoc, file1[idPos], file2[idPos]
}
}
delete file1
delete file2
}
$ awk -f tst.awk file1.tsv file2.tsv
Group_Source:Location df1.index df2.index
ch1:16 6 4
ch1:16 4 6
ch1:18 10 9
ch1:18 9 10
ch2:53 17 14
ch2:53 15 17
ch2:53 14 15
더 많은 정보를 getline
원하시면 읽어주세요http://awk.freeshell.org/AllAboutGetline.
Identifier
위 코드는 2개 파일 간의 4개 필드를 모두 비교하기 때문에 입력에서 및/또는이 반복되는 경우에도 작동합니다. Position
예제 입력에 표시된 것처럼 소스 및 위치 값이 두 파일 간에 동일한 순서로 있다고 가정합니다.
답변2
예를 들면 다음과 같습니다 awk
.
$ awk '{
if(FNR==1){
next
}
else if(FNR==NR){
a[$1]=FNR-1;
}
else if ( a[$1] != FNR-1 ){
print $3":"$4, FNR-1, a[$1]
}
}' file1.tsv file2.tsv
ch1:16 4 6
ch1:16 6 4
ch1:18 9 10
ch1:18 10 9
ch2:53 14 17
ch2:53 15 14
ch2:53 17 15
설명하다
if(FNR==1){ next }
:FNR
현재 읽고 있는 파일의 라인 번호(레코드 번호)를 저장합니다. 따라서 이것이 입력 파일의 첫 번째 줄인 경우 헤더를 처리하고 싶지 않으므로 건너뛰십시오.else if(FNR==NR){ ... }
:NR
어떤 파일을 읽고 있는지에 관계없이 현재 입력 줄 번호를 저장합니다. 따라서FNR
같으면NR
첫 번째 파일을 읽고 있다는 의미입니다.a[$1]=FNR-1
: 따라서 이것이 첫 번째 파일인 경우 첫 번째 필드를 연관 배열의 인덱스(키)로 저장하고 해당 값은 현재 파일의 줄 번호(FNR
)가 되지만 계산을 원하지 않기 때문에 1을 뺍니다. 머리글 .else if ( a[$1] != FNR-1 ){
: 이는else if
이전 파일과 관련되어 있으므로FNR
이 파일이 와 같지 않은 경우에만 입력하므로NR
두 번째 파일을 읽는 경우에만 입력됩니다. 그래서 우리가 두 번째 파일을 읽는다면그리고이 줄의 첫 번째 필드에 있는 배열에 저장된 값은a
현재 파일의 줄 번호에서 1을 뺀 것과 같지 않으므로 인쇄하려고 합니다.print $3":"$4, FNR-1, a[$1]
: 따라서 우리는 세 번째 필드인 a:
와 네 번째 필드를 인쇄한 다음 FNR 빼기 1과a
첫 번째 필드의 배열에 저장된 값을 인쇄합니다.
마지막으로 패딩과 헤더를 사용하여 예쁘게 인쇄하려면 다음을 사용하세요.
$ awk 'BEGIN{
printf "%-26s%-12s%-12s\n", \
"Group_Source:Location","df1.index","df2.index"
}
{
if(FNR==1){ next }
else if(FNR==NR){ a[$1]=FNR-1 }
else if ( a[$1] != FNR-1){
printf "%-26s%-12s%-12s\n", $3":"$4, FNR-1, a[$1]
}
}' file1.tsv file2.tsv
Group_Source:Location df1.index df2.index
ch1:16 4 6
ch1:16 6 4
ch1:18 9 10
ch1:18 10 9
ch2:53 14 17
ch2:53 15 14
ch2:53 17 15
중요한: 이 방법을 사용하려면 첫 번째 파일의 각 줄(헤더 제외)에 대해 메모리에 소량의 데이터를 유지해야 합니다. 이는 대용량 파일의 경우 문제가 될 수 있지만 이러한 작업이 수행될 가능성이 있는 대부분의 컴퓨터에서는 그렇지 않을 수도 있습니다. 이것이 문제라면 추천하고 싶습니다에드의 대답이는 훨씬 더 빠르고 메모리 문제도 없어야 합니다.