我有一个包含两列的数据文件,例如
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 < / strong>在这种情况下)
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
...
...
有人可以给我一些建议吗?如果我可以设置colmuns的值范围,那就太好了。在上述情况下,第1列值从1到4,与第2列相同。
EDITED: 已更新,以便处理更多常规数据输入,例如浮点数。上述情况下的步长为0.1,但如果它可以为其他设置调整,那将是很好的,即步长范围( bin size )是例如0.2,或 1.0 < / strong>即可。 如果步长是例如1.0,那么如果我有1.1和1.8他们有相同的bin,我们必须一起处理它们(例如,在这种情况下的范围让我们说两个列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
答案 0 :(得分:2)
你可以在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
)连接,并从应显示不同数字的行中删除零。
答案 1 :(得分:2)
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 -v l=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
答案 2 :(得分:0)
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);