投稿の延長線です最初の列が同じ平均行
入力ファイル:
a 12 13 14
b 15 16 17
a 21 22 23
b 24 25 26
希望の出力:
a 16.5 17.5 18.5
b 19.5 20.5 21.5
その投稿のawkコードは次のとおりです。
awk '
NR>1{
arr[$1] += $2
count[$1] += 1
}
END{
for (a in arr) {
print a "\t" arr[a] / count[a]
}
}
'
問題:このコードは最初の行でのみ機能します。このコードを複数の列に拡張するにはどうすればよいですか?
答え1
を使用すると、awk
キー(最初の列値)と列インデックスで複合インデックスを構成して2D配列をシミュレートできます。
awk '
{
c[$1]++;
for (i=2;i<=NF;i++) {
s[$1"."i]+=$i};
}
END {
for (k in c) {
printf "%s\t", k;
for(i=2;i<NF;i++) printf "%.1f\t", s[k"."i]/c[k];
printf "%.1f\n", s[k"."NF]/c[k];
}
}' file
a 16.5 17.5 18.5
b 19.5 20.5 21.5
perl
配列のハッシュを使用して、同様のアプローチをより直接的に実装できます。
あるいは、GNU datamash
(少なくともバージョン1.1.0以降)は非常にコンパクトにグループ平均化をサポートしています。
datamash --sort --whitespace groupby 1 mean 2-4 < file
a 16.5 17.5 18.5
b 19.5 20.5 21.5
FWIW ここでは、コメントで要求されたようにグローバル最大平均に正規化することを含む、Perl ソリューションに対する私の試みがあります。免責事項:私は初心者のPerlプログラマーなので、プログラムがうまくいかないかもしれません。。
#!/usr/bin/perl
use strict;
use warnings;
use List::MoreUtils qw(pairwise minmax);
use Math::Round qw(nearest);
my @hdr;
my %sums = ();
my %count = ();
my $key;
while (defined($_ = <ARGV>)) {
chomp $_;
my @F = split(' ', $_, 0);
# UGLY: hardcoded to expect exactly 1 header row
if ($. == 1) {
@hdr = @F;
next;
}
# sum column-wise, grouped by first column
$key = shift @F;
if ( exists $sums{$key} ) {
$sums{$key} = [ pairwise { $a + $b } @{ $sums{$key} }, @F];
}
else {
$sums{$key} = \@F;
}
$count{$key}++;
}
my %avgs = ();
# NB should really initialize $maxavg to a suitably large NEGATIVE value
my $maxavg = 0.0;
# find the column averages, and the global max of those averages
for $key ( keys %sums ) {
$avgs{$key} = [ map { $_ / $count{$key} } @{ $sums{$key} } ];
# NB could use List::Util=max here, but we're alresdy using List::MoreUtils
my ($kmin, $kmax) = minmax @{ $avgs{$key} };
$maxavg = $kmax > $maxavg ? $kmax : $maxavg;
}
# normalize and print the results, rounded to nearest 0.01
print join "\t", @hdr, "\n";
for $key ( sort keys %avgs ) {
print join "\t", $key, (map { nearest (0.01, $_ / $maxavg) } @{ $avgs{$key} }), "\n";
}
別の名前で保存しcolavgnorm.pl
て実行し、実行してください。
$ ./colavgnorm.pl file
K C1 C2 C3
a 0.77 0.81 0.86
b 0.91 0.95 1
file
どこ
K C1 C2 C3
a 12 13 14
b 15 16 17
a 21 22 23
b 24 25 26