나는 다음과 같은 형태의 출력을 가지고있다 :
count id type
588 10 | 3
10 12 | 3
883 14 | 3
98 17 | 3
17 18 | 1
77598 18 | 3
10000 21 | 3
17892 2 | 3
20000 23 | 3
63 27 | 3
6 3 | 3
2446 35 | 3
14 4 | 3
15 4 | 1
253 4 | 2
19857 4 | 3
1000 5 | 3
...
어느 것이 지저분하고 CSV로 정리해야하므로 프로젝트 관리자에게 선물로 선물 할 수 있습니다.
문제의 핵심은 이것입니다 : 나는 이것의 출력이 필요합니다 :
id, sum_of_type_1, sum_of_type_2, sum_of_type_3
이에 대한 예는 id “4”입니다.
14 4 | 3
15 4 | 1
253 4 | 2
19857 4 | 3
대신 다음과 같아야합니다.
4,15,253,19871
불행히도 나는 이런 종류의 일에 꽤 쓰레기입니다. 모든 줄을 정리하고 CSV로 만들었지 만 행을 중복 제거하고 그룹화 할 수 없었습니다. 지금 나는 이것을 가지고있다 :
awk 'BEGIN{OFS=",";} {split($line, part, " "); print part[1],part[2],part[4]}' | awk '{ gsub (" ", "", $0); print}'
그러나 모든 것은 쓰레기 문자를 정리하고 행을 다시 인쇄하는 것입니다.
행을 위에서 언급 한 출력으로 마사지하는 가장 좋은 방법은 무엇입니까?
답변
이를 수행하는 방법은 모든 것을 해시에 넣는 것입니다.
# put values into a hash based on the id and tag
awk 'NR>1{n[$2","$4]+=$1}
END{
# merge the same ids on the one line
for(i in n){
id=i;
sub(/,.*/,"",id);
a[id]=a[id]","n[i];
}
# print everyhing
for(i in a){
print i""a[i];
}
}'
편집 : 첫 번째 답변이 질문에 올바르게 대답하지 못했습니다
답변
구조에 펄 :
#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
<>; # Skip the header.
my %sum;
my %types;
while (<>) {
my ($count, $id, $type) = grep length, split '[\s|]+';
$sum{$id}{$type} += $count;
$types{$type} = 1;
}
say join ',', 'id', sort keys %types;
for my $id (sort { $a <=> $b } keys %sum) {
say join ',', $id, map $_ // q(), @{ $sum{$id} }{ sort keys %types };
}
유형 테이블과 ID 테이블의 두 테이블을 유지합니다. 각 ID에 대해 유형별 합계를 저장합니다.
답변
경우 GNU의 datamash는 당신을위한 옵션이 다음이다
awk 'NR>1 {print $1, $2, $4}' OFS=, file | datamash -t, -s --filler=0 crosstab 2,3 sum 1
,1,2,3
10,0,0,588
12,0,0,10
14,0,0,883
17,0,0,98
18,17,0,77598
2,0,0,17892
21,0,0,10000
23,0,0,20000
27,0,0,63
3,0,0,6
35,0,0,2446
4,15,253,19871
5,0,0,1000
답변
파이썬 (그리고 pandas
특히 라이브러리는 이런 종류의 작업에 매우 적합합니다.
data = """count id type
588 10 | 3
10 12 | 3
883 14 | 3
98 17 | 3
17 18 | 1
77598 18 | 3
10000 21 | 3
17892 2 | 3
20000 23 | 3
63 27 | 3
6 3 | 3
2446 35 | 3
14 4 | 3
15 4 | 1
253 4 | 2
19857 4 | 3
1000 5 | 3"""
import pandas as pd
from io import StringIO # to read from string, not needed to read from file
df = pd.read_csv(StringIO(data), sep=sep='\s+\|?\s*', index_col=None, engine='python')
이것은 CSV 데이터를 pandas DataFrame
count id type
0 588 10 3
1 10 12 3
2 883 14 3
3 98 17 3
4 17 18 1
5 77598 18 3
6 10000 21 3
7 17892 2 3
8 20000 23 3
9 63 27 3
10 6 3 3
11 2446 35 3
12 14 4 3
13 15 4 1
14 253 4 2
15 19857 4 3
16 1000 5 3
그런 다음 이 데이터를로 그룹화id
하고 열의 합을 취합니다.count
df_sum = df.groupby(('type', 'id'))['count'].sum().unstack('type').fillna(0)
는 unstack
재 성형 이 ID가 컬럼에의 이동, 그리고는 fillna
공의와 빈 필드를 채 웁니다
df_sum.to_csv()
이 반환
id,1,2,3
2,0.0,0.0,17892.0
3,0.0,0.0,6.0
4,15.0,253.0,19871.0
5,0.0,0.0,1000.0
10,0.0,0.0,588.0
12,0.0,0.0,10.0
14,0.0,0.0,883.0
17,0.0,0.0,98.0
18,17.0,0.0,77598.0
21,0.0,0.0,10000.0
23,0.0,0.0,20000.0
27,0.0,0.0,63.0
35,0.0,0.0,2446.0
데이터 프레임에 누락 된 데이터 (빈 ID 유형 조합)가 포함되어 있기 때문에 팬더는 int
s를float
(내부 작업의 제한)으로 . 입력이 int로만 알려진 경우 다음에서 마지막 행을df_sum = df.groupby(('type', 'id'))['count'].sum().unstack('type').fillna(0).astype(int)
답변
Perl을 사용하여 CSV 파일을 반복하고 도중에 해시에서 해당 유형의 합계를 누적 할 수 있습니다. 마지막으로 모든 ID에 대해 수집 된 정보를 표시하십시오.
데이터 구조
%h = (
ID1 => [ sum_of_type1, sum_of_type2, sum_of_type3 ],
...
)
이것은 아래 코드를 이해하는 데 도움이됩니다.
펄
perl -wMstrict -Mvars='*h' -F'\s+|\|' -lane '
$, = chr 44, next if $. == 1;
my($count, $id, $type) = grep /./, @F;
$h{ $id }[ $type-1 ] += $count}{
print $_, map { $_ || 0 } @{ $h{$_} } for sort { $a <=> $b } keys %h
' yourcsvfile
산출
2,0,0,17892
3,0,0,6
4,15,253,19871
5,0,0,1000
...
답변
나의 테이크는 다른 사람들과 크게 다르지 않습니다. 배열 배열을 가진 GNU awk 사용
gawk '
NR == 1 {next}
{count[$2][$4] += $1}
END {
for (id in count) {
printf "%d", id
for (type=1; type<=3; type++) {
# add zero to coerce possible empty string into a number
printf ",%d", 0 + count[id][type]
}
print "" # adds the newline for this line
}
}
' file
출력
2,0,0,17892
3,0,0,6
4,15,253,19871
5,0,0,1000
10,0,0,588
12,0,0,10
14,0,0,883
17,0,0,98
18,17,0,77598
21,0,0,10000
23,0,0,20000
27,0,0,63
35,0,0,2446
답변
이 코드를 사용하여 id 열을 기준으로 값을 요약 할 수 있습니다.
코드 뒤에 awk 문을 하나 추가했습니다.
awk 'BEGIN{OFS=",";} {split($line, part, " "); print part[1],part[2],part[4]}' abcd | awk '{ gsub (" ", "", $0); print}' | awk 'BEGIN{FS=OFS=SUBSEP=","}{arr[$2,$3]+=$1;}END{for ( i in arr ) print i,arr[i];}'
이것으로 계속 …