Создание 2D гистограммы - PullRequest
4 голосов
/ 05 января 2012

У меня есть файл данных, содержащий два столбца, например

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
...
...

Кто-нибудь может мне что-то подсказать?Было бы хорошо, если бы я мог установить диапазон значений colmuns.В приведенном выше случае значения 1-го столбца изменяются от 1 до 4 и аналогичны значениям для второго столбца.

РЕДАКТИРОВАНИЕ: обновлено для обработки более общего ввода данных,например, числа с плавающей точкой.Размер шага в приведенном выше случае равен 0,1, но было бы неплохо, если бы его можно было настраивать для других настроек, например, если диапазон шага ( размер ячейки ) составляет, например, 0,2 или 1,0 * 1019.*.Если размер шага равен, например, 1.0, то, если у меня есть 1.1 и 1.8, они имеют одну и ту же корзину, мы должны обработать их вместе, например (диапазон в этом случае скажем 4 для обоих из двух столбцов 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

выход (, если размер корзины = 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

Ответы [ 3 ]

2 голосов
/ 05 января 2012

Вы можете попробовать это в 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) и удаляет нули из строк, где должно отображаться другое число.

2 голосов
/ 05 января 2012
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
0 голосов
/ 05 января 2012

Одно решение в 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...