создание данных CDF с использованием bash или awk или perl

0

у нас есть некоторые данные, такие как:

12 0
13 0 
20 0
25 1
64 4
77 1
89 100
1201 204

Я хотел бы получить этот вывод:

3 0
5 1
6 4
7 100
8 204

объяснение: у нас есть 3 AS (автономные системы), которые имеют степень 0, а затем у нас есть 5 AS, у которых степень равна 1 или меньше 1, и у нас есть 6 AS, у которых степень составляет 4 или меньше 4 и ...

Я думаю, что есть много строк (100 000), это CDF дистрибутивов, это часть парсинга данных bgpdump, и я хочу вычислить эти числа. И снова tnx для вашей помощи

Сыпь
источник
Можете ли вы определить преобразование, которое вы хотите применить к данным? Глядя на пример, я не могу сказать, что вы пытаетесь сделать.
Аарон Миллер
хорошо, у нас есть 3 AS (автономные системы), которые имеют степень 0, а затем у нас есть 5 AS, которые имеют степень 1 или меньше 1, и поэтому
Arash
это пример накопительной функции распределения (CDF)
Arash
1
Похоже, что столбец 2 в данных - это степень, а вы ищете результат со степенью в столбце 2 и количеством систем этой степени (или меньше) в столбце 1. См. Ответ ниже -
Аарон Миллер
я хочу вот что: у нас есть 3 AS (автономные системы) со степенью 0, а затем у нас есть 5 AS, у которых степень равна 1 или меньше 1, и у нас есть 6 AS, у которых степень составляет 4 или меньше 4 и .. .
Arash

Ответы:

1

Вот быстрый Perl-скрипт, который должен сделать всю работу за вас:

#!/usr/bin/perl
use strict;
my %result;
my @data;
my %data;
my @degrees;
my $infile = shift() || die "Usage: $0 <file>\n";

# Read source data from input file
open IN, '<', $infile
    or die "Couldn't open data file: $!\n";
while (my $line = <IN>) { chomp $line; push @data, $line; };
close IN;

# Convert data lines to hash
foreach my $line (@data) {
    my ($count, $degree) = split(/\s+/, $line);
    $data{$degree}++;
};

# Get sorted degrees for count-up iteration
@degrees = sort { $a <=> $b } keys %data;

# Iterate degrees, adding each one's system count to result for this degree
# and all higher degrees
for (my $i = 0; $i < scalar(@degrees); $i++) {
    my $degree = $degrees[$i];
    my $count = $data{$degree};
    for (my $j = $i; $j < scalar(@degrees); $j++) {
        $result{$degrees[$j]} += $count;
    };
};

# Output result counts
foreach my $degree (sort { $a <=> $b } keys %result) {
    print "$result{$degree} $degree\n";
};

Этот сценарий потребует значительной памяти для больших входных наборов данных; он обрабатывает весь входной файл перед тем, как с ним работать, поскольку он не выглядит так, как будто входной файл отсортирован, и перед операцией необходимо отсортировать данные по степени. Тем не менее, это должно сделать работу для вас довольно хорошо - дайте мне знать, если это не так!

Аарон Миллер
источник
я начинающий в Perl, как я могу передать свой файл? Могу ли я использовать: Perl yourscript myfile ??
Араш
1
Да - просто отредактировал ответ, чтобы скрипт принимал имя файла в командной строке, чтобы вы могли называть его именно так.
Аарон Миллер
tnx у тебя так много, чххххххххххххххххх: - *: D
Араш
1
Рад помочь!
Аарон Миллер
1

Вот быстрый 100% скрипт bash, который сделает эту работу:

a=()
while read _ n; do
    [[ -n $n ]] && ((++a[n]))
done < datafile.txt
c=0
for i in ${!a[@]}; do
    echo "$((c+=a[i])) $i"
done

Если вам нужен скрипт, который вы можете вызвать из командной строки:

#!/bin/bash

a=()
while read _ n; do
    [[ -n $n ]] && ((++a[n]))
done < "$1"
c=0
for i in ${!a[@]}; do
    echo "$((c+=a[i])) $i"
done

Или, если вы предпочитаете однострочку, чтобы произвести впечатление на вашу бабушку:

a=(); while read _ n; do [[ -n $n ]] && ((++a[n])); done < datafile.txt; c=0; for i in ${!a[@]}; do echo "$((c+=a[i])) $i"; done

Он работает примерно за 2-3 секунды на двухъядерном процессоре Pentium с частотой 2,6 ГГц в файле с 100000 строк.

редактировать

Пояснения:

Первый цикл:

  • Мы инициализируем, aчтобы быть пустым массивом:a=()
  • Мы читаем файл datafile.txtпострочно. В каждой строке два поля, только второе добавляется в имена переменныхn
  • Если nне пусто (это тест, [[ -n $n ]]мы увеличиваем значение nключа -th массива a; это то, что ((++a[n]))делает строка . ((...))Это арифметический контекст bash.
  • После прочтения всех файлов у нас есть массив a, и kполе -th - это количество автономных систем, степень которых равна k.

Тогда второй цикл:

  • Перед циклом переменная cустанавливается в 0.
  • for i in ${!a[@]}; doбудет перебирать все ключи массива a.
  • $((c+=a[i]))добавит значение a[i]к cи расширит это значение. Это значение echoредактируется с iдобавлением значения ключа .

Надеюсь это поможет!

gniourf_gniourf
источник
Не могли бы вы, пожалуйста, объясните коды ?? tnx
Араш
1
@arashams Добавлены объяснения.
gniourf_gniourf