Pregunta crear datos de CDF usando bash o awk o perl


tenemos algunos datos como:

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

Me gustaría obtener esta salida:

3 0
5 1
6 4
7 100
8 204

explicación: tenemos 3 AS (sistemas autónomos) que tienen un grado de 0, y luego tenemos 5 AS que su grado es 1 o menor que 1 y tenemos 6 AS que Grado es 4 o menor que 4 y ...

Hay muchas líneas (100,000) esto es CDF de distribuciones, supongo, esto es parte del análisis de los datos de bgpdump y quiero calcular esos números. TNX nuevamente por tu ayuda


0


origen


¿Puedes definir la transformación que quieres aplicar a los datos? Mirando el ejemplo, no puedo decir lo que estás tratando de hacer. - Aaron Miller
bien, tenemos 3 AS (sistemas autónomos) que tienen un grado de 0, y luego tenemos 5 AS que su grado es 1 o menos de 1 y entonces - Arash
este es un ejemplo de función de distribución acumulativa (CDF) - Arash
Parece que la columna 2 de los datos es el grado, y lo que está buscando es un resultado con el grado en la columna 2 y el número de sistemas de ese grado (o menos) en la columna 1. Consulte la respuesta a continuación - - Aaron Miller
Quiero esto: tenemos 3 AS (sistemas autónomos) que tienen un grado de 0, y luego tenemos 5 AS que su grado es 1 o menor que 1 y tenemos 6 AS que ellos Degree es 4 o menor que 4 y ... . - Arash


Respuestas:


Aquí hay un script rápido de Perl que debería hacer el trabajo por usted:

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

Este script requerirá una memoria considerable para grandes conjuntos de datos de entrada; sorbe todo el archivo de entrada antes de operar en él, porque no parece que el archivo de entrada esté ordenado, y es necesario ordenar los datos por grado antes de operar en él. Dicho esto, debería hacer el trabajo por usted bastante bien, ¡dígame si no lo hace!


1



Estoy begginear en Perl, ¿cómo puedo pasar mi archivo? ¿Puedo usar: perl yourscript myfile? - Arash
Sí, acabo de editar la respuesta para que el script acepte un nombre de archivo en la línea de comando, para que pueda llamarlo exactamente de esa manera. - Aaron Miller
tnx u muchísimohhhhhhhhhhhhh: - *: D - Arash
¡Me alegra ser de ayuda! - Aaron Miller


Aquí hay un script 100% bash rápido que hará el trabajo:

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 desea un script que puede llamar desde una línea 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

O si prefiere un trazador de líneas para impresionar a su abuela:

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 ejecuta en aproximadamente 2-3 segundos en Pentium dual core @ 2.6GHz en un archivo con 100000 líneas.

Editar

Explicaciones

El primer ciclo

  • Inicializamos a para ser una matriz vacía: a=()
  • Leímos el archivo datafile.txt linea por linea. Hay dos campos por línea, solo el segundo se coloca en los nombres de las variables n
  • Si n no está vacío (esta es la prueba) [[ -n $n ]] incrementamos el valor de la n-th key of array a; eso es lo que la línea ((++a[n])) hace. ((...)) es el contexto aritmético de bash.
  • Después de leer todos los archivos, tenemos una matriz a, y el k-th campo es exactamente el número de sistemas autónomos que tienen un grado igual a k.

Luego, el segundo ciclo:

  • Antes del bucle, variable c está configurado a 0.
  • for i in ${!a[@]}; do recorrerá todas las teclas del array a.
  • $((c+=a[i])) agregará el valor de a[i] a c y expandir a este valor Este valor es echoed con el valor de la clave i anexado a él.

¡Espero que esto ayude!


1



podrías por favor explicar los códigos? tnx - Arash
@arashams Explicaciones agregadas. - gniourf_gniourf