2010-12-01 22 views
16

J'ai une liste de datetime à partir de laquelle je veux construire des segments de temps. En d'autres termes, tournez [t0, t1, ... tn] en [(t0,t1),(t1,t2),...,(tn-1, tn)]. Je l'ai fait de cette façon:Puis-je compter sur l'ordre d'être conservé dans un tuple 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) 

Questions ...

  1. Puis-je compter sur tn-1 < tn pour tout (tn-1, tn) après que je l'ai créé eux cette façon? (La commande est-elle conservée?)
  2. Est-ce une bonne pratique de copier la liste originale mdtimes avec les listes de compréhension? Sinon, comment devrait-il être fait?
  3. Le but de la construction de ces tuples est de les parcourir et de segmenter un ensemble de données avec tn-1 et tn. Est-ce une approche raisonnable? à savoir

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

Merci

+1

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

+2

La question que vous n'avez pas faite t ask: Étant donné que 'x' est trié, est' x.reverse(); x.pop(); x.sort() 'une bonne idée? Réponse: ** NON **; c'est horrible; 'x.pop (0)' fera la même chose, et dans tous les cas, il vaut mieux utiliser n'importe laquelle des réponses que d'utiliser la méthode 'pop()'. –

+0

J'ai fini par aller avec 'dtsegs = zip (mdtimes [:], mdtimes [1:])' – Pete

Répondre

13
  1. L'ordre de tuple est lorsque vous insérez des valeurs dans le tuple. Ils ne vont pas être triés comme je le pense. zip sera à nouveau, conserver l'ordre que vous avez inséré les valeurs dans

  2. Il est une méthode acceptable, mais je 2 autres suggestions:. Utilisez le module copy ou utiliser dtg1 = mdtimes[:].

  3. Semble raisonnable.

2

Au lieu de: dtg0 = [x for x in mdtimes], dtg0 = mdtimes[:] ferait, puisque vous venez de copier une liste dans une autre. Note: à partir de Python 3.3, vous pouvez simplement dire newlist = oldlist.copy()

Comme pour la commande, l'ordre de zip est bien défini, et les listes et les tuples sont des collections ordonnées, donc vous ne devriez pas avoir de problème ici.

+1

'liste (mdtimes)' est une autre façon de copier, à mon humble avis le plus propre d'entre eux. list() est un constructeur, donc il crée toujours un nouvel objet, même si son argument est déjà une liste. –

+2

@Beni: c'est une question d'idiomes et de ce à quoi les gens sont habitués. Certains traitent mentalement [[]] comme copiant une liste.D'ailleurs, il y a une proposition en cours pour ajouter une méthode 'copy' à un objet de liste, ainsi le dessus devient' mdtimes.copy() '. Il est discuté dans ce numéro de Python: http://bugs.python.org/issue10516 –

+0

Cool! Vous avez atterri 'list.copy()' et 'list.clear()' dans python 3.3. Je pense que '.copy()' est mon nouveau style favori. –

5

Vous pouvez obtenir la même chose avec zip:

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

génial ... merci – Pete

+0

pour le garder continu J'ai utilisé 'zip (l [:], l [1:])' – Pete

16

Les deux list et tuple sont commandés.

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

Est-ce que cela a tout avantage par rapport à la suggestion implicite de Pawel de 'dtsegs = zip (mdtimes [:], mdtimes [1:])' – Pete

+1

@Pete: Cela n'implique pas la création de 2 listes temporaires. –

1

Je ne suis pas expert, mais ne sont pas vous quadruplement vos besoins en mémoire en copiant la liste, puis faire une nouvelle liste de paires prises à partir de deux listes? Pourquoi ne pas simplement faire ce qui suit:

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

Dunno comment "Pythonic" c'est, cependant. EDIT: En fait, en regardant ce que vous devez faire avec cette liste de tuples, vous pouvez simplement faire ce [i] et [i + 1] truc directement à ce niveau et même pas créer cette nouvelle structure du tout. Je ne sais pas combien de dates vous avez, cependant - si c'est un petit nombre, je suppose que cela n'a pas vraiment d'importance.Pour ce que ça vaut, un couple d'autres répondeurs ici semblent mal comprendre votre question, même si je ne peux pas commenter leurs messages, car je n'ai pas encore assez de réputation :) La solution d'Ignacio Vazquez-Abrams semble être la mieux pour moi, bien que son "next (dtg0)" devrait probablement être "next (dtg1)" (?)

+0

Personnellement, je préférerais avoir une structure séparée avec les segments de date pour rendre le code suivant plus facile à comprendre. Aussi, cela me permet de voir les segments pour m'assurer que tout va bien. – Pete

2

En tournant (x1, x2, x3, ...) en [(x1, x2), (x2 , x3), ...] est appelé une combinaison par paires, et il est un modèle que la documentation itertools si commune fournit une recette:

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

Ceci est une réponse à la question "Est-ce une approche raisonnable?" (qui semble avoir été ignoré par tous).

Résumé: Vous voudrez peut-être/besoin de lever le regard de faire un thingy sur mdtimes par paires au problème englobant (segmentant bigdata).

Détail:

L'utilisation souhaitée du résultat est exprimé:

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

qui est mieux exprimée:

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

Notez que qui se distingue, il sera n'incluez aucun cas où l'horodatage est exactement égal à l'un des points de limite, changeons-le en:

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

Mais qui va apparaître dans une boucle:

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

Whoops! Cela va prendre du temps proportionnel à len(bigdata) * len(dtsegs) ... quelles sont les valeurs probables de len(bigdata) et len(dtsegs)? Si bigdata est trié, ce que vous voulez faire peut être fait dans le temps proportionnel à N, N = len(bigdata). Si bigdata n'est pas déjà trié, il peut être trié en temps proportionnel à N * log(N).

Vous pourriez vous poser une autre question ...

Il est également intéressant de souligner que tous les éléments de bigdata qui ont un horodatage < min (mdtimes) ou> = max (mdtimes) ne seront pas inclus dans tous les segment de données ... est-ce intentionnel?

+0

Merci John ... le kilométrage varie mais 'bigdata' est de l'ordre de 10^6 enregistrements et il y a environ 5-10 segments utiles avec environ 10^5 enregistrements dans chaque segment. 'bigdata' n'est pas trié en soi, mais il est lu à partir d'une séquence alphabétique de fichiers dont la date fait partie du nom, donc les parties sont triées par datetime. Oui, certaines données sont volontairement omises si elles ne tombent pas dans l'un des segments. Le goulot d'étranglement temporel jusqu'à présent consiste à lire les fichiers texte (500 Mo + pour chaque analyse), à ​​créer les dates et à compresser les colonnes de données sélectionnées. – Pete