첫 번째 열로 계산하고, 두 번째 열로 고유 값을 계산하고, 첫 번째 열로 출력을 그룹화하시겠습니까?

첫 번째 열로 계산하고, 두 번째 열로 고유 값을 계산하고, 첫 번째 열로 출력을 그룹화하시겠습니까?

CSV 파일(7억 라인 이상)을 읽으려면 Unix 명령이 필요합니다. 예는 다음과 같습니다.

A, 10
B, 11
C, 12
A, 10
B, 12
D, 10
A, 12
C, 12

이 명령은 첫 번째 열의 발생 횟수를 계산한 다음 두 번째 열의 개별 발생 횟수를 계산하고 첫 번째 열의 항목별로 출력을 그룹화합니다. 출력은 다음과 같습니다.

A, 3, 2
B, 2, 2
C, 2, 1
D, 1, 1 

답변1

출력의 처음 두 열을 얻으려면 다음을 수행하십시오.

$ cut -d, -f1 <file | sort | uniq -c | awk -vOFS=, '{ print $2, $1 }'
A,3
B,2
C,2
D,1

원본 파일의 첫 번째 열을 추출하여 정렬하고 중복 항목 수를 계산합니다. 마지막으로 awk열을 바꾸고 그 사이에 쉼표를 삽입하십시오.

마지막 열에는

$ sort -u <file | cut -d, -f1 | uniq -c | awk -vOFS=, '{ print $1 }'
2
2
1
1

이렇게 하면 원본 데이터가 정렬되고 중복된 데이터가 삭제됩니다. 그런 다음 첫 번째 열과 중복 횟수를 추출합니다.저것계산됩니다. 마지막으로 awk개수만 추출됩니다.

다음을 사용 bash하고 결합하십시오 paste.

$ paste -d, <( cut -d, -f1 <file | sort    | uniq -c | awk -vOFS=, '{ print $2, $1 }' ) \
            <( sort -u <file | cut -d, -f1 | uniq -c | awk -vOFS=, '{ print $1 }' )
A,3,2
B,2,2
C,2,1
D,1,1

데이터를 미리 정렬하면 이 속도가 약간 더 짧아지고 훨씬 빨라질 수 있습니다.

$ sort -o file file

$ paste -d, <( cut -d, -f1 <file        | uniq -c | awk -vOFS=, '{ print $2, $1 }' ) \
            <( uniq <file | cut -d, -f1 | uniq -c | awk -vOFS=, '{ print $1 }' )
A,3,2
B,2,2
C,2,1
D,1,1

답변2

나는 Perl one-liner를 사용하여 이 문제를 해결할 수 있는지 확인하고 싶었고 그것을 알아낼 수 있었습니다.

$ perl -F, -ane '$lcnt{$F[0]}++; $ccnt{$F[0]}{$F[1]}++; \
    END { print "$_, $lcnt{$_}, " . (keys %{ $ccnt{$_} }) . "\n" for sort keys %lcnt }' \
      file
A, 3, 2
B, 2, 2
C, 2, 1
D, 1, 1

무너지다

파일을 통해 반복

이 문장은 매우 복잡해 보이지만, 일단 분해해보면 실제로는 매우 간단합니다. Perl의 핵심 메커니즘은 다음과 같습니다.

$ perl -F, -ane '...; END { ... }' file

이는 Perl에게 파일을 가져오고 file이를 반복하면서 -F,구분 기호를 사용하여 자동으로 분할하고, 완료되면 END {..}블록을 한 번 실행하고 종료하도록 지시합니다.

예를 들어:

$ perl -F, -ane 'print "arg1: $F[0] arg2: $F[1]"; END { print "DONE\n" }' file
arg1: A arg2:  10
arg1: B arg2:  11
arg1: C arg2:  12
arg1: A arg2:  10
arg1: B arg2:  12
arg1: D arg2:  10
arg1: A arg2:  12
arg1: C arg2:  12
DONE

