J'essaie de trouver un code qui calculera essentiellement la valeur cumulée aux emplacements situés en dessous. Prendre la somme cumulée accomplit presque cela, mais certains emplacements contribuent au même point en aval. De plus, les points les plus en amont (ou points de départ) n'auront aucune valeur qui y contribue et peuvent rester leur valeur de départ dans le DataFrame cumulatif final.

Disons que j'ai le DataFrame suivant pour chaque site.

df = pd.DataFrame({
"Site 1": np.random.rand(10),
"Site 2": np.random.rand(10),
"Site 3": np.random.rand(10),
"Site 4": np.random.rand(10),
"Site 5": np.random.rand(10)})

J'ai également un tableau de données qui contient chaque site et son composant en aval correspondant.

df_order = pd.DataFrame({
    "Site 1": Site 3,
    "Site 2": Site 3,
    "Site 3": Site 4,
    "Site 4": Site 5,
    "Site 5": None})

Je veux faire ce qui suit:

1) Additionnez les valeurs en amont pour obtenir la somme cumulée sur la valeur en aval respective. Par exemple, le site 1 et le site 2 contribuent à la valeur du site 3. Je souhaite donc ajouter le site 1, le site 2 et le site 3 pour obtenir une valeur cumulée sur le site 3.

2) Maintenant que j'ai cette valeur cumulative sur le site 3, je veux enregistrer cette valeur cumulative sur le site 3 dans "df". Maintenant, je veux propager cette valeur sur le site 4, l'enregistrer en mettant à jour le DataFrame, puis passer au site 5.

Je peux me rapprocher en utilisant cumsum pour obtenir la valeur cumulée sur chaque site, comme ceci :

df = df.cumsum(axis=1)

Cependant, cela ne tient pas compte du fait que le site 1 et le site 2 contribuent au site 3, et non l'un l'autre.

Eh bien, je peux résoudre cela manuellement en utilisant:

df['Site 3'] = df.loc[:,'Site 1':'Site 3'].sum(axis = 1)
df['Site 4'] = df.loc[:,'Site 3':'Site 4'].sum(axis = 1)
df['Site 5'] = df.loc[:,'Site 4':'Site 5'].sum(axis = 1)

Cependant, ma liste actuelle de sites est beaucoup plus étendue et la méthode manuelle ne prend pas automatiquement en compte le "df_order" fourni. Existe-t-il un moyen de lier logiquement le DataFrame "df_order" de manière à ce qu'il puisse le calculer automatiquement ? Je sais comment faire cela manuellement, comment étendre cela pour pouvoir gérer un plus grand DataFrame et un ordre de sites ?

Pensez à un DataFrame plus grand, potentiellement jusqu'à 50 sites, qui ressemble à :

df_order = pd.DataFrame({
    "Site 1": Site 3,
    "Site 2": Site 3,
    "Site 3": Site 4,
    "Site 4": Site 5,
    "Site 5": Site 8,
    "Site 6": Site 8,
    "Site 7": Site 8,
    "Site 8": Site 9,
    "Site 9": None})
2
Jeff Coldplume 21 févr. 2020 à 21:21

1 réponse

Meilleure réponse

Vous pouvez utiliser networkx pour gérer les relations. Tout d'abord, faites votre commande DataFrame comme :

print(df_order)
   source  target
0  Site 1  Site 3
1  Site 2  Site 3
2  Site 3  Site 4
3  Site 4  Site 5
4  Site 5    None

Créer le graphe orienté

import networkx as nx
G = nx.from_pandas_edgelist(df_order.dropna(), 
                            source='source', target='target', 
                            create_using=nx.DiGraph)

nx.draw(G, with_labels=True)

enter image description here


Avec ce graphe orienté, vous voulez obtenir tous les predecessors. Nous pouvons le faire de manière récursive. (Votre graphique doit être un graphique dirigé acyclique, sinon la récursivité rencontre des problèmes)

def all_preds(G, target):
    preds=[target]
    for p in list(G.predecessors(target)):
        preds += all_preds(G, p)
    return preds

#Ex.
all_preds(G, 'Site 4')
['Site 4', 'Site 3', 'Site 1', 'Site 2']

Et nous pouvons maintenant vous créer des sommes en aval en boucle sur les colonnes générées par cette fonction pour tous vos sites uniques.

pd.concat([
    df[all_preds(G, target)].sum(1).rename(target)
    for target in df_order['source'].unique()
    ], axis=1)

Sortie en utilisant np.random.seed(42)

     Site 1    Site 2    Site 3    Site 4    Site 5
0  0.374540  0.020584  1.006978  1.614522  1.736561
1  0.950714  0.969910  2.060118  2.230642  2.725819
2  0.731994  0.832443  1.856581  1.921633  1.956021
3  0.598658  0.212339  1.177359  2.126245  3.035565
4  0.156019  0.181825  0.793914  1.759546  2.018326
5  0.155995  0.183405  1.124575  1.932972  2.595495
6  0.058084  0.304242  0.562000  0.866613  1.178324
7  0.866176  0.524756  1.905167  2.002839  2.522907
8  0.601115  0.431945  1.625475  2.309708  2.856418
9  0.708073  0.291229  1.045752  1.485905  1.670759
1
ALollz 21 févr. 2020 à 20:49