잘못 구분 된 일부 데이터를 유용한 CSV로 조작


13

나는 다음과 같은 형태의 출력을 가지고있다 :

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}'

그러나 모든 것은 쓰레기 문자를 정리하고 행을 다시 인쇄하는 것입니다.

행을 위에서 언급 한 출력으로 마사지하는 가장 좋은 방법은 무엇입니까?


카운트를 합산하고 싶습니까?
hjk

답변:


12

이를 수행하는 방법은 모든 것을 해시에 넣는 것입니다.

# 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];
    }
}'

편집 : 첫 번째 답변이 질문에 올바르게 대답하지 못했습니다


그렇습니다. 감사! 한가지 내가 ID를 일부 유형의 빈 따라서 CSV를 엉망으로 할 수 고려하지 않은,하지만 난에서 그 작은 세부 사항을 사용할 수 있습니다

@Paul 어쩌면 NF<4{$4="no_type";}시작에 추가
DarkHeart

11

구조에 펄 :

#!/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에 대해 유형별 합계를 저장합니다.


5

경우 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

4

파이썬 (그리고 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 유형 조합)가 포함되어 있기 때문에 팬더는 ints를float (내부 작업의 제한)으로 . 입력이 int로만 알려진 경우 다음에서 마지막 행을df_sum = df.groupby(('type', 'id'))['count'].sum().unstack('type').fillna(0).astype(int)


1
제공 한 코드의 기능을 설명해야하므로 특정 사람이 아니라이 게시물을 보는 모든 사람에게 도움이됩니다.
기금 모니카의 소송

이것이 더 명확합니까? 나는 또한
분리기

나에게 좋아 보인다. 설명을 추가해 주셔서 감사합니다!
기금 모니카의 소송

3

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
...

1

나의 테이크는 다른 사람들과 크게 다르지 않습니다. 배열 배열을 가진 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

0

이 코드를 사용하여 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];}'

이것으로 계속 ...

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.