Pagina 1 di 1

[Python] Manipolare colonne e nome di un file.dat

Inviato: martedì 15 aprile 2014, 12:21
da vaeVictis
Ciao a tutti.
Come ho accennato nel titolo, mi capita spesso di dover manipolare il contenuto e il nome file.dat.

Per manipolazione del contenuto intendo quanto segue.
Il file.dat contiene un numero arbitrario di campi (che in quanto segue indico con $1, $2, ... $N) divisi da un separatore (generalmente uso il tab).
Mi trovo spesso a rielaborare questo tipo di contenuto, nel senso che (riga per riga) devo manipolare matematicamente i dati contenuti nelle varie colonne, con funzioni generiche, e riscriverli in un file che, a priori, contenga un numero di colonne anche differente dal numero di colonne da cui sono partito.
Per essere meno generici e più "matematici", devo prendere queste $1, $2, ... , $N e produrre un file con abbia come i-esima colonna una funzione nota solo al momento in cui lancio il programma.
Vorrei pertanto qualche suggerimento su come impostare la funzione print (python 3.x) in modo che "capisca" a run time le varie funzioni con cui rielaborare le colonne del file.dat e scrivere poi l'output.
Un'idea la ho, ma è un po' troppo complessa, quindi evito di scriverla per non confondere chi volesse aiutarmi.

