2016-05-21 6 views
2

Ich habe zwei große Vektoren item_clusters und Beta. Das Element item_clusters [i] ist die Cluster-ID, zu der der Artikel i gehört. Das Element beta [i] ist eine Punktzahl für den Artikel i. Punkte sind {-1, 0, 1, 2, 3}.Fehlende Wert Anrechnungs in Python

Immer wenn der Punktestand eines bestimmten Eintrags 0 ist, muss ich dies mit dem durchschnittlichen Wert anderer Punkte, die zu demselben Cluster gehören, gleich Null berechnen. Was ist der schnellste Weg dazu?

Dies ist, was ich bisher versucht habe. I umgewandelt, um die item_clusters an eine Matrix clusters_to_items so daß das Element clusters_to_items [ i] [j ] = 1, wenn der Cluster i enthält Artikel j, sonst 0. Danach ich bin Ausführen des folgenden Codes

# beta (1x1.3M) csr matrix 
# num_clusters = 1000 
# item_clusters (1x1.3M) numpy.array 
# clust_to_items (1000x1.3M) csr_matrix 

alpha_z = [] 
for clust in range(0, num_clusters): 
    alpha = clust_to_items[clust, :] 
    alpha_beta = beta.multiply(alpha) 
    sum_row = alpha_beta.sum(1)[0, 0] 
    num_nonzero = alpha_beta.nonzero()[1].__len__() + 0.001 
    to_impute = sum_row/num_nonzero 
    Z = np.repeat(to_impute, beta.shape[1]) 
    alpha_z = alpha.multiply(Z) 
    idx = beta.nonzero() 
    alpha_z[idx] = beta.data 
interact_score = alpha_z.tolist()[0] 

# The interact_score is the required modified beta 
# This is used to do some work that is very fast 

Das Problem ist, dass dieser Code 150K mal ausgeführt werden muss und es sehr langsam ist. Nach meiner Schätzung wird es 12 Tage dauern.

Edit: Ich glaube, ich brauche eine sehr unterschiedliche Idee, in der ich direkt item_clusters verwenden kann, und nicht jedes Cluster einzeln durchlaufen müssen.

+0

Ok, ich werde das unpopuläre Kind sein hier: Pythons eine großartige Sprache, aber wenn die Leistung ist als genauso wie hier, und besonders, wenn Sie mit riesigen Mengen von Rohdaten zu tun haben, und dies ist Ihr Hotspot, wo die meiste Zeit verbracht wird, implementieren Sie es in C. –

+0

Können Sie herausfinden, welche Codezeile die meiste Zeit benötigt? –

+0

Hinweis: schau dir 'nufunc' von numpy an. –

Antwort

2

Ich weiß nicht, ob dies bedeutet, dass ich das populäre Kind hier bin oder nicht, aber ich denke, Sie Ihre Operationen in der folgenden Art und Weise vektorisieren können:

def fast_impute(num_clusters, item_clusters, beta): 

    # get counts 
    cluster_counts = np.zeros(num_clusters) 
    np.add.at(cluster_counts, item_clusters, 1) 

    # get complete totals 
    totals = np.zeros(num_clusters) 
    np.add.at(totals, item_clusters, beta) 

    # get number of zeros 
    zero_counts = np.zeros(num_clusters) 
    z = beta == 0 
    np.add.at(zero_counts, item_clusters, z) 

    # non-zero means 
    cluster_means = totals/(cluster_counts - zero_counts) 

    # perform imputations 
    imputed_beta = np.where(beta != 0, beta, cluster_means[item_clusters]) 

    return imputed_beta 

die mir

>>> N = 10**6 
>>> num_clusters = 1000 
>>> item_clusters = np.random.randint(0, num_clusters, N) 
>>> beta = np.random.choice([-1, 0, 1, 2, 3], size=len(item_clusters)) 
>>> %time imputed = fast_impute(num_clusters, item_clusters, beta) 
CPU times: user 652 ms, sys: 28 ms, total: 680 ms 
Wall time: 679 ms 
gibt

und

>>> imputed[:5] 
array([ 1.27582017, -1.  , -1.  , 1.  , 3.  ]) 
>>> item_clusters[:5] 
array([506, 968, 873, 179, 269]) 
>>> np.mean([b for b, i in zip(beta, item_clusters) if i == 506 and b != 0]) 
1.2758201701093561 

Hinweis dass ich das oben manuell gemacht habe. Es wäre viel einfacher, wenn Sie auf höhere Ebene Tools wurden, sagen, wie sie von pandas zur Verfügung gestellt:

>>> df = pd.DataFrame({"beta": beta, "cluster": item_clusters}) 
>>> df.head() 
    beta cluster 
0  0  506 
1 -1  968 
2 -1  873 
3  1  179 
4  3  269 
>>> df["beta"] = df["beta"].replace(0, np.nan) 
>>> df["beta"] = df["beta"].fillna(df["beta"].groupby(df["cluster"]).transform("mean")) 
>>> df.head() 
     beta cluster 
0 1.27582  506 
1 -1.00000  968 
2 -1.00000  873 
3 1.00000  179 
4 3.00000  269 
0

Mein Verdacht ist, dass

alpha_beta = beta.multiply(alpha) 

eine schreckliche Idee ist, weil man nur die ersten Elemente der Zeilensummen benötigen, so dass Sie ein paar tun Millionen vergeblich mehrfach ergänzt, wenn ich nicht zu verwechseln:

sum_row = alpha_beta.sum(1)[0, 0] 

die diskrete Formel für beta * alpha also aufschreiben, dann die Zeile wählen Sie die Formel für die Summe benötigen und abzuleiten.

+0

Die Idee ist, dass sowohl Alpha als auch Beta Vektoren sind. Ich muss die Summe der Beta-Elemente nur dann nehmen, wenn sie zum Cluster Clust gehören (d. H. Alpha-Werte sind 1). Deshalb multipliziere ich Alpha und Beta elementweise. Alpha_Beta-Summe ist eine Matrix aus einem Element. Um den tatsächlichen Gleitkommawert zu erhalten, muss ich explizit [0] [0] erwähnen. –

+0

@SonuKMishra Hinweis: Summe (elementweise Produkt) kann in einem Schritt berechnet werden, nämlich das * dot Produkt * –

+0

Aber ich brauche nicht nur Summe. Ich brauche einen Durchschnitt, für den ich auch die Anzahl solcher Elemente brauche. –

Verwandte Themen