Извлечение данных из столбцов Unix - PullRequest
1 голос
/ 13 марта 2012

У меня есть файлы с несколькими столбцами, и я хочу прочитать значения из определенного столбца. Я могу прочитать столбец, используя awk{print $column_number}.

Каждый файл имеет разную длину столбцов, то есть некоторые могут иметь длину 1000 записей, а другие - только 2 и т. Д. Сами записи варьируются от 1 до 5 цифр. Это одинаково для всех файлов.

Я хочу посчитать диапазон наиболее повторяющихся значений. Например, если в столбце указано:

5
93
201
2002
20003
20005
20087
31450
31451
31452
31458
52400
52428

затем я хочу сохранить 31,400 в качестве наиболее повторяющегося значения, затем 20,000 и 52,000 в качестве второго наиболее и третьего наиболее повторяющихся значений и так далее. Вы можете сказать, что я округляю значения, чтобы увидеть наиболее повторяющиеся числа, если это имеет смысл. Эти значения (наиболее повторяемые, вторые наиболее повторяющиеся) можно считать кратными 100. Поэтому в основном код должен выглядеть примерно так:

for f in ls path-to-the-files/*

do

while read i

    do
    <do the operation to sort and store the values>
done        

done

Буду признателен за помощь!

Ответы [ 2 ]

2 голосов
/ 13 марта 2012

Это может работать для вас:

sed 's/.\?.$//;s/^$/0/;s/.$/,&00/;s/^,/0,/' file | sort | uniq -c | sort -nr 
4 31,400
3 20,000
2 52,400
2 0,000
1 2,000
1 0,200

Если вас не интересует использование формата ,:

sed 's/.\?.$//;s/$/00/;s/^00$/0/' file | sort | uniq -c | sort -nr
  4 31400
  3 20000
  2 52400
  2 0
  1 2000
  1 200
1 голос
/ 13 марта 2012

Похоже, вы хотите подсчитать количество значений в каждом диапазоне 100, 0..99, 100..199, 200..299 и т. Д., А затем найти самый большой такой диапазон.

Вы, вероятно, можете сделать это в awk (и определенно в Python), но я собираюсь использовать Perl.

Я собираюсь жестко закодировать номер столбца в программе; это может быть изменено (например, опция в командной строке), если это необходимо. Я выбрал колонку 3, считая от 0.

#!/usr/bin/env perl
use strict;
use warnings;
use constant colno => 3;

my %ranges;

while (<>)
{
    my(@fields) = split /\s+/;
    my($key) = int($fields[colno] / 100);
    $range{$key}++;
}

# The hash now contains the number of entries for each range that's present in the
# data.  Now we need to hack the data so that we can easily find the range(s) with
# the largest counts.
# Apply the Schwartzian Transform: http://en.wikipedia.org/wiki/Schwartzian_transform

my @results = map  { [$_->[0], $_->[1]]  }
              sort { $a->[1] <=> $b->[1] }
              map  { [$_, $ranges{$_}]   }
                   keys %ranges;

# And print the results
foreach my $ref (reverse @results)
{
    printf "%5d = %d\n", $ref->[0] * 100, $ref->[1];
}

Для ваших образцов данных (дополненных тремя предыдущими столбцами), вывод будет:

31400 = 4
20000 = 3
    0 = 2
52400 = 2
 2000 = 1
  200 = 1

Преобразование Шварца - это глубокая черная магия. Это может быть не нужно здесь, но это работает. (И да, я впервые это использую.)


Код Perl был забавным (и, вероятно, довольно быстрым), но если у вас нет Perl на компьютере, вам нужна альтернатива.

awk '{value = int($3/100); print value*100;}' files |
sort |
uniq -c |
sort -nr

Код awk выбирает столбец 3 (считая от 1, а не 0!), Делит значение на 100 и преобразует его в целое число, а затем печатает значение, умноженное на 100; это дает группировку, которую вы хотите. Оставшийся sort | uniq -c | sort -nr конвейер - это стандартная идиома для подсчета вхождений и сортировки, так что наиболее частые появляются первыми. На самом деле, зачастую лучше не указывать r в окончательной сортировке, чтобы последние несколько строк были наиболее интересными.

...