créer des données CDF en utilisant bash, awk ou perl

0

nous avons des données comme:

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

J'aimerais avoir cette sortie:

3 0
5 1
6 4
7 100
8 204

explication: nous avons 3 AS (systèmes autonomes) qui ont le degré de 0, puis nous avons 5 LAS qui sont degré 1 ou moins que 1 et nous avons 6 LAS que Le degré est 4 ou moins que 4 et ...

Il y a beaucoup de lignes (100 000) il s’agit de distributions CDF, je suppose, cela fait partie de l’analyse des données bgpdump et je veux calculer ces nombres.et encore une fois pour votre aide

Arash
la source
Pouvez-vous définir la transformation que vous souhaitez appliquer aux données? En regardant l'exemple, je ne peux pas dire ce que vous essayez de faire.
Aaron Miller
ok bien, nous avons 3 AS (systèmes autonomes) qui ont un degré de 0, et ensuite nous avons 5 AS, leur degré est de 1 ou moins que 1 et donc
Arash
ceci est un exemple de fonction de distribution cumulative (CDF)
Arash
1
On dirait donc que la colonne 2 des données est le degré, et que vous recherchez un résultat avec le degré dans la colonne 2 et le nombre de systèmes de ce degré (ou moins) dans la colonne 1. Voir la réponse ci-dessous -
Aaron Miller
Je veux ceci: nous avons 3 AS (systèmes autonomes) qui ont un degré de 0, puis nous avons 5 AS, leur degré est égal à 1 ou inférieur à 1 et nous avons 6 AS, leur degré est égal à 4 ou inférieur à 4 et .. .
Arash

Réponses:

1

Voici un script Perl rapide qui devrait faire le travail pour vous:

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

Ce script nécessitera une mémoire considérable pour les grands ensembles de données en entrée; il insère tout le fichier d'entrée avant de l'utiliser, car il ne semble pas que le fichier d'entrée soit trié, et il est nécessaire de trier les données par degré avant de les utiliser. Cela dit, il devrait assez bien faire le travail pour vous - faites le moi savoir si ce n'est pas le cas!

Aaron Miller
la source
je suis débutant en Perl comment puis-je transmettre mon fichier? puis-je utiliser: Perl yourscript myfile ??
Arash
1
Ouais - vient de modifier la réponse afin que le script accepte un nom de fichier sur la ligne de commande, vous pouvez donc l'appeler exactement de cette façon.
Aaron Miller
TNX u so muchhhhhhhhhhhhhhhhhhh: - *: D
Arash
1
Heureux d'avoir pu aider!
Aaron Miller
1

Voici un script rapide à 100% bash qui fera le travail:

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

Si vous voulez un script que vous pouvez appeler depuis une ligne de commande:

#!/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 si vous préférez une ligne pour impressionner votre grand-mère:

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

Il s'exécute en environ 2-3 secondes sur un processeur Pentium dual core à 2,6 GHz sur un fichier de 100 000 lignes.

Modifier

Explications:

La première boucle:

  • Nous initialisons apour être un tableau vide:a=()
  • Nous lisons le fichier datafile.txtligne par ligne. Il y a deux champs par ligne, seul le second est mis dans les noms de variablesn
  • Si nest non-vide (c'est le test que [[ -n $n ]]nous incrémentons la valeur de la n-th clé du tableau a; c'est ce que fait la ligne ((++a[n])). ((...))C'est le contexte arithmétique de bash.
  • Après avoir lu tous les fichiers, nous avons un tableau aet le ktroisième champ est exactement le nombre de systèmes autonomes ayant un degré égal à k.

Puis la deuxième boucle:

  • Avant la boucle, la variable cest définie sur 0.
  • for i in ${!a[@]}; dopassera en boucle à travers toutes les clés du tableau a.
  • $((c+=a[i]))ajoutera la valeur de a[i]à cet augmentera à cette valeur. Cette valeur est echoédité avec la valeur de la clé qui lui est iajoutée.

J'espère que cela t'aides!

gniourf_gniourf
la source
pourriez-vous svp expliquer les codes? tnx
Arash
1
@arashams Ajouté des explications.
gniourf_gniourf