2010-12-01 14 views
16

Ho una lista di datetimes da cui voglio costruire segmenti di tempo. In altre parole, attivare [t0, t1, ... tn] in [(t0,t1),(t1,t2),...,(tn-1, tn)]. L'ho fatto in questo modo:Posso contare sull'ordine di essere conservato in una tupla Python?

# start by sorting list of datetimes 
mdtimes.sort() 
# construct tuples which represent possible start and end dates 

# left edges 
dtg0 = [x for x in mdtimes] 
dtg0.pop() 

# right edges 
dtg1 = [x for x in mdtimes] 
dtg1.reverse() 
dtg1.pop() 
dtg1.sort() 

dtsegs = zip(dtg0,dtg1) 

Domande ...

  1. Posso contare su tn-1 < tn per qualsiasi (tn-1, tn) dopo che li ho creato questo modo? (L'ordine è conservato?)
  2. È buona norma copiare l'elenco originale mdtimes con le descrizioni delle liste? Se non come dovrebbe essere fatto?
  3. Lo scopo per la costruzione di queste tuple è di scorrere su di esse e segmentare un set di dati con tn-1 e tn. È un approccio ragionevole? vale a dire

    datasegment = [x for x in bigdata if ((x['datetime'] > tleft) and (x['datetime'] < tright))] 
    

Grazie

+1

btw: '(x ['datetime']> tleft) e (x ['datetime']

+2

La domanda che non hai t ask: Dato 'x' è ordinato, è' x.reverse(); x.pop(); x.sort() 'una buona idea? Risposta: ** NO **; è orribile; 'x.pop (0)' farà la stessa cosa, e in ogni caso quasi tutte le risposte sono migliori dell'uso del metodo 'pop()'. –

+0

Ho finito per andare con 'dtsegs = zip (mdtimes [:], mdtimes [1:])' – Pete

risposta

13
  1. L'ordine di tupla è quando si inseriscono valori nella tupla. Non verranno ordinati come penso che tu stia chiedendo. zip sarà nuovamente, mantenere l'ordine inserito i valori in

  2. È un metodo accettabile, ma ho 2 suggerimenti alternativi:. Utilizzare il modulo copy, o utilizzare dtg1 = mdtimes[:].

  3. Suoni ragionevoli.

2

Invece di: dtg0 = [x for x in mdtimes], dtg0 = mdtimes[:] farebbe, dal momento che è sufficiente copiare una lista in un altro. Nota: a partire da Python 3.3, puoi semplicemente dire newlist = oldlist.copy()

Per quanto riguarda l'ordine, l'ordine zip è ben definito, e sia le liste che le tuple sono raccolte ordinate, quindi non dovresti avere alcun problema qui.

+1

'list (mdtimes)' è un altro modo per copiare, IMHO il più pulito di loro. list() è un costruttore, quindi crea sempre un nuovo oggetto, anche quando il suo argomento è già un elenco. –

+2

@Beni: è una questione di idiomi e di ciò a cui le persone sono abituate. Alcuni elaborano mentalmente '[:]' come copia di una lista.A proposito, c'è una proposta in corso per aggiungere un metodo 'copia' ad un oggetto lista, quindi quello sopra diventa' mdtimes.copy() '. È discusso in questo numero di Python: http://bugs.python.org/issue10516 –

+0

Cool! Hai scaricato 'list.copy()' e 'list.clear()' in python 3.3. Penso che '.copy()' sia il mio nuovo stile preferito. –

5

È possibile ottenere lo stesso con zip:

>>> l = ["t0", "t1", "t2", "t3", "t4", "t5", "t6"] 
>>> zip(l[::2], l[1::2]) 
[('t0', 't1'), ('t2', 't3'), ('t4', 't5')] 
+0

impressionante ... grazie – Pete

+0

per tenerlo continuo Ho usato 'zip (l [:], l [1:])' – Pete

16

Sia list e tuple sono ordinate.

dtg0, dtg1 = itertools.tee(mdtimes) 
next(dtg0) 
dtsegs = zip(dtg0, dtg1) 
+0

Questo ha qualche vantaggio rispetto al suggerimento implicito di Pawel di 'dtsegs = zip (mdtimes [:], mdtimes [1:])' – Pete

+1

@Pete: non comporta la creazione di 2 elenchi provvisori. –

1

Non sono un esperto, ma non stai quadruplicare i vostri requisiti di memoria copiando la lista e poi fare una nuova lista di coppie prese da due liste? Perché non fare solo quanto segue:

dtsegs = [(dtg0[i], dtg0[i+1]) for i in range(len(dtg0)-1)] 

Non so come "Pythonic" sia, però.

EDIT: In realtà, guardando ciò che è necessario fare con questa lista di tuple, si può solo fare questo [i] e cose [i + 1] direttamente a quel livello e neanche creare questa nuova struttura a tutti. Non so quante date hai a che fare, però - se è un numero piccolo, suppongo che non abbia molta importanza.

Per quello che vale, un paio di altri risponditori qui sembrano fraintendere la tua domanda, anche se non posso commentare i loro post poiché non ho ancora abbastanza reputazione :) La soluzione di Ignacio Vazquez-Abrams sembra il meglio per me, anche se il suo "next (dtg0)" dovrebbe probabilmente essere "next (dtg1)" (?)

