2009-12-28 14 views
1

J'ai des fichiers HDF5 avec plusieurs groupes, où chaque groupe contient un ensemble de données avec> = 25 millions de lignes. À chaque étape de simulation, chaque agent produit les autres agents qu'il/elle a détectés à ce pas de temps. Il y a ~ 2000 agents dans le scénario et des milliers de pas de temps; la nature O (n^2) de la sortie explique le grand nombre de lignes.Python, PyTables - tirer parti de la recherche dans le noyau

Ce qui m'intéresse est de calculer le nombre d'observations uniques par catégorie. Par exemple, les agents appartiennent à un côté, rouge, bleu ou vert. Je veux faire une table bidimensionnelle où la rangée i, colonne j est le nombre d'agents dans la catégorie j qui ont été détectés par au moins un agent dans la catégorie i. (J'utilise les côtés dans cet exemple de code, mais nous pouvons classer les agents d'autres façons, par exemple par l'arme qu'ils possèdent ou les capteurs qu'ils portent.)

Voici un exemple de tableau de sortie; Notez que la simulation ne produit pas de sensations bleu/bleu car cela prend énormément de place et ne nous intéresse pas. Idem pour le vert vert)

 blue  green  red 
blue 0  492  186 
green 1075 0  186 
red 451 498  26 

Les colonnes sont

  1. tique - pas de temps
  2. sensingAgentId - id de l'agent faisant détection
  3. sensedAgentId - id de l'agent étant lu
  4. detRange - plage en mètres entre deux agents
  5. senseType - type énuméré pour quel type de détection a été effectué

Voici le code Je suis actuellement en utilisant pour ce faire:

def createHeatmap(): 
    h5file = openFile("someFile.h5") 
    run0 = h5file.root.run0.detections 

    # A dictionary of dictionaries, {'blue': {'blue':0, 'red':0, ...} 
    classHeat = emptyDict(sides) 

    # Interested in Per Category Unique Detections 
    seenClass = {} 

    # Initially each side has seen no one  
    for theSide in sides: 
    seenClass[theSide] = [] 

    # In-kernel search filtering out many rows in file; in this instance 25,789,825 rows 
    # are filtered to 4,409,176 
    classifications = run0.where('senseType == 3') 

    # Iterate and filter 
    for row in classifications: 
    sensedId = row['sensedAgentId'] 
    # side is a function that returns the string representation of the side of agent 
    # with that id. 
    sensedSide = side(sensedId) 
    sensingSide = side(row['sensingAgentId']) 

    # The side has already seen this agent before; ignore it 
    if sensedId in seenClass[sensingSide]: 
     continue 
    else: 
     classHeat[sensingSide][sensedSide] += 1 
     seenClass[sensingSide].append(sensedId) 


    return classHeat 

Note: J'ai un fond Java, donc je me excuse si ce n'est pas Pythonic. Veuillez le signaler et suggérer des façons d'améliorer ce code, j'aimerais devenir plus compétent avec Python. Maintenant, c'est très lent: cela prend environ 50 secondes pour faire cette vérification d'itération et d'appartenance, et ceci avec l'ensemble de critères d'appartenance le plus restrictif (les autres types de détection ont beaucoup plus de lignes à parcourir).

Ma question est, est-il possible de déplacer le travail de python et dans la requête de recherche dans le noyau? Si c'est le cas, comment? Y a-t-il des accélérations évidentes qui me manquent? Je dois être capable d'exécuter cette fonction pour chaque exécution dans un ensemble d'exécutions (~ 30), et pour plusieurs ensembles de critères (~ 5), donc ce serait génial si cela pouvait être accéléré. Note finale: J'ai essayé d'utiliser psyco mais cela a à peine fait une différence.

+0

Pouvez-vous publier un fichier .h5 de test réduit? J'ai quelques idées, mais il serait plus facile de les vérifier avec des données semi-réelles. –

Répondre

2

Si vous avez des agents N = ~ 2k, je suggère de placer toutes les observations dans un tableau numérique de taille NxN. Cela s'adapte facilement en mémoire (environ 16 méga pour les entiers). Il suffit de stocker un 1 partout où une observation s'est produite.

Supposons que vous avez un tableau sightings. La première coordonnée est la détection, la seconde est détectée. Supposons que vous ayez également des tableaux d'index 1-d indiquant quels agents sont de quel côté. Vous pouvez obtenir le nombre d'observations de côté B par A côté de cette façon:

sideAseesB = sightings[sideAindices, sideBindices] 
sideAseesBcount = numpy.logical_or.reduce(sideAseesB, axis=0).sum() 

Il est possible que vous auriez besoin d'utiliser sightings.take(sideAindices, axis=0).take(sideBindices, axis=1) dans la première étape, mais je doute.

+0

http://pastebin.com/f5490dce0 - qu'est-ce que je fais mal? – I82Much

+0

J'avais tort, vous avez besoin des observations.take (...). Prenez (...) peu. (J'ai mis à jour le pastebin) –