J'ai l'exemple de trame de données suivant

df = pd.DataFrame({'ID': [11, 12, 16, 19, 14, 9, 4, 13, 6, 18], 
                   'Value': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]})

Auquel j'ajoute le pourcentage de Value utilisant

df['Percent Value'] = df.reset_index()['Value'].rank(method='dense', pct=True)

Qui donne

    ID  Value   Percent Value
0   11   1         0.1
1   12   2         0.2
2   16   3         0.3
3   19   4         0.4
4   14   5         0.5
5   9    6         0.6
6   4    7         0.7
7   13   8         0.8
8   6    9         0.9
9   18   10        1.0

Je définis ensuite le tableau de pourcentage suivant

percentage = np.array([30, 40, 60, 90, 100])

Ma sortie souhaitée est la suivante avec une colonne Order où, sur la base du tableau percentage, les Value qui sont jusqu'à 30% obtiennent l'ordre 1, 30-40% obtiennent l'ordre 2, 40-60% obtient l'ordre 3, 60-90% obtient l'ordre 4, 90-100% obtient l'ordre 5.

Donc, la sortie finale est

    ID  Value   Percent Value   Order
0   11   1          0.1           1
1   12   2          0.2           1
2   16   3          0.3           1
3   19   4          0.4           2
4   14   5          0.5           3
5   9    6          0.6           3
6   4    7          0.7           4
7   13   8          0.8           4
8   6    9          0.9           4
9   18   10         1.0           5

Je peux le faire en faisant une boucle sur la colonne Percent Value et en prenant l'index de la première valeur du tableau percentage qui renvoie True pour la condition <. Je me demande s'il existe un moyen plus simple dans les pandas où je peux passer le tableau percentage comme argument pour comparer la colonne Percent Value.

Ma tentative en utilisant la compréhension de liste

df['Order'] = [1 + np.where(v <= percentage)[0][0] for v in df['Percent Value']]
2
Sheldore 4 juin 2020 à 12:53

4 réponses

Meilleure réponse

Les pandas cut pourraient aider ici; J'ai inclus un 0 au début pour obtenir des gammes inférieures à 0,3

df['Percent Value'] = df.Value.rank(method='dense',pct=True)

percentage = np.array([30, 40, 60, 90, 100])


#get the values in fraction, since percent value is in that format
percentage = percentage/100


#insert a 0 at the start to get the boundary,
#so u'll have a 0 to 0.3 bin, 0.3 to 0.4, 0.4 to 0.6, and so on
#the final value will have the labels based on the bins
df['Order'] = pd.cut(df['Percent Value'],bins=np.insert(percentage,0,0), labels = [1,2,3,4,5])


    ID  Value   Percent Value   Order
0   11    1      0.1            1
1   12    2      0.2            1
2   16    3      0.3            1
3   19    4      0.4            2
4   14    5      0.5            3
5   9     6      0.6            3
6   4     7      0.7            4
7   13    8      0.8            4
8   6     9      0.9            4
9   18    10     1.0            5
3
sammywemmy 4 juin 2020 à 10:06

Encore une autre approche.

>>> df
   ID  Value  Percent Value
0  11      1            0.1
1  12      2            0.2
2  16      3            0.3
3  19      4            0.4
4  14      5            0.5
5   9      6            0.6
6   4      7            0.7
7  13      8            0.8
8   6      9            0.9
9  18     10            1.0
>>>
>>> percentage = np.array([30, 40, 60, 90, 100])
>>> pd.cut(df['Percent Value'], bins=[-np.inf, *percentage/100], labels=range(1, len(percentage) + 1))
0    1
1    1
2    1
3    2
4    3
5    3
6    4
7    4
8    4
9    5
Name: Percent Value, dtype: category
Categories (5, int64): [1 < 2 < 3 < 4 < 5]

pandas 1.0.3

3
timgeb 4 juin 2020 à 10:20

Utilisation de np.where comme instruction CASE:

# Initialise packages in session: 
import pandas as pd
import numpy as np

# Create data: df => data.frame
df = pd.DataFrame({'ID': [11, 12, 16, 19, 14, 9, 4, 13, 6, 18], 
                   'Value': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]})

# Percentage Dense ranke the value vector: Percent Value => float vector
df['Percent Value'] = df.reset_index()['Value'].rank(method = 'dense', pct = True)

# Conditionally define order vector: order => integer vector
df['order'] = np.where(
     df['Percent Value'].between(.0, .30, inclusive = True), 
    1, 
     np.where(
        df['Percent Value'].between(.31, .40, inclusive = True), 2,
         np.where(
             df['Percent Value'].between(.41, .59, inclusive = True), 3, 
             np.where(
                 df['Percent Value'].between(.60, .90, inclusive = True), 4, 5
                 )
             )
         )
     )

# Display data.frame: df => stdout (console)
print(df)
1
hello_friend 4 juin 2020 à 10:11

Vous pouvez utiliser np.select:

In [1695]: import numpy as np

In [1702]: conditions = [df['Percent Value'].le(0.30),\ 
  ...: (df['Percent Value'].gt(0.30) & df['Percent Value'].le(0.40)),\ 
  ...: (df['Percent Value'].gt(0.40) & df['Percent Value'].le(0.60)),\ 
  ...: (df['Percent Value'].gt(0.60)& df['Percent Value'].le(0.90)),\ 
  ...: (df['Percent Value'].gt(0.90) & df['Percent Value'].le(1))]

In [1694]: choices = [1,2,3,4,5]

In [1697]: df['Order'] = np.select(conditions, choices)

In [1698]: df 
Out[1698]:
   ID  Value  Percent Value  Order
0  11      1           0.10      1
1  12      2           0.20      1
2  16      3           0.30      1
3  19      4           0.40      2
4  14      5           0.50      3
5   9      6           0.60      3
6   4      7           0.70      4
7  13      8           0.80      4
8   6      9           0.90      4
9  18     10           1.00      5

Juste une comparaison des performances pour toutes les réponses:

Réponse de @ sammywemmy:

In [1723]: %timeit pd.cut(df['Percent Value'],bins=np.insert(percentage,0,0), labels = [1,2,3,4,5])
1.21 ms ± 57.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Réponse de @ timgeb:

In [1725]: %timeit pd.cut(df['Percent Value'], bins=[-np.inf, *percentage/100], labels=range(1, len(percentage) + 1)) 
1.02 ms ± 64.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Ma réponse:

In [1726]: %timeit np.select(conditions, choices) 
86 µs ± 3.4 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Je sais que l'écriture explicite des conditions est lourde, mais les performances de numpy sont très élevées. Veuillez vérifier les statistiques ci-dessus partagées par réponse.

2
Mayank Porwal 4 juin 2020 à 10:47