• Publicidad

Salida en formato matricial

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Salida en formato matricial

Notapor jorcaes » 2007-05-14 14:00 @625

Hola a todos,

En primer lugar tengo que comentar que soy un usuario principiante desarrollando aplicaciones con lenguaje Perl, por ello espero que entre todos podáis ayudarme en este problema que se me ha planteado.

Por una parte tengo una pequeña aplicación que lo que me realiza es una búsqueda de aquellas combinaciones de palabras dos a dos, existentes en 140 ficheros de texto a partir de un listado de 1781 palabras.

A continuación os pongo el código:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!perl
# Muestra las combinaciones de palabras del listado de la sección __DATA__ entre las palabras de los textos
# ubicados en la ruta <C:\\Textos\\*.txt>
# Muestra el resultado por fichero

use warnings;
use strict;

#Leemos la lista de palabras keywords
my %keywords;
while ( <DATA> ){
        chomp;
        $keywords{ lc($_) }=1;
}

#Para cada fichero...
foreach my $nombre_fichero ( <C:\\Textos\\*.txt> ){
        #Nos leemos todo el fichero y lo dividimos en palabras
        my @palabras;
        {
                my $fichero=do{ local $/; open FH, "<$nombre_fichero"; <FH> };
                @palabras = $fichero =~ /(\b[^\W_\d][\w'-]+\b)/g;
        }

        #print "Número de palabras del fichero $nombre_fichero: ", scalar @palabras,"\n";

        #Para todas las palabras del fichero
        my %combinaciones;
        my $palabra;
        my $palabra_anterior = '';
        foreach my $palabra_org ( @palabras ) {
                $palabra = lc($palabra_org);
                if( $keywords{$palabra} && $keywords{$palabra_anterior} ) {
                        $combinaciones{"$palabra_anterior|$palabra"}++;
                }
                $palabra_anterior = $palabra;
        }

        #Sacamos el resultado, si lo hay
        if ( keys %combinaciones ) {
                print "Fichero $nombre_fichero:\n";
                foreach my $combinacion ( sort { $combinaciones{$b} <=> $combinaciones{$a} } keys %combinaciones ) {
                        print "\t$combinacion :", $combinaciones{$combinacion},"\n";
                }
        }
}
__DATA__
CATALYST
REACTION
CATALYSTS
ZEOLITE
BETA
ZEOLITES

Ésta es la lista de 1781 palabras
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4


El resultado de este script es el siguiente:

Código: Seleccionar todo
Fichero C:\Textos\BioTechVol77-2(2001).txt:
   data|base :7
   organic|wastes :6
   solid|organic :4
   data|bases :2
   particle|size :2
   high|quality :2
   high|air :1
   pore|space :1
Fichero C:\Textos\BioTechVol82-3(2002).txt:
   data|base: 5
   cation|exchange :4
   calcium|magnesium :3
   peat|source :3
   carbon|nitrogen :2
   processing|method :2
   nitrogen|calcium :2
   nitrogen|ratio :2
   material|control :1
   …

Ahora viene mi problema, me gustaría representar la salida de ese script en un formato matricial, y no sé si desde un script en Perl puedo depositar el resultado una hoja de cálculo Excel, por ejemplo.

El formato de la matriz debe ser el siguiente:

Imagen

Mi pregunta es si se puede dirigir la salida del script a un Excel por ejemplo, para que saque la salida en forma de matriz y cuáles deberían ser las modificaciones a realizar.

¡Espero sus aportaciones! ¡Muchas gracias!
jorcaes
Perlero nuevo
Perlero nuevo
 
Mensajes: 26
Registrado: 2006-07-12 02:35 @149

Publicidad

Notapor explorer » 2007-05-14 15:21 @681

Jeje... esa aplicación es conocida.

Para la salida matricial, existen módulos tanto para sacarlo en modo texto como Excel. Yo, de hecho, lo uso casi todos los días, los módulos Spreadsheet::WriteExcel y Win32::OLE.

Si vas a trabajar en un sistema donde no esté instalado la aplicación Excel, deberás usar el primer módulo. El segundo es recomendable usarlo si tienes una licencia de Excel funcionando en tu máquina, además de disponer de más opciones a la hora de escribir en hojas Excel. Pero el primero es perfecto si lo vas a hacer en Unix/Linux o no estarás seguro de que en el futuro exista un Excel en la máquina.

Hay otros módulos especializados en sacar datos de forma tabular, como Data::Tabular::Dumper::Excel, pero es mejor usar el método de ir celda a celda, porque la puedes personalizar mucho más.

Si quieres hacerlo en modo texto, aquí tienes dos módulos muy interesantes: Text::Table y Text::TabularDisplay, pero hay más.

A la hora de sacar los resultados, si eliges un módulo como Win32::OLE o SpreadSheet::WriteExcel, puedes ir rellenando la tabla a medida que vas obteniendo los resultados: vas colocando en la primera columna los pares de palabras, pero deberás recordar (en otro hash, por ejemplo) en qué línea has puesto cada par. Luego, como el bucle principal es por ficheros, debes llevar una variable que haga de índice de columna dentro de la tabla, una por fichero.

Algo así:
Código: Seleccionar todo
$fila = 1;
$columna = 0;
Bucle de ficheros
  $columna++;
  Ponemos el titular "Documento$columna" en la posición (0,$columna)
  Buscamos las combinaciones de palabras
  Bucle combinaciones
    Si la combinación no tiene índice de fila asignada, le damos una:
       if ( ! $fila{ $combinacion } ) {
           $fila{ $combinacion } = $fila;
           $fila++;  # siguiente línea para la siguiente combinación
       }
    Pintamos el valor de las $combinaciones{$combinacion} en la celda ($fila{$combinacion},$columna)
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor jorcaes » 2007-05-14 15:31 @688

Si, después de mucho tiempo, he decidido retomar este proyecto en Perl y por ello recurro a este magnífico foro.

Explorer, muchas gracias por responder tan rápidamente. En cuanto tenga algo de tiempo, me pongo con esto último que me comentas.

Muchas gracias de nuevo!
jorcaes
Perlero nuevo
Perlero nuevo
 
Mensajes: 26
Registrado: 2006-07-12 02:35 @149

Notapor jorcaes » 2007-07-23 10:06 @463

Hola de nuevo, he decidido retomar este proyecto que tenía abandonado y llevo un par de días dándole vueltas a este código y a las recomendaciones de tu última respuesta, pero no consigo saber dónde ubicar correctamente la siguiente parte:

Código: Seleccionar todo
Bucle combinaciones
    Si la combinación no tiene índice de fila asignada, le damos una:
       if ( ! $fila{ $combinacion } ) {
           $fila{ $combinacion } = $fila;
           $fila++;  # siguiente línea para la siguiente combinación
       }
    Pintamos el valor de las $combinaciones{$combinacion} en la celda ($fila{$combinacion},$columna)


El código que tengo hasta el momento es el siguiente:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
use Win32::OLE;

# use existing instance if Excel is already running
eval {$ex = Win32::OLE->GetActiveObject('Excel.Application')};
die "Excel not installed" if $@;
unless (defined $ex) {
$ex = Win32::OLE->new('Excel.Application', sub {$_[0]->Quit;})
        or die "Oops, cannot start Excel";
}

#Leemos la lista de palabras keywords
my %keywords;
while ( <DATA> ){
        chomp;
        $keywords{ lc($_) }=1;
}

# get a new workbook
$book = $ex->Workbooks->Add;
# nos ubicamos en la primera hoja sheet
$sheet = $book->Worksheets(1);

$fila = 3;
$columna = 0;

#Para cada fichero...
foreach my $nombre_fichero ( <C:\\Textos\\*.txt> ){
        $columna++;
        #Nos leemos todo el fichero y lo dividimos en palabras
        my @palabras;
        {
                my $fichero=do { local $/; open FH, "<$nombre_fichero"; <FH> };
                @palabras = $fichero =~ /(\b[^\W_\d][\w'-]+\b)/g;
        }

        $sheet->Cells(1,$columna)->{Value} = "$columna";
        $sheet->Cells(2,$columna)->{Value} = "$nombre_fichero";
        #print "Número de palabras del fichero $nombre_fichero: ", scalar @palabras,"\n";

        #Para todas las palabras del fichero
        my %combinaciones;
        my $palabra;
        my $palabra_anterior = '';
        foreach my $palabra_org ( @palabras ) {
                $palabra = lc($palabra_org);
                if( $keywords{$palabra} && $keywords{$palabra_anterior} ) {
                        $combinaciones{"$palabra_anterior|$palabra"}++;
                }
                $palabra_anterior = $palabra;
        }

        #Sacamos el resultado, si lo hay
        if ( keys %combinaciones ) {
                print "Fichero $nombre_fichero:\n";
                foreach my $combinacion ( sort { $combinaciones{$b} <=> $combinaciones{$a} } keys %combinaciones ) {
                        print "\t$combinacion :", $combinaciones{$combinacion},"\n";
                }
        }
       
}
# save and exit
        $book->SaveAs( 'C:\ingles.xls' );
        undef $book;
        undef $ex;
__DATA__
CATALYST
REACTION
CATALYSTS
ZEOLITE
BETA
ZEOLITES
ACID
CATALYTIC
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Si alguien me pudiera echar una mano con la última parte le estaría muy agradecido.

¡Un saludo!
jorcaes
Perlero nuevo
Perlero nuevo
 
Mensajes: 26
Registrado: 2006-07-12 02:35 @149

Notapor explorer » 2007-07-23 17:46 @782

Pues... aparte de lo indicado... sólo falta agregar una variable contador, dentro del bucle de ficheros, para saber la columna en la que hay que pintar los valores.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor jorcaes » 2007-07-24 05:49 @284

No entiendo tu último mensaje. Aparte de lo indicado, ¿dónde?

Por otra parte, ¿el contador dónde debería ir exactamente?

¡Un saludo!
jorcaes
Perlero nuevo
Perlero nuevo
 
Mensajes: 26
Registrado: 2006-07-12 02:35 @149

Notapor explorer » 2007-07-24 06:37 @318

Lo indicado se refiere al trozo de código que te indiqué en otra respuesta, más arriba. Hay que integrarla en lugar del bucle que pinta las combinaciones en pantalla, y trasladarla a posiciones de celda. La combinación indicará qué fila hay que usar y el índice de fichero leído, la columna.

El contador de fichero leído tienes que incrementarle entonces dentro del bucle de ficheros, el principal.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor jorcaes » 2007-07-25 05:17 @261

Hola de nuevo, he estado modificando la parte final del código y actualmente lo que tengo es lo siguiente:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#Sacamos el resultado, si lo hay
        if ( keys %combinaciones ) {
                foreach my $combinacion ( sort { $combinaciones{$b} <=> $combinaciones{$a} } keys %combinaciones ) {
                        $sheet->Cells($fila,1)->{Value} = "$combinacion";
                        $sheet->Cells($fila,$columna)->{Value} = "$combinaciones{$combinacion}";
                        $fila++;
                }
        }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Lo que obtengo con este código es un archivo Excel como describo a continuación:

En toda la primera fila, en cada una de sus columnas, el nombre del fichero. En la primera columna, y para cada uno de los ficheros, las combinaciones dos a dos a razón de la lista de keywords. En cada una de las casillas correspondientes, el número de veces que aparece dicha combinación.

Ahora bien, algunas combinaciones aparecen varias veces en varios ficheros, esto no debería ocurrir, ¿cómo debería modificar el código para que se evitaran las repeticiones?

Por otra parte, también me gustaría mostrar la información ordenada de mayor frecuencia de aparición de combinaciones a menor. ¿Cómo debería hacerlo?

Creo que ya me queda poco para completar el pequeño script.

Un saludo y gracias por la colaboración, sin ustedes no podría avanzar en este proyecto que tanto me trae de cabeza.
jorcaes
Perlero nuevo
Perlero nuevo
 
Mensajes: 26
Registrado: 2006-07-12 02:35 @149

Notapor jorcaes » 2007-07-25 10:17 @470

Ya he conseguido lo que quería:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#Sacamos el resultado, si lo hay
        if ( keys %combinaciones ) {
                foreach my $combinacion ( sort { $combinaciones{$b} <=> $combinaciones{$a} } keys %combinaciones ) {
                        if (! $fila { $combinacion} ) {
                                $fila {$combinacion}=$fila;
                                $sheet->Cells($fila,1)->{Value} = "$combinacion";
                                $fila++;
                        }
                        $sheet->Cells($fila{$combinacion},$columna)->{Value} = "$combinaciones{$combinacion}";
                }
        }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Muchas gracias!
jorcaes
Perlero nuevo
Perlero nuevo
 
Mensajes: 26
Registrado: 2006-07-12 02:35 @149

Otro tipo de salida matricial

Notapor jorcaes » 2007-09-10 10:53 @495

Hola a todos de nuevo, parece que este proyecto no se acaba nunca! Os comento que ahora se me ha planteado la necesidad de mostrar los resultados de una forma, un tanto diferente. Empecemos:

1) Matriz de palabras.
La siguiente matriz debe mostrar las combinaciones de palabras de la siguiente manera:

Imagen

Para ello, se tienen que buscar las combinaciones en cada uno de los ficheros e ir sumando y almacenando las combinaciones en el correspondiente Excel.


2) Matriz de ubicación.
Todos y cada uno de los textos tienen todo su contenido etiquetado con unos tags como: <tit> título </tit>, <en> Encabezado </en>, pues bien, debo disponer una matriz de la siguiente manera:

En la columna de la izquierda están todas las palabras de la lista de keywords, pero en el encabezado de la tabla están las partes que se encuentran delimitadas por las etiquetas. Se debe buscar cada una de las palabras, observar en qué sección del texto se encuentra con las etiquetas e ir sumando las apariciones, además de poder encontrarse en diferentes secciones.

Imagen


3) Matriz múltiple.
La última matriz a representar parte de una lista de combinaciones (de tres palabras, de cuatro palabras, etc.) y se trata de buscar la frecuencia de aparición en cada uno de los documentos.

Imagen

Espero que puedan ofrecerme alguna ayuda como lo han estado haciendo hasta ahora. Sin ustedes no podría seguir avanzando en estos pequeños desarrollos que se me presentan.

Muchas gracias de antemano!
jorcaes
Perlero nuevo
Perlero nuevo
 
Mensajes: 26
Registrado: 2006-07-12 02:35 @149

Siguiente

Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 0 invitados