일반적으로 R에서 실행되는 코드가 있는데 파일이 너무 커서 awk에서 동일한 명령을 실행하려고 합니다.
Gene
한 열의 값을 ID 열(또는 제 경우에는 열)별로 그룹화하려고 합니다 .
내 데이터는 다음과 같습니다.
Gene col1 col2 col3
ACE 1 0.4 BP
ACE 2 0.5 DP
RPP-I.1 1 0.01 BP
NOS2 -0.1 0.2 DP
NOS2 1.4 2.5 SP
NOS2 1 1 BP
나는 그것을 다음과 같이 그룹화하고 싶습니다 Gene
:
Gene col1 col2 col3
ACE 1, 2 0.4, 0.5 BP, DP
RPP-I.1 1 0.01 BP
NOS2 -0.1, 1.4, 1 0.2, 2.5, 1 BP, SP, DP
내 실제 데이터는 약 200개의 열과 24972316개의 행을 포함하는 14.8GB입니다. 처음에는 R의 data.table을 사용해 보았으나 파일을 읽으려고 할 때 버스 오류가 발생했습니다.
awk를 사용하여 이것을 시도할 수 있는 방법이 있습니까?
답변1
GNU를 사용하는 일반적인 솔루션 awk
은 다음과 같습니다.
gawk 'NR>1{ for (i=2; i<=NF; i++) {
c[i][$1]= c[i][$1]?c[i][$1] s $i:$i;
} next;
}1;
ENDFILE{
for (x in c[2]) {
printf ("%s", x);
for (i=2;i<=NF;i++) { printf ("\t%s", c[i][x]); delete c[i][x]; };
print "";
};
}' s=', ' infile |column -s $'\t' -t
위의 명령은 입력 파일의 거의 전부를 메모리에 로드하지 않고 메모리에 30GB의 RAM이 있고 파일 크기가 15GB 정도라고 했으니 최소 15GB 이상의 여유 메모리가 충분하다면 그럴 일은 없을 것 같습니다. 문제가 생길 것입니다.
그러나 아래는 해결 방법이지만 최선의 해결책은 아닙니다. bigfile.txt를 작은 파일로 분할하고 각 파일에 동일한 GeneName이 있는 다음 위 명령을 awk
모든 *.small
파일에 적용하고 출력을 추가 모드에서 단일 파일에 저장할 수 있습니다.
나는 유전자 이름의 분포가 동일하지 않을 수 있고, 일부는 더 적고 일부는 더 많을 수 있기 때문에 이것이 최적이 아니라고 말합니다. 그러나 다음과 같이 할 수 있습니다.
첫 번째 열에서 입력 파일을 작은 크기로 분할합니다
Gene
.awk 'NR>1{ print >$1".small"; }' bigfile.txt
awk
그런 다음 파일에 대해 위의 명령을 실행하십시오 .*.small
bigfile.txt를 분할할 때 이미 건너뛰었으므로 처음에 조건을 제거하십시오.NR>1
gawk '{ ... }; ENDFILE{ ... }' s=', ' *.small >>proccedfile
rm *.small
나중에 파일을 삭제하세요 .
답변2
다음은 sort
전체 파일을 한 번만 처리하면 대용량 파일을 처리할 수 있도록 설계되었으며, sort
Demand Paging 등을 사용하여 파일을 처리하도록 설계되었으므로 실제로 전체 입력을 메모리에 저장할 필요가 없습니다. awk 명령에서는 한 번에 현재 값만 저장되므로 $1
메모리 문제가 없습니다.
$ cat tst.sh
#!/usr/bin/env bash
awk -v OFS='\t' '{print (NR>1), NR, $0}' "${@:--}" |
sort -k1,1n -k3,3 -k2,2n |
cut -f 3- |
awk '
BEGIN { OFS="\t" }
NR == 1 { $1=$1; print; next }
$1 != prev { prt() }
{
for (i=2; i<=NF; i++) {
col[i] = (i in col ? col[i] ", " : "") $i
}
}
END { prt() }
function prt( i) {
if ( prev != "" ) {
printf "%s%s", prev, OFS
for (i=2; i<=NF; i++) {
printf "%s%s", col[i], (i<NF ? OFS : ORS)
}
}
delete col
prev = $1
}
'
$ ./tst.sh file
Gene col1 col2 col3
ACE 1, 2 0.4, 0.5 BP, DP
NOS2 1, 1.4, -0.1 1, 2.5, 0.2 BP, SP, DP
RPP-I.1 1 0.01 BP
위 스크립트의 출력은 탭으로 구분되어 있어 쉽게 다른 도구를 실행할 수 있고 스프레드시트로 가져올 수 있으므로 유용하다고 생각합니다. 시각적으로 정렬된 열을 생성하려면 스크립트 끝에 추가 | column -s $'\t' -t
하지만 인쇄하기 전에 최대 필드 너비를 계산하기 위해 전체 출력 파일을 메모리로 읽어야 할 수 있는 다른 프로그램을 도입하므로 YMMV를 사용할 수 없습니다. 탭으로 구분된 출력을 허용하고 표 형식 출력을 생성하는 데 사용할 수 없습니다 column
. 그런 다음 이와 관련된 새 질문을 게시하세요.
위 코드는 입력이 파일에서 오는지 파이프에서 오는지 여부에 관계없이 작동합니다.