2009-11-09 6 views
4

J'ai actuellement une structure qui est un dict: chaque valeur est une liste qui contient des valeurs numériques. Chacune de ces listes numériques contient ce que (pour emprunter un idiome SQL) vous pourriez appeler une clé primaire contenant les trois premières valeurs qui sont: une année, un identifiant de joueur et un identifiant d'équipe. C'est la clé pour le dict.Recommandation de structure de données Python?

Vous pouvez obtenir une ligne unique en faisant passer la valeur dans l'année, identification du joueur, et l'ID d'équipe comme ceci:

statline = stats[(2001, 'SEA', 'suzukic01')] 

Ce qui donne quelque chose comme

[305, 20, 444, 330, 45] 

Je d aimer modifier cette structure de données pour qu'elle soit rapidement additionnée de l'une ou l'autre de ces trois clés: ainsi vous pouvez facilement découper les totaux pour un index donné dans les listes numériques en passant UN de l'année, ID du joueur et ID de l'équipe, puis indice. Je veux être capable de faire quelque chose comme

hr_total = stats[year=2001, idx=3] 

Où que IDX 3 correspond à la troisième colonne de la liste numérique (s) qui serait récupéré.

Des idées?

Répondre

4

Lire sur Data Warehousing. Tout livre

Lire sur Star Schema Design. Tout livre Sérieusement.

Vous avez plusieurs dimensions: Année, Joueur, Equipe.

Vous avez un fait: score

Vous voulez avoir une structure comme celui-ci.

Vous souhaitez ensuite créer un ensemble d'index de dimensions comme celui-ci.

years = collections.defaultdict(list) 
players = collections.defaultdict(list) 
teams = collections.defaultdict(list) 

Votre table de faits peut être cette collections.namedtuple. Vous pouvez utiliser quelque chose comme ça.

class ScoreFact(object): 
    def __init__(self, year, player, team, score): 
     self.year= year 
     self.player= player 
     self.team= team 
     self.score= score 
     years[self.year].append(self) 
     players[self.player].append(self) 
     teams[self.team].append(self) 

Maintenant, vous pouvez trouver tous les éléments d'une valeur de dimension donnée. C'est une liste simple attachée à une valeur de dimension. Vous pouvez simplement utiliser sum() pour les ajouter. Une requête multidimensionnelle est quelque chose comme ça.

[ x for x in players['SEA'] if x.year == '2001' ] 
+0

J'aime ce un peu, mais N'est-ce pas une mémoire intensive? Je suppose que vous ne stockez que trois références plutôt que trois copies de la valeur, mais quand même ... – Wells

+0

C'est le design standard de Star Schema. Vous pouvez l'implémenter en SQL, ou shelve ou pure en mémoire. Il faut seulement un peu plus de stockage qu'une liste de faits. Plus précisément, il nécessite les dictionnaires supplémentaires - qui ne sont que des références aux objets de la collection de faits d'origine. –

4

Mettez vos données dans SQLite, et utilisez son moteur relationnel pour faire le travail. Vous pouvez créer une base de données en mémoire et même ne pas avoir à toucher le disque.

1

La syntaxe stats[year=2001, idx=3] est Python invalide et il est impossible de le faire fonctionner avec ces crochets et «mots-clés arguments»; vous devrez avoir un appel de fonction ou de méthode pour accepter les arguments de mots-clés. Donc, disons que nous en faisons une fonction, pour appeler wells(stats, year=2001, idx=3). J'imagine que l'argument idx est obligatoire (ce qui est très particulier compte tenu de l'appel, mais vous ne donnez aucune indication de ce qui pourrait signifier omettre idx) et exactement l'un de l'année, playerid, et teamid doit être là.

Avec votre structure de données actuelles, les puits peuvent déjà être mis en œuvre:

def wells(stats, year=None, playerid=None, teamid=None, idx=None): 
    if idx is None: raise ValueError('idx must be specified') 
    specifiers = [(i, x) for x in enumerate((year, playerid, teamid)) if x is not None] 
    if len(specifiers) != 2: 
    raise ValueError('Exactly one of year, playerid, teamid, must be given') 
    ikey, keyv = specifiers[0] 
    return sum(v[idx] for k, v in stats.iteritems() if k[ikey]==keyv) 

bien sûr, cela est O (N) dans la taille de stats - il doit examiner chaque entrée en elle. S'il vous plaît mesurer l'exactitude et la performance avec cette implémentation simple comme référence. Une solution alternative (beaucoup plus rapide en usage, mais demandant beaucoup de temps pour la préparation) consiste à mettre trois dicts de listes (un pour chaque année, playerid, teamid) du côté de stats, chaque entrée indiquant (ou copiant, mais je pense en indiquant par clé complète peut suffire) toutes les entrées de statistiques qui correspondent à cette paire ikey/keyv. Mais il n'est pas clair pour le moment si cette implémentation n'est peut-être pas prématurée, alors essayez d'abord avec l'idée simple! -)

0
def getSum(d, year, idx): 
    sum = 0 
    for key in d.keys(): 
     if key[0] == year: 
      sum += d[key][idx] 
    return sum 

Cela devrait vous aider à démarrer. J'ai fait l'hypothèse dans ce code, cette année seulement sera demandé, mais il devrait être assez facile pour vous de manipuler ce pour vérifier d'autres paramètres ainsi

Vive

Questions connexes