노트:Perl의 자동 분할 기능은 자동으로 열을 배열에 넣습니다 . 여기서는 요소 1과 2, &를 @F사용하고 있습니다 .$F[0]$F[1]

물건을 세어보세요

다음으로 해야 할 일은 입력의 개별 비트를 계산하는 것입니다. 이를 위해 Perl의 해싱 기능을 활용하겠습니다. 우리는 2, 를 사용할 것 %lcnt입니다 %ccnt.

노트:Perl에서 가장 짜증나는 것 중 하나는 해시를 정의할 때와 해시에 액세스할 때 기호를 전환하는 것입니다. 액세스하면 에서 로 전환되지만 %lcnt다른 $lcnt["A"]방향으로 전환됩니다.

$lcnt{$F[0]}++; $ccnt{$F[0]}{$F[1]}++;
  • %lcnt- 첫 번째 열의 문자 수
  • %ccnt- 두 번째 열의 개수에 액세스하기 위한 2개 좌표의 2D 해시가 포함되어 있습니다.

노트:이런 식으로 사물을 세는 것은 우리가 숫자를 세는 방식만으로 독특한 기능을 수행할 수 있게 해준다.

%lcnt예를 들어 해시 내용을 확인해 보겠습니다 .

$ perl -F, -ane '$lcnt{$F[0]}++; $ccnt{$F[0]}{$F[1]}++; \
    END { print "key: $_\n" for sort keys %lcnt }' file
key: A
key: B
key: C
key: D

각 해시를 보려면 다음을 수행하세요.

$ perl -F, -ane '$lcnt{$F[0]}++; $ccnt{$F[0]}{$F[1]}++; \
    END { print "key: $_ val: $lcnt{$_}\n" for sort keys %lcnt }' file
key: A val: 3
key: B val: 2
key: C val: 2
key: D val: 1

노트:$lcnt{$F[0]}++여기서 우리는 모든 노력이 완료되었음을 볼 수 있습니다계산파일을 반복하고 각 문자를 해시에 추가합니다 %lcnt.

이게 결말이야

퍼즐의 마지막 조각은 수집된 모든 정보를 유용한 방식으로 표시하는 것입니다. 이를 위해 다음에서 사용합니다 END {...}.

print "$_, $lcnt{$_}, " . (keys %{ $ccnt{$_} }) . "\n" for sort keys %lcnt

그러면 키 목록을 반복하여 %lcnt다음 줄이 인쇄됩니다.

$_, $lcnt{$_}, " . (keys %{ $ccnt{$_} }) . "\n"

위의 구조를 확인하기 어려울 경우 보다 일반적인 구조는 다음과 같습니다.

A, 3, 2
      ^--- (keys %{ $ccnt{$_} })  ## count of unique columns for each character ($_)
   ^------ $lcnt{$_}              ## count of each character
^--------- $_                     ## character

그러면 문자( $_), 해당 문자의 개수 값( $lcnt{$_}) 및 두 번째 열의 각 문자에 대한 고유 값 개수가 포함된 행이 생성됩니다.

인용하다

답변3

입력 데이터가 있는 sqlite3명령줄에서 작은 스크립트를 실행합니다 .input.csv

sqlite3 -batch <<EOF
.mode csv

CREATE TABLE data (letter TEXT, number INTEGER);

.import input.csv data

SELECT letter, COUNT(*) AS lcount, COUNT(DISTINCT number) AS dcount
FROM data
GROUP BY letter ;
EOF

이것은 다음과 같이 작동합니다

$ bash query.sqlite 
A,3,2
B,2,2
C,2,1
D,1,1

답변4

datamash -t, -s -g 1 count 1 countunique 2 < input.txt

입력하다

A, 10
B, 11
C, 12
A, 10
B, 12
D, 10
A, 12
C, 12

산출

A,3,2
B,2,2
C,2,1
D,1,1

관련 정보