2D直方图制作

我有一个数据文件包含两列,如

1.1 2.2 3.1 4.5 1.2 4.5 3.2 4.6 1.1 2.3 4.2 4.9 4.2 1.1 

我想从两列中得到一个直方图,也就是得到这个输出(如果在这种情况下,步长(或者在我们讨论直方图的时候, bin的大小等于0.1

 1.0 1.0 0 1.0 1.1 0 1.0 1.2 0 ... 1.1 1.0 0 1.1 1.1 0 1.1 1.2 0 ... 1.1 2.0 0 1.1 2.1 0 1.1 2.2 1 ... ... 

有人可以build议我吗? 如果我可以设定科尔姆斯的价值范围,这将是很好的。 在上述情况下,第一列值从1到4,与第二列相同。

编辑: 更新,以处理更一般的数据input,例如浮点数。 在上述情况下,步长为0.1,但如果其他设置可以调整,例如步长范围( bin size )为0.2或1.0 ,则步是可以调整的。 如果步长是例如1.0,那么如果我有1.1和1.8他们有相同的斌,我们必须一起处理它们,例如(在这种情况下的范围让我们说两个两个0.0 0.0 .. 4.0)

 1.1 1.8 2.5 2.6 1.4 2.1 1.3 1.5 3.3 4.0 3.8 3.9 4.0 3.2 4.0 4.0 

输出( 如果bin大小= 1.0

 1 1 2 1 2 1 1 3 0 1 4 0 2 1 0 2 2 1 2 3 0 2 4 0 3 1 0 3 2 0 3 3 1 3 4 1 4 1 0 4 2 0 4 3 1 4 4 1 

 awk 'END { for (i = 0; ++i <= l;) { for (j = 0; ++j <= l;) printf "%d %d %d %s\n", i, j, \ b[i, j], (j < l ? x : ORS) } } { f[NR] = $1; s[NR] = $2 b[$1, $2]++ }' l=4 infile 

你可以试试这个(没有经过彻底的测试):

 awk -vl=4 -v bs=0.1 'BEGIN { if (!bs) { print "invalid bin size" > "/dev/stderr" exit } split(bs, t, ".") t[2] || fl++ m = "%." length(t[2]) "f" } { fk = fl ? int($1) : sprintf(m, $1) sk = fl ? int($2) : sprintf(m, $2) f[fk]; s[sk]; b[fk, sk]++ } END { if (!bs) exit 1 for (i = 1; int(i) <= l; i += bs) { for (j = 1; int(j) <= l; j += bs) { if (fl) { fk = int(i); sk = int(j); m = "%d" } else { fk = sprintf(m, i); sk = sprintf(m, j) } printf "%s" m OFS m OFS "%d\n", (i > 1 && fk != p ? ORS : x), fk, sk, b[fk, sk] p = fk } } }' infile 

你可以在bash中试试这个:

 for x in {1..4} ; do for y in {1..4} ; do echo $x%$y 0 done done \ | join -1 1 -2 2 - -a1 <(sed 's/ /%/' FILE \ | sort \ | uniq -c \ | sort -k2 ) \ | sed 's/ 0 / /;s/%/ /' 

它创建了最后一列中全零的表格,并将其与实际结果(经典频率表sort | uniq -c )结合起来,并从应显示不同数字的行中移除零。

perl中的一个解决方案(样本输出和使用遵循):

 #!/usr/bin/perl -W use strict; my ($min, $step, $max, $file) = @ARGV or die "Syntax: $0 <min> <step> <max> <file>\n"; my %seen; open F, "$file" or die "Cannot open file $file: $!\n"; my @l = map { chomp; $_} qx/seq $min $step $max/; foreach my $first (@l) { foreach my $second (@l) { $seen{"$first $second"} = 0; } } foreach my $line (<F>) { chomp $line; $line or next; $seen{$line}++; } my $len = @l; # size of list my $i = 0; foreach my $key (sort keys %seen) { printf("%s %d\n", $key, $seen{$key}); $i++; print "\n" unless $i % $len; } exit(0);