procesamiento de textos a partir de un archivo que no es plana (para extraer información como si se * * un archivo plano)

StackOverflow https://stackoverflow.com/questions/2264504

Pregunta

Tengo un conjunto de datos longitudinal generada por una simulación por ordenador que se puede representar por las siguientes tablas ( 'var' son variables):

time subject var1 var2 var3
t1   subjectA  ...
t2   subjectB  ...

y

subject   name
subjectA  nameA
subjectB  nameB

Sin embargo, el archivo generado escribe un archivo de datos en un formato similar al siguiente:

time t1 
  description
subjectA nameA
  var1 var2 var3
subjectB nameB
  var1 var2 var3
time t2
  description
subjectA nameA
  var1 var2 var3
subjectB nameB
  var1 var2 var3
...(and so on)

He estado usando un script (python) para procesar estos datos de salida en un archivo de texto plano para que pueda importarlo en R, pitón, SQL o awk / grep para extraer información - un ejemplo del tipo de información deseada de una sola consulta (en notación SQL, después de los datos se convierte en una tabla) se muestra a continuación:

SELECT var1, var2, var3 FROM datatable WHERE subject='subjectB'

Me pregunto si hay una solución más eficaz que cada uno de estos archivos de datos puede ser ~ 100 MB cada uno (y tengo cientos de ellos) y crear el archivo de texto plano es mucho tiempo y ocupa espacio en disco duro adicional redundante información. Idealmente, me gustaría interactuar con los datos originales creados directamente para extraer la información que deseo, sin crear el archivo de texto plano adicional ... ¿Hay una solución awk / Perl para este tipo de tareas que es más simple? Estoy bastante eficientes en el procesamiento de textos en Python, pero mis habilidades en AWK son rudimentarios y no tengo conocimiento de Perl; Me pregunto si estas u otras herramientas específicas de dominio pueden proporcionar una mejor solución.

Gracias!

PostScript: Wow, gracias a todos! Siento que no puedo elegir respuestas de todo el mundo @FM: gracias. Mi script Python se asemeja a su código sin la etapa de filtración. Sin embargo, su organización está limpio. @PP: pensé que ya estaba competentes en grep pero al parecer no! Esto es muy útil ... pero creo grepping se hace difícil cuando la mezcla del 'tiempo' en la salida (que no pude incluir como un posible escenario de extracción en mi ejemplo! Ese es mi mal). @ Ghostdog74: Esto es simplemente fantástico ... pero modificando la línea de conseguir 'subjecta' no fue sencillo ... (aunque voy a estar leyendo hasta más en awk, mientras tanto, y espero asimilo más adelante). @weismat: Bien dicho. @ S. Lott: Esto es muy elegante y flexible - yo no estaba pidiendo una solución pitón (IC), pero esto encaja limpiamente con el análisis sintáctico, filtro, y un marco de salida sugerida por el PP, y es lo suficientemente flexible como para dar cabida a una serie de diferentes consultas para extraer diferentes tipos de información de este archivo jerárquico.

Una vez más, estoy agradecido a todo el mundo -. Muchas gracias

¿Fue útil?

Solución

Esto es lo que los generadores de Python se trata.

def read_as_flat( someFile ):
    line_iter= iter(someFile)
    time_header= None
    for line in line_iter:
        words = line.split()
        if words[0] == 'time':
            time_header = [ words[1:] ] # the "time" line
            description= line_iter.next()
            time_header.append( description )
        elif words[0] in subjectNameSet:
            data = line_iter.next()
            yield time_header + data

Puede utilizar esto como un iterador estándar de Python

for time, description, var1, var2, var3 in read_as_flat( someFile ):
    etc.

Otros consejos

Si lo que quieres es var1, var2, var3 en juego un tema en particular, entonces puede probar con el siguiente comando:


  grep -A 1 'subjectB'

El argumento de la línea de comandos grep -A 1 da instrucciones para imprimir la línea encajada y una línea después de la línea encajada (y en este caso las variables entran en una línea después del sujeto).

Es posible que desee utilizar la opción -E para hacer la búsqueda grep para una expresión regular y fijar el tema de búsqueda a la línea de principio de (por ejemplo grep -A 1 -E '^subjectB').

Por último, la salida será ahora consistirá en la línea de asunto y la línea variable que desea. Es posible que desee ocultar la línea de asunto:


  grep -A 1 'subjectB' |grep -v 'subjectB'

Y es posible que desee procesar la línea de variable:


  grep -A 1 'subjectB' |grep -v 'subjectB' |perl -pe 's/ /,/g'

La mejor opción sería modificar la simulación por ordenador para producir una salida rectangular. Suponiendo que usted no puede hacer eso, aquí está uno de los enfoques:

Con el fin de poder utilizar los datos en R, SQL, etc. que necesita para convertirlo de jerárquica a rectangular de una manera u otra. Si ya tiene un programa de análisis que puede convertir todo el archivo en un conjunto de datos rectangular, que son la mayor parte del camino. El siguiente paso es añadir flexibilidad adicional a su programa de análisis, de modo que pueda filtrar los registros de datos no deseados. En lugar de tener un conversor de archivos, tendrá una utilidad de extracción de datos.

El siguiente ejemplo es en Perl, pero se puede hacer lo mismo en Python. La idea general es la de mantener una separación limpia entre (a) de análisis sintáctico, el filtrado de (b), y (c) de salida. De esta manera, usted tiene un entorno flexible, por lo que es fácil de añadir diferentes métodos de filtrado o de salida, dependiendo de sus necesidades de datos-crujido inmediatos. También puede configurar los métodos de filtrado para aceptar parámetros (tanto desde la línea de comandos o un archivo de configuración) para una mayor flexibilidad.

use strict;
use warnings;

read_file($ARGV[0], \&check_record);

sub read_file {
    my ($file_name, $check_record) = @_;
    open(my $file_handle, '<', $file_name) or die $!;
    # A data structure to hold an entire record.
    my $rec = {
        time => '',
        desc => '',
        subj => '',
        name => '',
        vars => [],
    };
    # A code reference to get the next line and do some cleanup.
    my $get_line = sub {
        my $line = <$file_handle>;
        return unless defined $line;
        chomp $line;
        $line =~ s/^\s+//;
        return $line;
    };
    # Start parsing the data file.
    while ( my $line = $get_line->() ){
        if ($line =~ /^time (\w+)/){
            $rec->{time} = $1;
            $rec->{desc} = $get_line->();
        }
        else {
            ($rec->{subj}, $rec->{name}) = $line =~ /(\w+) +(\w+)/;
            $rec->{vars} = [ split / +/, $get_line->() ];

            # OK, we have a complete record. Now invoke our filtering
            # code to decide whether to export record to rectangular format.
            $check_record->($rec);
        }
    }
}

sub check_record {
    my $rec = shift;
    # Just an illustration. You'll want to parameterize this, most likely.
    write_output($rec)
        if  $rec->{subj} eq 'subjectB'
        and $rec->{time} eq 't1'
    ;
}

sub write_output {
    my $rec = shift;
    print join("\t", 
        $rec->{time}, $rec->{subj}, $rec->{name},
        @{$rec->{vars}},
    ), "\n";
}

Si son perezosos y tienen suficiente memoria RAM, entonces me gustaría trabajar en un disco RAM en lugar del sistema de archivos, siempre y cuando los necesita inmediatamente.
No creo que Perl o awk será más rápido que Python si son sólo para recodificar algoritmo actual en un idioma diferente.

awk '/time/{f=0}/subjectB/{f=1;next}f' file
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top