Per manipolazione del nome di file.dat, intendo che il file di output avrà un nome ovviamente diverso da quello iniziale, ma che spesso è una "manipolazione" di quest'ultimo, in cui semplicemente aggiungo "qualcosa" che faccia capire il tipo di elaborazione fatta sulle colonne del file di partenza.
Anche per questo problema, avrei bisogno di qualche consiglio per muovermi in modo oculato (e come prima ho in mente alcune soluzioni che però sono un po' "complesse").

Vi ringrazio in anticipo per l'attenzione e per gli aiuti :ciao:

Re: [Python] Manipolare colonne e nome di un file.dat

Inviato: giovedì 17 aprile 2014, 8:59
da Nexol
vaeVictis ha scritto:Il file.dat contiene un numero arbitrario di campi (che in quanto segue indico con $1, $2, ... $N) divisi da un separatore (generalmente uso il tab).
Un file csv. Se vuoi semplificarti la vita rivolgiti al modulo csv di Python.
vaeVictis ha scritto:e produrre un file con abbia come i-esima colonna una funzione nota solo al momento in cui lancio il programma.
Forse volevi dire "e produrre un file che abbia come i-esima colonna il risultato dell'elaborazione della colonna originale tramite una funzione nota solo al momento in cui lancio il programma.".
vaeVictis ha scritto:Vorrei pertanto qualche suggerimento su come impostare la funzione print (python 3.x) in modo che "capisca" a run time le varie funzioni con cui rielaborare le colonne del file.dat e scrivere poi l'output.
Print, o write? Vuoi stampare, o scrivere su un file?
vaeVictis ha scritto:Un'idea la ho, ma è un po' troppo complessa, quindi evito di scriverla per non confondere chi volesse aiutarmi.
Magari sei già sulla buona strada e si tratta solo di semplificare, se riporti la tua idea anche solo in pseudocodice, ci si può capire di più.

Per manipolazione del nome di file.dat, intendo che il file di output avrà un nome ovviamente diverso da quello iniziale, ma che spesso è una "manipolazione" di quest'ultimo, in cui semplicemente aggiungo "qualcosa" che faccia capire il tipo di elaborazione fatta sulle colonne del file di partenza.
Anche per questo problema, avrei bisogno di qualche consiglio per muovermi in modo oculato (e come prima ho in mente alcune soluzioni che però sono un po' "complesse").[/quote]

Idem come sopra, se le riporti magari si "semplificano".

Re: [Python] Manipolare colonne e nome di un file.dat

Inviato: venerdì 18 aprile 2014, 17:46
da vaeVictis
Ciao, grazie per l'interessamento.

Allora, in questi giorni ho dovuto lavorare anche su altre cose, ma, pensando a questo mio problema, mi sono reso conto che sto cercando di scrivere in Python un programma per la soluzione di un problema che si affronta facilmente con awk o altre utility del genere. E usando awk in realtà si risolve anche il problema relativo al nome del file, usando i barbatrucchi di bash.
Detto questo, mi spiego meglio, perché in effetti in alcuni punti su cui poni l'attenzione avrei potuto/dovuto essere più chiaro.
Per non confondere le cose, cerchiamo prima di risolvere la parte relativa all'elaborazione delle colonne del file di input :)
Nella spiegazione (lo scrivo a posteriori, dopo aver scritto tutto) sarò un po' prolisso... quindi ho evidenziato in nero le frasi "salienti".
A fine messaggio, c'è il punto riassuntivo che può essere letto anche saltando tutta la parte precedente :)

Elaborazione del file
Un file csv. Se vuoi semplificarti la vita rivolgiti al modulo csv di Python.
L'acquisizione delle righe del file non è un problema e per quanto segue possiamo ignorarla o darla per risolta.
Lo ho già del tutto risolta, infatti, usando le funzioni appositamente pensate nel modulo numpy, anche perché i miei file contengono valori numerici.
Pertanto possiamo anche ridurre il problema alla elaborazione degli elementi di una singola lista di Python, invece che pensare alle righe del file.
Quindi, da ora in poi, pensiamo di avere a che fare con l'elaborazione di una singola lista di numeri e che ogni elemento della lista corrisponda ad uno dei campi del file di input.
Forse volevi dire "e produrre un file che abbia come i-esima colonna il risultato dell'elaborazione della colonna originale tramite una funzione nota solo al momento in cui lancio il programma.".
Sì, mi sono espresso male.
Intendevo dire che a partire dagli elementi della lista iniziale di dimensione N (che per quanto detto precedentemente contiene gli N campi della riga letta), io devo produrre un'altra lista di dimensione M, i cui elementi sono il risultato dell'elaborazione degli N elementi di partenza.
Pertanto, parto con una lista di N elementi/campi e devo ottenere una lista con M elementi, in cui M ed N non sono uguali a priori e i singoli elementi della lista finale sono il prodotto di una generica elaborazione di tutti gli elementi della lista di partenza (all'atto pratico non sarà così, in quanto elaborerò solo una parte degli elementi iniziali, ma per non perdere generalità devo impostare la cosa in questo modo).

Print, o write? Vuoi stampare, o scrivere su un file?
Non fa molta differenza, almeno credo.
Nel senso che print (di Python 3.x) permette la stampa sia su std output, sia su file.
Tra i due, opterei per la funzione print, perché mi sembra più versatile per il mio caso.

E ora spiego meglio che intendo e come avevo pensato io la soluzione.
Come spiegato, la lista di dimensione M è quella che poi devo andare a stampare sul file di output.
Posso pertanto pensare di "produrla" e poi passarla a print come primo parametro, fargliela "spacchettare" e stamparla con un separatore e un fine riga appropriati, su standard output o su file, con una chiamata di questo tipo
(molto semplificata)

Codice: Seleziona tutto

>>> from __future__ import print_function
>>> foo = [0,1,2,3,4,5]
>>> print(*foo)
0 1 2 3 4 5
>>> print(*foo, sep = '-')
0-1-2-3-4-5
>>> print(*foo, sep = '\t')
0	1	2	3	4	5
Il problema si riduce pertanto a come far capire al programma quali elementi della lista iniziale debba elaborare e in che modo debba elaborarli.
Per semplificare ancora di più, facciamo "finta" che la lista finale abbia un solo elemento, e quindi M = 1.
Una volta risolto questo problema, infatti, si tratta solo di generalizzare il tutto, istruendo il programma


Punto riassuntivo
Visto quanto argomentato precedentemente, il problema si riduce a come introdurre nel seguente codice la possibilità di passare tramite argparse una funzione che indichi l'elaborazione degli elementi della lista (che qui ho passato come parametro, ma che in "futuro" sarà acquisita dalla lettura delle righe del file).

Codice: Seleziona tutto

#! /usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import print_function
import argparse

parser = argparse.ArgumentParser()
parser.add_argument("--lista", nargs='+', type=float, default=[1.,2.,3.,4.])
parser.add_argument("--funzione")

args = parser.parse_args()
Devo quindi far capire al programma che tipo di elaborazione della lista voglio fare... per esempio dicendogli, calcolami il seno del primo elemento più il logaritmo al quadrato del terzo elemento...
Ma la cosa deve essere generica al massimo.
Con lo stesso programma devo poter indicare il calcolo di qualsiasi combinazione matematica di tutte (o parte) le componenti della lista.

Spero di aver fatto un po' più di chiarezza :ciao:

Re: [Python] Manipolare colonne e nome di un file.dat

Inviato: venerdì 18 aprile 2014, 19:08
da crap0101
in pratica hai bisogno di una o più factory che, in base a certi parametri ti costruiscono e restituiscono un qualche oggetto callable a cui passare i dati per l'elaborazione vera... per fare si fà, non so quanto possa essere generico (nel senso di trovare un trade-off tra genericità e complessità di scrittura e uso); comunque, hai presente no?

Re: [Python] Manipolare colonne e nome di un file.dat

Inviato: domenica 20 aprile 2014, 2:48
da vaeVictis
Grazie per l'interessamento crap0101 :)
Allora... cosa è una factory? Come ti avevo accennato in un'altra discussione (morta sul nascere :) ) sto studiando i vari design pattern per la creazione di oggetti... ma non sto capendo a cosa ti riferisci.

Sempre premettendo che il problema l'ho risolto con awk e che ora questo programma è solo uno "sfizio", in pratica mi serve di capire come poter passare (in stile awk) una funzione al programma e fare in modo che il programma la "esegua".
Intendo dire che io riesca a passare una funzione che indichi al programma come deve elaborare una lista di numeri float.
Io semplicemente scrivo una cosa del tipo:

Codice: Seleziona tutto

(log($1))^2 - sin($2)
e il programma capisce che, su una data lista, lui deve fare il la differenza tra il quadrato del logaritmo del primo campo e il seno del secondo campo.
E, ovviamente, deve poter capire le "altre possibili combinazioni" :)

Re: [Python] Manipolare colonne e nome di un file.dat

Inviato: domenica 20 aprile 2014, 19:44
da Claudio_F
Forse non ho capito il problema, o forse ha una soluzione banale, questo ha senso?

Codice: Seleziona tutto

from math import log, sin
#------------------------------------------------------------------------------
def elabora(*args):
    return args[0]( *(args[1:]) )
#------------------------------------------------------------------------------
argomenti = lambda p1, p2: log(p1)**2 - sin(p2),  50.6,  3.141
print(elabora(*argomenti))
Ho scritto una lambda per concisione, ma ovviamente il primo elemento della tupla 'argomenti' può essere il nome di qualsiasi altra funzione.

Re: [Python] Manipolare colonne e nome di un file.dat

Inviato: mercoledì 23 aprile 2014, 13:06
da vaeVictis
Non ho avuto modo di rispondere prima :)
Dunque, sì, Claudio_F, il problema è abbastanza vicino a come lo hai compreso e quanto hai gentilmente postato ha senso :)

