Supposons que j'ai deux Dataframes de tailles différentes:

df1 = pd.DataFrame(dict(xlow=np.linspace(0, 10, 11), 
                           xup=np.linspace(1.0, 11, 11))) 
df2 = pd.DataFrame(dict(x=np.random.uniform(low=1, high=10, size=(20,)), 
                           volume=np.random.randint(0, 10, size=20)))

Auquel j'ai:

df1: 
    xlow   xup
0    0.0   1.0
1    1.0   2.0
2    2.0   3.0
3    3.0   4.0
4    4.0   5.0
5    5.0   6.0
6    6.0   7.0
7    7.0   8.0
8    8.0   9.0
9    9.0  10.0
10  10.0  11.0

Et:

df2:
         x  volume
0   1.632789       8
1   8.346898       7
2   1.372285       2
3   1.946896       9
4   7.047305       0
5   3.851938       4
6   2.439664       7
7   8.823509       1
8   1.136700       1
9   8.766352       8
10  2.135441       8
11  8.092385       4
12  6.532898       3
13  7.199914       2
14  1.036684       0
15  9.714326       1
16  5.964111       0
17  9.625200       2
18  9.999818       6
19  9.891857       1

Maintenant, je veux ajouter une troisième colonne à df1, disons total_volume, où c'est la somme du volume qui se trouve entre la ligne individuelle de xlow et xup de df1. Je peux le faire en utilisant:

df1['total_volume']=df1.apply(lambda row: df2[(df2.x<=row['xup']) & (df2.x>row['xlow'])].volume.sum(),axis=1)

which results in 

    xlow   xup  total_volume
0    0.0   1.0             0
1    1.0   2.0            20
2    2.0   3.0            15
3    3.0   4.0             4
4    4.0   5.0             0
5    5.0   6.0             0
6    6.0   7.0             3
7    7.0   8.0             2
8    8.0   9.0            20
9    9.0  10.0            10
10  10.0  11.0             0

Nous pouvons vérifier la valeur de disons la deuxième ligne comme:

df2[(df2.x<=2) & (df2.x>1) ].volume.sum()=20

En réalité, mon df1 peut avoir jusqu'à des centaines de milliers de lignes, ce qui peut prendre jusqu'à des dizaines de minutes. Y a-t-il une manière plus vectorisée / pythonique de faire cela. J'ai essayé de fusionner et de rejoindre les pandas, mais je n'ai pas réussi, probablement parce que je suis encore un novice.

Je vous remercie pour votre aide!

2
tn22288 19 oct. 2020 à 08:03

2 réponses

Meilleure réponse

Si les bacs ne se chevauchent pas, utilisez {{X0} } avec un agrégat sum, puis ajouter à df1 par DataFrame.join:

df2['g'] = pd.cut(df2['x'], bins=[0] + df1['xup'].tolist(), labels=df1['xup'])

df2 = df1.join(df2.groupby('g')['volume'].sum(), on='xup')
print (df2)

    xlow xup  volume
0    0.0   1       0
1    1.0   2      20
2    2.0   3      15
3    3.0   4       4
4    4.0   5       0
5    5.0   6       0
6    6.0   7       3
7    7.0   8       2
8    8.0   9      20
9    9.0  10      10
10  10.0  11       0
0
jezrael 19 oct. 2020 à 06:00

Est-ce que chaque ligne de df1 a la même plage? Ensuite, itérez df2 et ajoutez simplement à df1.

for d in df2:
    df1[d.x//1].total_volume += d.volume

Sinon, triez df2.

0
Canasta 19 oct. 2020 à 05:13