Извлечение данных из столбцов Unix
У меня есть файлы с несколькими столбцами, и я хочу прочитать значения из определенного столбца. Я могу прочитать колонку, используя 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 ответа
Это может работать для вас:
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
Похоже, вы хотите подсчитать количество значений в каждом диапазоне 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
pipe является стандартной идиомой для подсчета вхождений и сортировки, так что наиболее частые появляются первыми. На самом деле, часто лучше оставить r
из окончательной сортировки, поэтому последние несколько строк вывода являются наиболее интересными.