Il punti da risolvere per poter adattare il tuo esempio al mio problema sono (per come la vedo io ora) due:
1) gli elementi, che poi saranno oggetto dell'elaborazione specificata dalla funzione, devo prenderli da "dentro" una lista, magari indicandoli con il loro indice;
2) devo inoltre poter passare una generica funzione da riga di comando, magari come parametro letto dal modulo argparse.
In questa funzione devo poter indicare quali siano i singoli elementi della lista da elaborare. Per esempio devo poter scrivere log($2) - sin($5), indicando che voglio il logaritmo del secondo elemento della lista meno il seno del quinto elemento della lista. Ma devo poter anche indicare un'altra funzione di altri parametri... per esempio ($8)^2 - arctan($1) + exp($3) se voglio il quadrato dell'ottavo elemento della lista - l'arcotangente del primo elemento + l'esponenziale del terzo elemento... e così via.
E questa funzione la dovrei poter passare da riga di comando :)

Ti cito la parte di un messaggio precedente in cui c'è anche una bozza di codice:
vaeVictis [url=http://forum.ubuntu-it.org/viewtopic.php?p=4565508#p4565508][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto: [...]
Punto riassuntivo
Visto quanto argomentato precedentemente, il problema si riduce a come introdurre nel seguente codice la possibilità di passare tramite argparse una funzione che indichi l'elaborazione degli elementi della lista (che qui ho passato come parametro, ma che in "futuro" sarà acquisita dalla lettura delle righe del file).1

Codice: Seleziona tutto

#! /usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import print_function
import argparse

parser = argparse.ArgumentParser()
parser.add_argument("--lista", nargs='+', type=float, default=[1.,2.,3.,4.])
parser.add_argument("--funzione")

args = parser.parse_args()
Devo quindi far capire al programma che tipo di elaborazione della lista voglio fare... per esempio dicendogli, calcolami il seno del primo elemento più il logaritmo al quadrato del terzo elemento...
Ma la cosa deve essere generica al massimo.
Con lo stesso programma devo poter indicare il calcolo di qualsiasi combinazione matematica di tutte (o parte) le componenti della lista.

Spero di aver fatto un po' più di chiarezza :ciao:


Sinceramente io non saprei proprio come fare... e sto sommerso da talmente tanta roba da fare che non riesco neanche tanto a concentrarmi sul problema.

Se non sono stato abbastanza chiaro, chiedi pure.
E grazie ancora per l'interessamento.
:ciao:

Re: [Python] Manipolare colonne e nome di un file.dat

Inviato: venerdì 25 aprile 2014, 21:15
da crap0101
io non sono sicuro di aver capito bene, puoi fare un esempio con una linea di comando per awk (che scrivevi aver risolto con quello)?

btw, se ho inteso bene, per "dire al programma" quali funzioni utilizzare e come nello stile dell'esempio di awk

Codice: Seleziona tutto

(log($1))^2 - sin($2)
puoi fare la stessa cosa anche con python (il codice immagino sia un argomento passato al programma) e poi ci vai brutalmente di eval e/o compile etc, altrimenti devi costruire un miniparser per parsare quelle espressioni.