179 votes

Mise à plat d'une colonne avec Python Pandas

J'ai une colonne de cadre de données avec des valeurs numériques :

df['percentage'].head()
46.5
44.2
100.0
42.12

Je veux voir la colonne comme comptes de poubelles :

bins = [0, 1, 5, 10, 25, 50, 100]

Comment puis-je obtenir le résultat sous forme de bacs avec leur valeur des comptes ?

[0, 1] bin amount
[1, 5] etc
[5, 10] etc
...

326voto

jezrael Points 290608

Vous pouvez utiliser pandas.cut :

bins = [0, 1, 5, 10, 25, 50, 100]
df['binned'] = pd.cut(df['percentage'], bins)
print (df)
   percentage     binned
0       46.50   (25, 50]
1       44.20   (25, 50]
2      100.00  (50, 100]
3       42.12   (25, 50]

bins = [0, 1, 5, 10, 25, 50, 100]
labels = [1,2,3,4,5,6]
df['binned'] = pd.cut(df['percentage'], bins=bins, labels=labels)
print (df)
   percentage binned
0       46.50      5
1       44.20      5
2      100.00      6
3       42.12      5

Ou numpy.searchsorted :

bins = [0, 1, 5, 10, 25, 50, 100]
df['binned'] = np.searchsorted(bins, df['percentage'].values)
print (df)
   percentage  binned
0       46.50       5
1       44.20       5
2      100.00       6
3       42.12       5

...et ensuite value_counts o groupby et agrégat size :

s = pd.cut(df['percentage'], bins=bins).value_counts()
print (s)
(25, 50]     3
(50, 100]    1
(10, 25]     0
(5, 10]      0
(1, 5]       0
(0, 1]       0
Name: percentage, dtype: int64

s = df.groupby(pd.cut(df['percentage'], bins=bins)).size()
print (s)
percentage
(0, 1]       0
(1, 5]       0
(5, 10]      0
(10, 25]     0
(25, 50]     3
(50, 100]    1
dtype: int64

Par défaut cut renvoie à categorical .

Series des méthodes comme Series.value_counts() utilisera toutes les catégories, même si certaines catégories ne sont pas présentes dans les données, opérations dans les catégories .

0 votes

Sans bins = [0, 1, 5, 10, 25, 50, 100] Par exemple, j'ai 110 enregistrements, je veux les couper en 5 bacs avec 22 enregistrements dans chaque bac.

2 votes

@qqqwww - Je ne suis pas sûr de comprendre, pensez-vous que qcut ? lien

0 votes

@qqqwww pour faire cela, l'exemple de pd.cut dans sa page le montre : pd.cut(np.array([1, 7, 5, 4, 6, 3]), 3) va couper le tableau en 3 parties égales.

23voto

Erfan Points 19682

Utilisation de la Numba pour accélérer le processus.

Sur les grands ensembles de données (plus de 500k), pd.cut peut être assez lent pour les données de binning.

J'ai écrit ma propre fonction en Numba avec une compilation juste à temps, ce qui revient à peu près à six fois plus rapide :

from numba import njit

@njit
def cut(arr):
    bins = np.empty(arr.shape[0])
    for idx, x in enumerate(arr):
        if (x >= 0) & (x < 1):
            bins[idx] = 1
        elif (x >= 1) & (x < 5):
            bins[idx] = 2
        elif (x >= 5) & (x < 10):
            bins[idx] = 3
        elif (x >= 10) & (x < 25):
            bins[idx] = 4
        elif (x >= 25) & (x < 50):
            bins[idx] = 5
        elif (x >= 50) & (x < 100):
            bins[idx] = 6
        else:
            bins[idx] = 7

    return bins

cut(df['percentage'].to_numpy())

# array([5., 5., 7., 5.])

Facultatif : vous pouvez également le mettre en correspondance avec les bacs en tant que chaînes de caractères :

a = cut(df['percentage'].to_numpy())

conversion_dict = {1: 'bin1',
                   2: 'bin2',
                   3: 'bin3',
                   4: 'bin4',
                   5: 'bin5',
                   6: 'bin6',
                   7: 'bin7'}

bins = list(map(conversion_dict.get, a))

# ['bin5', 'bin5', 'bin7', 'bin5']

Comparaison des vitesses :

# Create a dataframe of 8 million rows for testing
dfbig = pd.concat([df]*2000000, ignore_index=True)

dfbig.shape

# (8000000, 1)

%%timeit
cut(dfbig['percentage'].to_numpy())

# 38 ms ± 616 µs per loop (mean ± standard deviation of 7 runs, 10 loops each)

%%timeit
bins = [0, 1, 5, 10, 25, 50, 100]
labels = [1,2,3,4,5,6]
pd.cut(dfbig['percentage'], bins=bins, labels=labels)

# 215 ms ± 9.76 ms per loop (mean ± standard deviation of 7 runs, 10 loops each)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X