• Publicidad

Promedio por columnas

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

Promedio por columnas

Notapor enric73 » 2013-05-30 04:44 @239

Hola compañeros.

Os pido ayuda otra vez. ¿Cómo puedo hacer el promedio de cada columna? La primera fila tiene el nombre de cada columna:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
Azores   Cantabrico  Gran Sol  Vizcaya
1.50     2.00        3.00      3.00
1.75     2.24        3.10      3.20
2.00     2.50        3.30      3.10
1.75     2.40        3.50      3.30
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Estos datos están en un fichero .dat, alturaolas.dat.

El resultado que quiero es
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
Azores     Cantabrico    Gran Sol    Vizcaya
Promedio   Promedio      Promedio    Promedio
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


He visto que se puede hacer con
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. use Statistics::Lite qw(:all);
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
y
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. $mean= mean @data;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
pero no sé cómo hacerlo columna por columna... ¿me podéis ayudar? Gracias

Saludos
enric73
Perlero nuevo
Perlero nuevo
 
Mensajes: 154
Registrado: 2012-03-16 06:27 @311

Publicidad

Re: Promedio por columnas

Notapor explorer » 2013-05-30 08:05 @379

¿Qué delimitador hay entre cada columna? No es el espacio en blanco, porque un titular (Gran Sol) tiene un espacio en blanco dentro de él.

¿Están las columnas en posiciones fijas? ¿O es que hay tabuladores entre las columnas?

Puedes leer el archivo y meterlo en un array bidimensional, y luego hacer operaciones con las columnas.

Si, suponemos, que tomamos un doble espacio en blanco como separador de columnas, este programa saca lo que quieres:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use v5.10;
  3. use autodie;                    # «Es mejor morir que regresar con deshonor» --proverbio Klingon
  4. use Statistics::Lite qw(mean);
  5.  
  6. my @datos;                              # aquí guardamos la matriz
  7.  
  8. open my $DATOS, 'kk.txt';
  9. while (<$DATOS>) {
  10.     chomp;
  11.     my @cols = split /\s{2,}/;          # partimos cada línea, por dos, o más, espacios en blanco
  12.     push @datos, \@cols;                # y guardamos como referencia a un array dentro de otro array
  13. }
  14. close   $DATOS;
  15.  
  16. #use Data::Dumper::Perltidy;
  17. #say Dumper \@datos;                    # esto es lo que tenemos al final
  18. # $VAR1 = [
  19. #    [ 'Azores', 'Cantabrico', 'Gran Sol', 'Vizcaya' ],
  20. #    [ '1.50',   '2.00',       '3.00',     '3.00 ' ],
  21. #    [ '1.75',   '2.24',       '3.10',     '3.20' ],
  22. #    [ '2.00',   '2.50',       '3.30',     '3.10' ],
  23. #    [ '1.75',   '2.40',       '3.50',     '3.30' ]
  24. # ];
  25.  
  26. my @promedios;
  27.  
  28. for my $x ( 0 .. $#{$datos[0]} ) {              # recorremos todas las columnas
  29.     my @columna;
  30.  
  31.     for my $y ( 1 .. $#datos ) {                # recorremos todas las filas, menos la primera
  32.         push @columna, $datos[$y][$x];          # vamos leyendo la columna
  33.     }
  34.  
  35.     push @promedios, mean @columna;             # sacamos la media y la guardamos
  36. }
  37.  
  38. say join "\t", @{ $datos[0] };                  # promedios
  39. say join "\t", @promedios;
  40.  
  41. __END__
  42. Azores  Cantabrico      Gran Sol        Vizcaya
  43. 1.75    2.285   3.225   3.15
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Promedio por columnas

Notapor enric73 » 2013-05-31 13:54 @621

Hola, explorer.

Muchas gracias, lo he probado y va como la seda. Consultas varias sobre el código.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my @cols = split /\s{2,}/;          # partimos cada línea, por dos, o más, espacios en blanco
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
¿¿¿qué quieres decir...??? Por ejemplo la línea
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
Azores   Cantabrico  Gran Sol  Vizcaya
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4
queda de la siguiente manera, ¿separamos las palabras por dos espacios y por una coma?
'Azores', 'Cantabrico', 'Gran Sol', 'Vizcaya'

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. push @datos, \@cols;                # y guardamos como referencia a un array dentro de otro array
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
¿¿¿metemos las líneas dentro de la matriz @datos? ¿y con \ indicamos que estén una debajo de la otra?
# [ 'Azores', 'Cantabrico', 'Gran Sol', 'Vizcaya' ],
# [ '1.50', '2.00', '3.00', '3.00 ' ],
# [ '1.75', '2.24', '3.10', '3.20' ],
# [ '2.00', '2.50', '3.30', '3.10' ],
# [ '1.75', '2.40', '3.50', '3.30' ]
# ];


Gracias
enric73
Perlero nuevo
Perlero nuevo
 
Mensajes: 154
Registrado: 2012-03-16 06:27 @311

Re: Promedio por columnas

Notapor explorer » 2013-05-31 14:59 @666

enric73 escribiste:¿¿¿qué quieres decir...??? ¿separamos las palabras por dos espacios y por una coma?
No, estamos ejecutando la función split(), y ésta coge la línea actual y la parte por el delimitador que le hemos indicado (en este caso, todos los sitios donde haya dos o mas espacios en blanco). El resultado es una lista de elementos, que es almacenada en la parte izquierda de la asignación, en este caso, en el array @cols. Cada elemento de @cols almacena una elemento de cada columna.

Más información en perldoc -f split

