J'ai un programme qui fonctionne sur un grand nombre de données expérimentales. Les données sont stockées sous forme de liste d'objets qui sont des instances d'une classe avec les attributs suivants:Python: Amélioration de la somme cumulative longue
- time_point - le temps de l'échantillon
- groupe - le nom du groupe de noeuds dont l'échantillon était pris
- nœud - le nom du noeud à partir duquel l'échantillon a été prélevé
- qty1 = la valeur de l'échantillon pour la première quantité
- qty2 = la valeur de l'échantillon pour la deuxième quantité
J'ai besoin de dériver certaines valeurs de l'ensemble de données, regroupées de trois façons - une fois pour l'échantillon dans son ensemble, une fois pour chaque groupe de nœuds, et une fois pour chaque nœud. Les valeurs que je dois dériver dépendent des sommes cumulatives (temps triées) de qty1 et qty2: la valeur maximale de la somme par élément des sommes cumulatives de qty1 et qty2, le point temporel auquel cette valeur maximale s'est produite, et le les valeurs de qty1 et qty2 à ce moment.
je suis venu avec la solution suivante:
dataset.sort(key=operator.attrgetter('time_point'))
# For the whole set
sys_qty1 = 0
sys_qty2 = 0
sys_combo = 0
sys_max = 0
# For the cluster grouping
cluster_qty1 = defaultdict(int)
cluster_qty2 = defaultdict(int)
cluster_combo = defaultdict(int)
cluster_max = defaultdict(int)
cluster_peak = defaultdict(int)
# For the node grouping
node_qty1 = defaultdict(int)
node_qty2 = defaultdict(int)
node_combo = defaultdict(int)
node_max = defaultdict(int)
node_peak = defaultdict(int)
for t in dataset:
# For the whole system ######################################################
sys_qty1 += t.qty1
sys_qty2 += t.qty2
sys_combo = sys_qty1 + sys_qty2
if sys_combo > sys_max:
sys_max = sys_combo
# The Peak class is to record the time point and the cumulative quantities
system_peak = Peak(time_point=t.time_point,
qty1=sys_qty1,
qty2=sys_qty2)
# For the cluster grouping ##################################################
cluster_qty1[t.cluster] += t.qty1
cluster_qty2[t.cluster] += t.qty2
cluster_combo[t.cluster] = cluster_qty1[t.cluster] + cluster_qty2[t.cluster]
if cluster_combo[t.cluster] > cluster_max[t.cluster]:
cluster_max[t.cluster] = cluster_combo[t.cluster]
cluster_peak[t.cluster] = Peak(time_point=t.time_point,
qty1=cluster_qty1[t.cluster],
qty2=cluster_qty2[t.cluster])
# For the node grouping #####################################################
node_qty1[t.node] += t.qty1
node_qty2[t.node] += t.qty2
node_combo[t.node] = node_qty1[t.node] + node_qty2[t.node]
if node_combo[t.node] > node_max[t.node]:
node_max[t.node] = node_combo[t.node]
node_peak[t.node] = Peak(time_point=t.time_point,
qty1=node_qty1[t.node],
qty2=node_qty2[t.node])
Cela produit la sortie correcte, mais je me demande si elle peut être plus lisible/Pythonic et/ou plus rapide/plus évolutive. Ce qui précède est attrayant en ce sens qu'il ne fait qu'une boucle dans le (grand) jeu de données une fois, mais peu attrayant du fait que j'ai essentiellement copié/collé trois copies du même algorithme.
Pour éviter les problèmes de copier/coller de ce qui précède, j'ai essayé cela aussi:
def find_peaks(level, dataset):
def grouping(object, attr_name):
if attr_name == 'system':
return attr_name
else:
return object.__dict__[attrname]
cuml_qty1 = defaultdict(int)
cuml_qty2 = defaultdict(int)
cuml_combo = defaultdict(int)
level_max = defaultdict(int)
level_peak = defaultdict(int)
for t in dataset:
cuml_qty1[grouping(t, level)] += t.qty1
cuml_qty2[grouping(t, level)] += t.qty2
cuml_combo[grouping(t, level)] = (cuml_qty1[grouping(t, level)] +
cuml_qty2[grouping(t, level)])
if cuml_combo[grouping(t, level)] > level_max[grouping(t, level)]:
level_max[grouping(t, level)] = cuml_combo[grouping(t, level)]
level_peak[grouping(t, level)] = Peak(time_point=t.time_point,
qty1=node_qty1[grouping(t, level)],
qty2=node_qty2[grouping(t, level)])
return level_peak
system_peak = find_peaks('system', dataset)
cluster_peak = find_peaks('cluster', dataset)
node_peak = find_peaks('node', dataset)
Pour les (non regroupés) calculs au niveau du système, Je suis également venu avec ce qui est assez:
dataset.sort(key=operator.attrgetter('time_point'))
def cuml_sum(seq):
rseq = []
t = 0
for i in seq:
t += i
rseq.append(t)
return rseq
time_get = operator.attrgetter('time_point')
q1_get = operator.attrgetter('qty1')
q2_get = operator.attrgetter('qty2')
timeline = [time_get(t) for t in dataset]
cuml_qty1 = cuml_sum([q1_get(t) for t in dataset])
cuml_qty2 = cuml_sum([q2_get(t) for t in dataset])
cuml_combo = [q1 + q2 for q1, q2 in zip(cuml_qty1, cuml_qty2)]
combo_max = max(cuml_combo)
time_max = timeline.index(combo_max)
q1_at_max = cuml_qty1.index(time_max)
q2_at_max = cuml_qty2.index(time_max)
Cependant, des compréhensions de liste et zip() malgré l'utilisation fraîche de cette version, il boucle dans l'ensemble de données trois fois seulement pour les calculs au niveau du système, et je ne peux pas penser à une bonne façon de faire la calaculations au niveau du cluster et du nœud sans faire quelque chose de lent comme:
timeline = defaultdict(int)
cuml_qty1 = defaultdict(int)
#...etc.
for c in cluster_list:
timeline[c] = [time_get(t) for t in dataset if t.cluster == c]
cuml_qty1[c] = [q1_get(t) for t in dataset if t.cluster == c]
#...etc.
Est-ce que quelqu'un ici à Stack Overflow a des suggestions d'améliorations? Le premier extrait ci-dessus fonctionne bien pour mon jeu de données initial (de l'ordre du million d'enregistrements), mais les jeux de données ultérieurs auront plus d'enregistrements et de clusters/nœuds, donc l'évolutivité est une préoccupation. Ceci est ma première utilisation non-triviale de Python, et je veux m'assurer que je profite bien du langage (ceci remplace un ensemble très compliqué de requêtes SQL, et les versions antérieures de la version Python étaient transalations droites essentiellement très inefficaces de ce que cela a fait). En général, je ne fais pas beaucoup de programmation, il me manque peut-être quelque chose d'élémentaire.
Merci beaucoup!
Vous pouvez d'abord effectuer tous les calculs de nœud, puis utiliser les résultats de nœud pour calculer les résultats du cluster, puis utiliser les résultats de cluster pour calculer les résultats à l'échelle du système. Cela réduirait au moins une partie de la répétition (ajouts identiques) que vous faites actuellement. – unutbu
Merci pour la suggestion. Cependant, le pic du cluster pourrait être différent de n'importe lequel des pics des nœuds individuels. Par exemple, ils peuvent tous atteindre une valeur moyenne à la fois, provoquant un pic énorme pour le cluster, mais un pic non-énorme pour un nœud individuel. – bbayles