100개의 파일이 있고 csv
각 파일에는 2개의 열이 포함되어 있습니다. 첫 번째는 이고 taxonomy
, 두 번째는 입니다 counts
. 각 파일에는 약 10,000줄이 있습니다. 각 파일의 데이터는 taxonomy
부분적으로만 공유되며 총 약 50,000개의 고유 값이 있습니다. taxa
한 파일에서 누락된 항목 에 값이 할당된 테이블로 병합해야 합니다 0
. 결과는 50,000개의 행과 101개의 열이 있는 테이블이어야 합니다 csv
. tsv
단순화된 예는 다음과 같습니다. 파일 1( R1.csv
):
A,1
B,20
C,30
파일 2( R2.csv
):
C,1
D,13
E,15
F,19
파일 3( R3.csv
):
A,1
B,4
E,2
G,6
H,8
예상되는 결과:
Taxa,R1,R2,R3
A,1,0,1
B,20,0,4
C,30,1,0
D,0,13,0
E,0,15,2
F,0,19,0
G,0,0,6
H,0,0,8
bash 스크립트를 사용하여 이 작업을 수행하는 방법을 아시나요?
답변1
나는 awk
이것을 사용하여 여러 파일을 한 번에 처리합니다.
sed 's/,R[1-9]\+\.csv:/,/g' <(awk -v HEADER="$(printf ",%s:" R{1..3}.csv)" -F, '
{ seen[$1]=seen[$1]","FILENAME":"$2; }
END { print HEADER; for (x in seen) print x seen[x]}' R{1..3}.csv \
|awk -F, 'NR==1{split($0,arr,/,/);next} {SEP=""; fld=1;
for (x in arr){printf ($0 ~ arr[x])?SEP""$(fld++):",0";SEP=","};print ""}')
산출:
A,1,0,1
B,20,0,4
C,30,1,0
D,0,13,0
E,0,15,2
F,0,19,0
G,0,0,6
H,0,0,8
코드 분석:
awk -F, '{ seen[$1]=seen[$1]","FILENAME":"$2; }
END{ print HEADER; for (x in seen) print x seen[x] }' R{1..3}.csv
코드의 주요 부분은 모든 파일의 두 번째 열을 모두 하나로 연결하고 동일한 첫 번째 열이 있는 파일에 속한 값을 인쇄합니다. 다음은 키가 첫 번째 열이고 값이 추가 모드 seen
인 배열 이름입니다 .,FILENAME:$2
In은 seen[$1]=seen[$1]","FILENAME":"$2;
쉼표를 인쇄하고 ,
그 뒤에 현재 처리된 FILENAME
파일을 인쇄하는 것을 의미합니다.앗, 콜론 :
뒤에 두 번째 열 값이 옵니다 $2
(첫 번째 열이 동일한 경우). seen[$1]=...
동일한 키 인덱스에 추가되고 =seen[$1]...
동일한 키 값에 저장됩니다.
이 END
진술은,앗이 블록은 모든 레코드/행을 읽을 때 최종적으로 실행되며 for 루프를 사용하여 배열을 반복합니다.본인쇄하고열쇠첫 번째와핵심 가치다음에서.
결과는 다음과 같습니다.
A,R1.csv:1,R3.csv:1
B,R1.csv:20,R3.csv:4
C,R1.csv:30,R2.csv:1
D,R2.csv:13
E,R2.csv:15,R3.csv:2
F,R2.csv:19
G,R3.csv:6
H,R3.csv:8
자, 이제 기존 값이 어떤 파일에서 왔는지, 어떤 파일에 이 데이터가 없는지 알 수 있습니다. 존재하지 않는 파일을 data 로 채우기 위해 0
쉘 명령을 사용했습니다.모든 파일 이름을 포함하는 헤더 행 생성그리고 전달앗~처럼HEADER
-V변하기 쉬운:
awk -v HEADER="$(printf ",%s:" R{1..3}.csv)" ...
HEADER
나중에 이 줄을 사용하겠습니다 0
. 현재 입력 형식은 다음과 같습니다.
$ awk -v HEADER="$(printf ",%s:" R{1..3}.csv)" -F, '
{ seen[$1]=seen[$1]","FILENAME":"$2; }
END { print HEADER; for (x in seen) print x seen[x]}' R{1..3}.csv
,R1.csv:,R2.csv:,R3.csv:
A,R1.csv:1,R3.csv:1
B,R1.csv:20,R3.csv:4
C,R1.csv:30,R2.csv:1
D,R2.csv:13
E,R2.csv:15,R3.csv:2
F,R2.csv:19
G,R3.csv:6
H,R3.csv:8
다음으로 아래의 다른 것을 사용했습니다.앗종료되지 않는 파일 데이터를 채우는 스크립트, 0
질문에 대한 다른 답변에서 이 데이터를 복사했습니다."열을 기준으로 서식을 지정하고 누락된 데이터 채우기".
... |awk -F, 'NR==1{split($0,arr,/,/);next} {SEP=""; fld=1;
for (x in arr){printf ($0 ~ arr[x])?SEP""$(fld++):",0";SEP=","};print ""}'
마지막으로 sed 's/,R[1-9]\+\.csv:/,/g'
결과의 기존 파일 이름을 단일 쉼표로 바꾸는 데 사용합니다 ,
.
답변2
훌륭하게 사용하다밀러, 넌 할 수있어
mlr --csv --implicit-csv-header put '$f=FILENAME;$f=sub($f,"\..+","")' then \
label Taxa then \
reshape -s f,2 then \
unsparsify then \
fill-empty -v 0 then \
sort-within-records then \
reorder -f Taxa *.csv
얻기 위해
Taxa,R1,R2,R3
A,1,0,1
B,20,0,4
C,30,1,0
D,0,13,0
E,0,15,2
F,0,19,0
G,0,0,6
H,0,0,8
답변3
이건 고통스러울 거야
join -t, -j1 -a1 -e0 -o auto r1.csv r2.csv > r12a.csv
join -t, -j1 -a2 -e0 -o auto r1.csv r2.csv > r12b.csv
sort -u r12?.csv > r12.csv
join -t, -j1 -a1 -e0 -o auto r12.csv r3.csv > r123a.csv
join -t, -j1 -a2 -e0 -o auto r12.csv r3.csv > r123b.csv
sort -u r123{a,b}.csv
- 첫 번째 연결은 파일 x( )에 짝이 없는 값을 인쇄합니다.
-ax
기본값은 (-e0
)-o auto
이며 연결에 0을 인쇄하도록 지시합니다. sort -u
고유한 기록을 분류하고 유지합니다.
awk
코드가 더 읽기 쉬울지는 잘 모르겠습니다 .
답변4
그것을 처리하는 방법은 여러 가지가 있습니다명령줄의 CSV, 또는 Archemar의 답변. 그러나 귀하의 요구 사항으로 인해 Python을 사용하는 것이 좋습니다. 저는 이 스크립트를 Python 3.5에서 테스트했는데 트릭을 수행하거나 적어도 좋은 시작을 제공해야 합니다.
import os,re,argparse
import csv
parser = argparse.ArgumentParser(description='join csvs with rows of the \
form \w+,[1-9], inserting a zero for a row label if it does not \
exist.')
parser.add_argument('infiles', type=str, help='infile names', nargs='+')
args = parser.parse_args()
d = {}
file_idx = 0
for infile in args.infiles:
with open(infile, 'r') as f:
for line in f:
parsed_line = re.match('(\w+),([0-9]+)', line)
if not parsed_line:
print("line {} not parsed in file {}".format(line, infile))
continue
if parsed_line.group(1) in d:
d[parsed_line.group(1)].append(parsed_line.group(2))
else:
l = [0]*(file_idx)
l.append(parsed_line.group(2))
d[parsed_line.group(1)]=l
for k in d:
if (len(d[k]) == file_idx):
d[k].append(0)
if not(len(d[k]) == file_idx+1):
print("problem with file {}, dict {}, key {}".format(f,d,k))
file_idx = file_idx + 1
## output time
with open('results.csv','w') as csvfile:
cwriter = csv.writer(csvfile)
header = [os.path.splitext(x)[0] for x in args.infiles]
header.insert(0,'Taxa')
cwriter.writerow(header)
for k in sorted(d.keys()):
d[k].insert(0,k)
cwriter.writerow(d[k])