enric73 escribiste:¿¿¿metemos las líneas dentro de la matriz @datos? ¿y con \ indicamos que estén una debajo de la otra?
El poner un '\' delante del array es porque queremos obtener una referencia a ese array (algo así como un "puntero" o la "dirección de memoria" donde está almacenado ese array). Esa referencia es la que almacenamos como un elemento más en el array @datos.

Al final, tenemos un array (@datos), en que cada uno de sus elementos es una referencia a otro array. Esto es lo mismo que crear una matriz bidimensional en otros lenguajes que usan punteros de memoria, como en C.

Con el módulo Data::Dumper::Perltidy (o con el incluido Data::Dumper) se puede ver la estructura de ese array.

Por ejemplo, para acceder al tercer elemento del quinto elemento de @datos, escribiríamos

print $datos[4]->[2], "\n";

que podemos abreviar a

print $datos[4][2], "\n";

y ya tiene aspecto de matriz bidimensional.

Más información sobre referencias, en tu propio ordenador en perldoc perlref, y en la Web (traducido al español).

Más información sobre ejemplos de estructuras complejas de datos, en tu propio ordenador en perldoc perllol, y en la Web (traducido al español).
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Promedio por columnas

Notapor enric73 » 2013-06-01 11:09 @506

Gracias por las aclaraciones explorer.

Otra duda: en la siguiente línea del código, donde se recorren todas las columnas del array @datos, ¿qué significa $#{$datos[0]}? ¿Por qué dentro hay un cero?
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. for my $x ( 0 .. $#{$datos[0]} ) {              # recorremos todas las columnas
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Saludos
enric73
Perlero nuevo
Perlero nuevo
 
Mensajes: 154
Registrado: 2012-03-16 06:27 @311

Re: Promedio por columnas

Notapor explorer » 2013-06-01 11:30 @521

En principio, no sabemos cuántas columnas tenemos. Pero podemos saberlo viendo cuántas columnas hay en la primera fila, la de los títulos.

En @datos se almacena un elemento por cada fila del archivo. Ese elemento es una referencia a un array, cuyos elementos son las distintas columnas de esa fila.

Entonces, en $datos[0] (primer elemento de @datos), tenemos una referencia al array que almacena los valores de la primera fila, la de los títulos.

Lo que queremos es tener una variable que recorra los índices de las columnas. Debe comenzar en 0 y debe seguir hasta el índice de la última columna.

Para saber qué valor tiene el índice del último elemento, usamos la notación $#. Así, de un array @array, el valor del índice del último elemento será $#array.

Esto lo aplicamos al array referenciado por $datos[0]: Si $datos[0] es una referencia a un array, @{$datos[0]} es el propio array, así que, entonces, $#{$datos[0]} es el valor del último índice del array.

Solo queda usar ese valor para ponerlo en un operador rango: 0 .. $#{$datos[0]}, con lo que el bucle for() está, efectivamente, recorriendo los índices de los elementos del array referenciado por el primer elemento de @datos.

O sea... que podemos recorrer los nombres de los títulos del archivo leído.

Otra forma de escribirlo:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. for(my $x = 0; $x < @{$datos[0]}; $x++ ) {
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Otra forma, más descriptiva:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $fila_titulares = $datos[0];
  2. my @titulares      = @$fila_titulares;                 # sacamos una copia de los titulares
  3. for my $x (0 .. $#titulares) {
  4.     my $titular= $titulares[$x];
  5.     ...;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Más información y ejemplos en perllol.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Promedio por columnas

Notapor enric73 » 2013-06-04 15:54 @704

Hola explorer,

muchas gracias por la detallada explicación, ahora lo he entendido, gracias.

Saludos.
enric73
Perlero nuevo
Perlero nuevo
 
Mensajes: 154
Registrado: 2012-03-16 06:27 @311

Re: Promedio por columnas

Notapor enric73 » 2013-06-08 06:04 @294

Hola explorer,

para redondear el promedio de las columnas a un decimal, lo he programado de esta manera

Donde antes había
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #push @promedios,  mean @columna;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Ahora lo he cambiado por
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $avg = mean (@columna);
  2. $avg = sprintf "%.1f", $avg;
  3. push @promedios,  mean $avg;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


¿Es correcta la manera, o es preferible otra? El resultado me sale bien.
Gracias por los consejos.

Saludos
enric73
Perlero nuevo
Perlero nuevo
 
Mensajes: 154
Registrado: 2012-03-16 06:27 @311

Re: Promedio por columnas

Notapor explorer » 2013-06-08 06:13 @300

El resultado sale bien, desde luego... pero, fíjate, en la última línea, que estás calculando la media de un solo valor, por lo que obtenemos el mismo valor (media de una número = suma de un número / 1 = el mismo número).

Mejor si lo quitas.

Algo así:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $avg = mean (@columna);
  2. $avg = sprintf "%.1f", $avg;
  3. push @promedios,  $avg;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

que puede quedar simplificado en
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. push @promedios, sprintf "%.1f", mean @columna;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
(En Perl se pueden quitar los paréntesis de una función siempre que no afecten a la lógica del resto de la sentencia).
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Promedio por columnas

Notapor enric73 » 2013-06-08 07:00 @333

Hola, explorer.

Gracias, es verdad, me he dejado el mean() en la última línea, pero mejor, ¡todo agrupadito en una sola!

Muchas gracias.
enric73
Perlero nuevo
Perlero nuevo
 
Mensajes: 154
Registrado: 2012-03-16 06:27 @311

Siguiente

Volver a Básico

¿Quién está conectado?

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