J'ai une longue table de données (environ 200 lignes sur 50 colonnes) et je dois créer un code capable de calculer les valeurs moyennes de toutes les deux lignes et pour chaque colonne de la table, le résultat final étant une nouvelle table de la moyenne. valeurs. C'est évidemment fou à faire dans Excel! J'utilise python3 et je suis conscient de certaines questions similaires: ici , ici et ici . Mais rien de tout cela n’aide, car j’ai besoin d’un code élégant pour travailler avec plusieurs colonnes et produire un tableau de données organisé. En passant, mon datatable original a été importé à l'aide de pandas et est défini comme un cadre de données, mais il n'a pas été facile de trouver un moyen simple de le faire. L'aide est très appréciée.
Un exemple de tableau (version courte) est:
a b c d
2 50 25 26
4 11 38 44
6 33 16 25
8 37 27 25
10 28 48 32
12 47 35 45
14 8 16 7
16 12 16 30
18 22 39 29
20 9 15 47
Tableau moyen attendu:
a b c d
3 30.5 31.5 35
7 35 21.5 25
11 37.5 41.5 38.5
15 10 16 18.5
19 15.5 27 38
Vous pouvez créer un groupe artificiel à l'aide de df.index//2
(ou comme l'a souligné @DSM, à l'aide de np.arange(len(df))//2
- pour que cela fonctionne pour tous les index), puis utiliser groupby:
df.groupby(np.arange(len(df))//2).mean()
Out[13]:
a b c d
0 3.0 30.5 31.5 35.0
1 7.0 35.0 21.5 25.0
2 11.0 37.5 41.5 38.5
3 15.0 10.0 16.0 18.5
4 19.0 15.5 27.0 38.0
La méthode NumPythonic consisterait à extraire les éléments sous forme de tableau NumPy avec df.values
, à le remodeler en tableau 3D
avec les éléments 2
suivant axis=1
et 4
suivant axis=2
, puis à effectuer la réduction moyenne suivant axis=1
, puis à reconvertir en une base de données,
pd.DataFrame(df.values.reshape(-1,2,df.shape[1]).mean(1))
En fin de compte, vous pouvez présenter l'outil très efficace de NumPy: np.einsum
faire ceci average-reduction
en combinant sum-reduction
et scaling-down
, comme suit -
pd.DataFrame(np.einsum('ijk->ik',df.values.reshape(-1,2,df.shape[1]))/2.0)
Veuillez noter que les approches proposées supposent que le nombre de lignes est divisible par 2
.
Également en tant que noted by @DSM
, pour conserver les noms de colonne, vous devez ajouter columns=df.columns
lors de la reconversion en Dataframe, c'est-à-dire -
pd.DataFrame(...,columns=df.columns)
Exemple de cycle -
>>> df
0 1 2 3
0 2 50 25 26
1 4 11 38 44
2 6 33 16 25
3 8 37 27 25
4 10 28 48 32
5 12 47 35 45
6 14 8 16 7
7 16 12 16 30
8 18 22 39 29
9 20 9 15 47
>>> pd.DataFrame(df.values.reshape(-1,2,df.shape[1]).mean(1))
0 1 2 3
0 3 30.5 31.5 35.0
1 7 35.0 21.5 25.0
2 11 37.5 41.5 38.5
3 15 10.0 16.0 18.5
4 19 15.5 27.0 38.0
>>> pd.DataFrame(np.einsum('ijk->ik',df.values.reshape(-1,2,df.shape[1]))/2.0)
0 1 2 3
0 3 30.5 31.5 35.0
1 7 35.0 21.5 25.0
2 11 37.5 41.5 38.5
3 15 10.0 16.0 18.5
4 19 15.5 27.0 38.0
Tests d'exécution -
Dans cette section, testons les trois approches répertoriées jusqu'à présent pour résoudre le problème en termes de performances, notamment @ayhan's solution with groupby
.
In [24]: A = np.random.randint(0,9,(200,50))
In [25]: df = pd.DataFrame(A)
In [26]: %timeit df.groupby(df.index//2).mean() # @ayhan's solution
1000 loops, best of 3: 1.61 ms per loop
In [27]: %timeit pd.DataFrame(df.values.reshape(-1,2,df.shape[1]).mean(1))
1000 loops, best of 3: 317 µs per loop
In [28]: %timeit pd.DataFrame(np.einsum('ijk->ik',df.values.reshape(-1,2,df.shape[1]))/2.0)
1000 loops, best of 3: 266 µs per loop
df.set_index(np.arange(len(df)) // 2).mean(level=0)
Vous pouvez aborder ce problème en utilisant pd.rolling()
pour créer une moyenne glissante, puis saisissez chaque deuxième élément en utilisant iloc
df = df.rolling(2).mean()
df = df.iloc[::2, :]
Notez que la première observation sera manquante (c'est-à-dire que le roulement commence en haut)