+0

Personalmente preferirei avere una struttura separata con i segmenti di data per facilitare la comprensione del codice successivo. Inoltre mi permette di visualizzare i segmenti per assicurarmi che tutto sia OK. – Pete

2

Tornitura (x1, x2, x3, ...) in [(x1, x2), (x2 , x3), ...] si chiama una combinazione a due a due, ed è così comune un modello che la documentazione itertools fornisce una ricetta:

def pairwise(iterable): 
    "s -> (s0,s1), (s1,s2), (s2, s3), ..." 
    a, b = tee(iterable) 
    next(b, None) 
    return izip(a, b) 

for ta, tb in pairwise(mdtimes): 
    .... 
2

Questa è una risposta alla domanda "È un approccio ragionevole?" (che sembra essere stato ignorato da tutti).

Sommario: Si consiglia/necessità di alzare lo sguardo dal fare un thingy coppie di mdtimes al problema che comprende (segmentazione bigdata).

dettaglio:

L'uso desiderato del risultato è espresso come:

datasegment = [x for x in bigdata if ((x['datetime'] > tleft) and (x['datetime'] < tright))] 

che è meglio espresso in:

datasegment = [x for x in bigdata if tleft < x['datetime'] < tright] 

Nota che, come che si distingue, lo farà non includere alcun caso in cui il timestamp è esattamente uguale a uno dei punti limite, quindi cambialo in:

datasegment = [x for x in bigdata if tleft <= x['datetime'] < tright] 

Ma che sta per comparire in un ciclo:

for tleft, tright in dtsegs: 
    datasegment = [x for x in bigdata if tleft <= x['datetime'] < tright] 
    do_something_with(datasegment) 

Ops! Ci vorrà del tempo proporzionale a len(bigdata) * len(dtsegs) ... quali sono probabilmente i valori di len(bigdata) e len(dtsegs)?

Se bigdata è ordinato, ciò che si vuole fare può essere fatto in tempo proporzionale a N, dove N = len(bigdata). Se bigdata non è già ordinato, può essere ordinato in base al tempo proporzionale a N * log(N).

Come si potrebbe fare un'altra domanda ...

E 'anche la pena sottolineare che tutti gli articoli nel bigdata che hanno un timestamp < min (mdtimes) o> = max (mdtimes) non saranno inclusi in qualsiasi segmento di dati ... è intenzionale?

+0

Grazie John ... il chilometraggio varia ma 'bigdata' è nell'ordine dei 10^6 record e ci sono circa 5-10 segmenti utili con circa 10^5 record in ogni segmento. 'bigdata' non è ordinato di per sé ma viene letto da una sequenza alfabetica di file che hanno la data come parte del nome, quindi le parti sono ordinate per data/ora. Sì, alcuni dati vengono omessi intenzionalmente se non rientrano in uno dei segmenti. Il collo di bottiglia temporale finora è la lettura dei file di testo (500 MB per ogni analisi), la creazione dei datet e lo zipping delle colonne di dati selezionate. – Pete

Problemi correlati