web-dev-qa-db-fra.com

Obtenir l'index des colonnes et des lignes pour obtenir la valeur la plus élevée dans les pandas Dataframe

J'aimerais savoir s'il existe un moyen de trouver l'emplacement (index de colonne et de ligne) de la valeur la plus élevée dans un cadre de données. Donc si par exemple mon dataframe ressemble à ceci:

   A         B         C         D         E
0  100       9         1         12        6
1  80        10        67        15        91
2  20        67        1         56        23
3  12        51        5         10        58
4  73        28        72        25        1

Comment puis-je obtenir un résultat qui ressemble à ceci: [0, 'A'] en utilisant des pandas?

5
christfan868

Utilisez np.argmax

Les numéros argmax de NumPy peuvent être utiles:

>>> df.stack().index[np.argmax(df.values)]
(0, 'A')

Par étapes

df.values est un tableau NumPy à deux dimensions:

>>> df.values
array([[100,   9,   1,  12,   6],
       [ 80,  10,  67,  15,  91],
       [ 20,  67,   1,  56,  23],
       [ 12,  51,   5,  10,  58],
       [ 73,  28,  72,  25,   1]])

argmax vous donne l'index pour la valeur maximale du tableau "aplati":

>>> np.argmax(df.values)
0

Maintenant, vous pouvez utiliser cet index pour trouver l'emplacement de la ligne-colonne sur le dataframe empilé:

>>> df.stack().index[0]
(0, 'A')

Alternative rapide

Si vous en avez besoin rapidement, faites aussi peu que possible. Travailler uniquement sur le tableau NumPy pour trouver les indices np.argmax semble être préférable:

v = df.values
i, j = [x[0] for x in np.unravel_index([np.argmax(v)], v.shape)]
[df.index[i], df.columns[j]]

Résultat:

[0, 'A']

Les horaires

La synchronisation convient mieux aux trames de données lareg:

df = pd.DataFrame(data=np.arange(int(1e6)).reshape(-1,5), columns=list('ABCDE'))

Trié le plus lent au plus rapide:

Masque:

%timeit df.mask(~(df==df.max().max())).stack().index.tolist()
33.4 ms ± 982 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

Stack-idmax

%timeit list(df.stack().idxmax())
17.1 ms ± 139 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Stack-Argmax

%timeit df.stack().index[np.argmax(df.values)]
14.8 ms ± 392 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%%timeit
i,j = np.where(df.values == df.values.max())
list((df.index[i].values.tolist()[0],df.columns[j].values.tolist()[0]))

4.45 ms ± 84.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Argmax-unravel_index

%%timeit

v = df.values
i, j = [x[0] for x in np.unravel_index([np.argmax(v)], v.shape)]
[df.index[i], df.columns[j]]

499 µs ± 12 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Comparer

d = {'name': ['Mask', 'Stack-idmax', 'Stack-argmax', 'Where', 'Argmax-unravel_index'],
     'time': [33.4, 17.1, 14.8, 4.45, 499],
     'unit': ['ms', 'ms', 'ms', 'ms', 'µs']}


timings = pd.DataFrame(d)
timings['seconds'] = timings.time * timings.unit.map({'ms': 1e-3, 'µs': 1e-6})
timings['factor slower'] = timings.seconds / timings.seconds.min()
timings.sort_values('factor slower')

Sortie:

                   name    time unit   seconds  factor slower
4  Argmax-unravel_index  499.00   µs  0.000499       1.000000
3                 Where    4.45   ms  0.004450       8.917836
2          Stack-argmax   14.80   ms  0.014800      29.659319
1           Stack-idmax   17.10   ms  0.017100      34.268537
0                  Mask   33.40   ms  0.033400      66.933868

Ainsi, la version "Argmax-unravel_index" semble être plus rapide d’un à deux ordres de grandeur pour les grandes trames de données, c’est-à-dire où la vitesse importe souvent le plus.

9
Mike Müller

Utilisez stack pour Series avec MultiIndex et idxmax pour l'index de valeur max:

print (df.stack().idxmax())
(0, 'A')

print (list(df.stack().idxmax()))
[0, 'A']

Détail:

print (df.stack())
0  A    100
   B      9
   C      1
   D     12
   E      6
1  A     80
   B     10
   C     67
   D     15
   E     91
2  A     20
   B     67
   C      1
   D     56
   E     23
3  A     12
   B     51
   C      5
   D     10
   E     58
4  A     73
   B     28
   C     72
   D     25
   E      1
dtype: int64
7
jezrael

mask + max

df.mask(~(df==df.max().max())).stack().index.tolist()
Out[17]: [(0, 'A')]
2
Wen-Ben

À mon avis, pour les grands ensembles de données, stack () devient inefficace, utilisons np.where pour renvoyer les positions d'index:

i,j = np.where(df.values == df.values.max())
list((df.index[i].values.tolist()[0],df.columns[j].values.tolist()[0]))

Sortie:

[0, 'A']

Timings pour les plus grands fichiers de données:

df = pd.DataFrame(data=np.arange(10000).reshape(-1,5), columns=list('ABCDE'))

méthode np.where

> %%timeit i,j = np.where(df.values == df.values.max())
> list((df.index[i].values.tolist()[0],df.columns[j].values.tolist()[0]))

1000 boucles, meilleur de 3: 364 µs par boucle

Autres méthodes de pile

> %timeit df.mask(~(df==df.max().max())).stack().index.tolist()

100 boucles, le meilleur de 3: 7,68 ms par boucle

> %timeit df.stack().index[np.argmax(df.values)`]

10 boucles, meilleur de 3: 50,5 ms par boucle

> %timeit list(df.stack().idxmax())

1000 boucles, le meilleur des 3: 1,58 ms par boucle

Une base de données encore plus grande:

df = pd.DataFrame(data=np.arange(100000).reshape(-1,5), columns=list('ABCDE'))

Respectivement:

1000 loops, best of 3: 1.62 ms per loop
10 loops, best of 3: 18.2 ms per loop
100 loops, best of 3: 5.69 ms per loop
100 loops, best of 3: 6.64 ms per loop
1
Scott Boston
print('Max value:', df.stack().max())
print('Parameters :', df.stack().idxmax())

C'est la meilleure façon à mon humble avis.

0
Alex Deineha

Cela devrait fonctionner:

def max_df(df):
    m = None
    p = None
    for idx, item in enumerate(df.idxmax()):
        c = df.columns[item]
        val = df[c][idx]
        if m is None or val > m:
            m = val
            p = idx, c
    return p

Ceci utilise la fonction idxmax , puis compare toutes les valeurs renvoyées par celle-ci.

Exemple d'utilisation:

>>> df

     A  B
0  100  9
1   90  8
>>> max_df(df)

(0, 'A')

Voici un one-liner (pour le fun):

def max_df2(df):
    return max((df[df.columns[item]][idx], idx, df.columns[item]) for idx, item in enumerate(df.idxmax()))[1:]
0
rassar