두 개의 열이 포함된 파일이 있는 경우:
Id ht
510 69
510 67
510 65
510 62
510 59
601 29
601 26
601 21
601 20
동일한 ID를 가진 모든 행을 평균 높이의 행으로 병합하는 방법이 필요합니다. 이 예에서는 (69 + 67 + 65 + 62 + 59) / 5 = 64 및 (29 + 26 + 21 + 20) / 4 = 24이므로 출력은 다음과 같아야 합니다.
Id Avg.ht
510 64
601 24
sed/awk/perl을 사용하여 이 작업을 어떻게 수행할 수 있나요?
답변1
awk 사용:
입력 파일
$ cat FILE
Id ht
510 69
510 67
510 65
510 62
510 59
601 29
601 26
601 21
601 20
쉘에서 awk :
$ awk '
NR>1{
arr[$1] += $2
count[$1] += 1
}
END{
for (a in arr) {
print "id avg " a " = " arr[a] / count[a]
}
}
' FILE
또는 쉘에서 Perl을 사용하십시오.
$ perl -lane '
END {
foreach my $key (keys(%hash)) {
print "id avg $key = " . $hash{$key} / $count{$key};
}
}
if ($. > 1) {
$hash{$F[0]} += $F[1];
$count{$F[0]} += 1;
}
' FILE
출력은 다음과 같습니다
id avg 601 = 24
id avg 510 = 64.4
마지막 농담은 Perl의 어둡게 난독화된 한 줄짜리 농담입니다 =)
perl -lane'END{for(keys(%h)){print"$_:".$h{$_}/$c{$_}}}($.>1)&&do{$h{$F[0]}+=$F[1];$c{$F[0]}++}' FILE
답변2
#!/usr/bin/perl
use strict;
use warnings;
my %sum_so_far;
my %count_so_far;
while ( <> ) {
# Skip lines that don't start with a digit
next if m/^[^\d]/;
# Accumulate the sum and the count
my @line = split();
$sum_so_far{$line[0]} += $line[1];
$count_so_far{$line[0]} += 1;
}
# Dump the output
print "Id Avg.ht\n";
foreach my $id ( keys %count_so_far ) {
my $avg = $sum_so_far{$id}/$count_so_far{$id};
print " $id $avg\n";
}
산출:
ire@localhost$ perl make_average.pl input.txt
Id Avg.ht
510 64.4
601 24
예제 출력이 잘못되었습니다. 해당 ID의 모든 값이 59 이상이면 평균 52를 얻을 수 없습니다.
또한 열 중 하나에 l
숫자로 위장한 문자가 있습니다 1
.
답변3
그리고gnu
datamash
:
datamash -H -s -g 1 mean 2 <file
GroupBy(ID) 평균() 510 64.4 601 24
s
헤더를 유지하면서 정렬 및 그룹화할 첫 번째 필드를 기준으로 두 번째 필드 값을 계산합니다 . 필드가 단일 탭 문자로 구분되어 있다고 가정합니다. 여러 공백으로 구분되거나 다른 필드 구분 기호(공백, 쉼표 등)를 정의하는 경우 사용됩니다. 입력을 정렬해야 하므로 출력은 그룹화 열을 기준으로 정렬됩니다.g
1
2
mean
H
-W, --whitespace
-t, --field-separator=
datamash
답변4
여기에서 수행된 작업을 확인하세요.http://www.sugihartono.com/programming/group-by-count-and-sorting-using-perl-script/
가장 어려운 부분은 "그룹별" 작업을 수행하는 것입니다. 링커 스크립트는 이를 달성하기 위해 해시를 사용합니다.
해당 링크에서는 합계를 계산하지만 평균을 구해도 큰 차이가 없습니다.