2010-12-01 12 views
16

Tengo una lista de fechas a partir de las cuales quiero construir segmentos de tiempo. En otras palabras, gire [t0, t1, ... tn] en [(t0,t1),(t1,t2),...,(tn-1, tn)]. Yo he hecho de esta manera:¿Puedo contar con que se conserve el orden en una tupla de 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) 

Preguntas ...

  1. ¿Puedo contar con tn-1 < tn para cualquier (tn-1, tn) después de que les he creado este ¿camino? (¿Se conserva el pedido?)
  2. ¿Es una buena práctica copiar la lista original mdtimes con listas de comprensión? Si no, ¿cómo debería hacerse?
  3. El propósito de la construcción de estas tuplas es iterar sobre ellas y segmentar un conjunto de datos con tn-1 y tn. ¿Es este un enfoque razonable? es decir,

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

Gracias

+1

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

+2

La pregunta que no hiciste t ask: Dado que 'x' está ordenado, es' x.reverse(); x.pop(); x.sort() 'una buena idea? Respuesta: ** NO **; es horrible 'x.pop (0)' hará lo mismo, y en cualquier caso, casi todas las respuestas son mejores que usar el método 'pop()'. –

+0

Terminé yendo con 'dtsegs = zip (mdtimes [:], mdtimes [1:])' – Pete

Respuesta

13
  1. El orden de un tuplo es cuando inserta valores en la tupla. No van a ser ordenados como creo que estás preguntando. zip será otra vez, mantener el orden que ha insertado en los valores

  2. Es un método aceptable, pero tengo 2 sugerencias alternativas:. Usar el módulo copy, o utilizar dtg1 = mdtimes[:].

  3. Suena razonable.

2

En lugar de: dtg0 = [x for x in mdtimes], dtg0 = mdtimes[:] harían, ya que sólo tienes que copiar una lista en otra. NOTA: A partir de Python 3.3, se puede decir simplemente newlist = oldlist.copy()

cuanto a orden, zip 's orden está bien definido, y las dos listas y tuplas están clasificadas colecciones, por lo que no debería tener problemas aquí.

+1

'list (mdtimes)' es otra forma de copiar, en mi humilde opinión, el más limpio de todos. list() es un constructor, por lo que siempre crea un nuevo objeto, incluso cuando su argumento ya es una lista. –

+2

@Beni: se trata de expresiones idiomáticas y de lo que la gente está acostumbrada. Algunos mentalmente procesan '[:]' como copiar una lista.Por cierto, hay una propuesta en curso para agregar un método 'copy' a un objeto list, por lo que lo anterior se convierte en' mdtimes.copy() '. Se discute en este problema de Python: http://bugs.python.org/issue10516 –

+0

¡Genial! Has aterrizado 'list.copy()' y 'list.clear()' en python 3.3. Creo que '.copy()' es mi nuevo estilo favorito. –

5

Usted puede lograr lo mismo con zip:

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

impresionante ... gracias – Pete

+0

para mantenerlo continuo He usado 'zip (l [:], l [1:])' – Pete

16

Tanto listtuple y están clasificadas.

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

¿Esto tiene alguna ventaja sobre la sugerencia implícita de Pawel de 'dtsegs = zip (mdtimes [:], mdtimes [1:])' – Pete

+1

@Pete: no implica la creación de 2 listas temporales. –

1

No soy un experto, pero no se le cuadruplicar sus requisitos de memoria mediante la copia de la lista y luego hacer una nueva lista de pares tomado de dos listas? ¿Por qué no simplemente hacer lo siguiente:

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

No sé cómo "Pythonic" eso es, sin embargo.

EDITAR: En realidad, mirando lo que tiene que hacer con esta lista de tuplas, podría hacer esto [i] y [i + 1] directamente en ese nivel y ni siquiera crear esta nueva estructura. Sin embargo, no sé con cuántas fechas estás lidiando, si se trata de un número pequeño, supongo que realmente no importa.

Por lo que sea, algunos de los otros que responden aquí parecen estar malinterpretando su pregunta, aunque no puedo comentar sobre sus publicaciones ya que no tengo suficiente reputación todavía :) La solución de Ignacio Vazquez-Abrams parece ser mejor para mí, aunque su "próximo (dtg0)" probablemente debería ser "next (dtg1)" (?)

+0

Personalmente, preferiría tener una estructura separada con los segmentos de fecha para que el siguiente código sea más fácil de entender. También me permite ver los segmentos para asegurarme de que todo esté bien. – Pete

2

Giro (x1, x2, x3, ...) en [(x1, x2), (x2 , x3), ...] que se llama una combinación de dos a dos, y es por lo común un patrón que la documentación itertools ofrece una receta:

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

Esta es una respuesta a la pregunta "¿Es este un enfoque razonable?" (que parece haber sido ignorado por todos).

Resumen: Es posible que desee/necesidad de levantar la mirada de hacer una cosita pares de mdtimes al problema que abarca (segmentar bigdata).

Detalle:

El uso deseado del resultado se expresa como:

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

que está mejor expresado como:

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

Tenga en cuenta que como que destaca, lo hará no incluya ningún caso en el que la marca de tiempo sea exactamente igual a uno de los puntos de límite, así que vamos a cambiarlo a:

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

Pero eso va a aparecer en un bucle:

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

¡Vaya! Eso tomará tiempo proporcional a len(bigdata) * len(dtsegs) ... ¿cuáles son los valores probables de len(bigdata) y len(dtsegs)?

Si se ordena bigdata, lo que desea hacer se puede hacer en un tiempo proporcional a N, donde N = len(bigdata). Si bigdata no está ya ordenado, se puede ordenar en un tiempo proporcional a N * log(N).

Que le gustaría hacer otra pregunta ...

También vale la pena señalar que cualquier artículo en bigdata que tienen una marca de tiempo < min (mdtimes) o> = max (mdtimes) no se incluirán en ningún segmento de datos ... ¿es esto intencional?

+0

Gracias John ... el kilometraje varía, pero 'bigdata' está en el orden de 10^6 registros y hay alrededor de 5-10 segmentos útiles con aproximadamente 10^5 registros en cada segmento. 'bigdata' no está ordenado per se, pero se lee de una secuencia alfabética de archivos que tienen la fecha como parte del nombre, por lo que las partes se ordenan por fecha y hora. Sí, algunos datos se omiten intencionalmente si no se incluyen en uno de los segmentos. El cuello de botella de tiempo hasta ahora está leyendo los archivos de texto (500MB + para cada análisis), creando los tiempos de fecha y comprimiendo las columnas de datos seleccionadas. – Pete

Cuestiones relacionadas