criando dados CDF usando bash ou awk ou perl

0

temos alguns dados como:

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

Gostaria de obter esta saída:

3 0
5 1
6 4
7 100
8 204

explicação: temos 3 AS (sistemas autônomos) que têm grau 0, e então temos 5 AS que o grau é 1 ou menor que 1 e temos 6 AS que Grau é 4 ou menor que 4 e. ..

Existem muitas linhas (100.000) isso é CDF de distribuições, eu acho, isso faz parte da análise de dados do bgpdump e eu quero calcular esses números.e tnx novamente por sua ajuda

    
por Arash 20.12.2012 / 16:33

2 respostas

1

Aqui está um rápido script Perl que deve fazer o trabalho para você:

#!/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";
};

Esse script exigirá memória considerável para grandes conjuntos de dados de entrada; ele absorve todo o arquivo de entrada antes de operá-lo, porque não parece que o arquivo de entrada está classificado e é necessário classificar os dados por grau antes de operá-lo. Dito isto, deve fazer o trabalho para você muito bem - deixe-me saber se isso não acontecer!

    
por 20.12.2012 / 17:13
1

Aqui está um rápido script de 100% que fará o trabalho:

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

Se você quiser um script que possa chamar a partir de uma linha de comando:

#!/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

Ou se você preferir um verso para impressionar sua avó:

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

Ele é executado em cerca de 2-3 segundos no Pentium dual core @ 2.6GHz em um arquivo com 100.000 linhas.

Editar

Explicações:

O primeiro loop:

  • Inicializamos a para ser uma matriz vazia: a=()
  • Lemos o arquivo datafile.txt linha por linha. Existem dois campos por linha, apenas o segundo é colocado nos nomes das variáveis n
  • Se n não estiver vazio (esse é o teste [[ -n $n ]] , aumentamos o valor da n -th chave da matriz a ; é isso que a linha ((++a[n])) faz. ((...)) é contexto aritmético de bash.
  • Depois de ler todos os arquivos, temos uma matriz a e o campo k -th é exatamente o número de sistemas autônomos com um grau igual a k .

Em seguida, o segundo loop:

  • Antes do loop, a variável c está definida como 0.
  • for i in ${!a[@]}; do irá percorrer todas as chaves da matriz a .
  • $((c+=a[i])) adicionará o valor de a[i] a c e expandirá para esse valor. Esse valor é echo ed com o valor da chave i anexada a ele.

Espero que isso ajude!

    
por 20.12.2012 / 18:42