Disons que j'ai un pandas DataFrame avec deux colonnes: salary et food_perc (le pourcentage du salaire que vous dépensez pour la nourriture). Chaque ligne correspond à une personne différente.

import pandas as pd
import numpy as np

# Set seed
np.random.seed(1)

# Create dataframe
df = pd.DataFrame({'salary': np.round(np.random.uniform(10000, 100000, 100), 2),
                   'food_perc': np.round(np.random.uniform(0.1, 0.9, 100), 2)})

Je veux une nouvelle colonne appelée food_compare où, pour chaque personne, je vois comment leur food_perc se compare aux personnes ayant des revenus similaires (+/- 10%).

Parce que la cohorte +/- 10% sera différente pour chaque personne, je ne vois pas de moyen d'éviter d'itérer à travers chaque ligne et de créer la cohorte à chaque fois, comme ci-dessous.

for i in df.index:

    # Isolate the cohort
    df_sub = df[(df.loc[:, 'salary'] * 0.9 < df.loc[i, 'salary']) &
                (df.loc[:, 'salary'] * 1.1 > df.loc[i, 'salary'])]

    # Make the comparison
    df.loc[i, 'food_compare'] = np.divide(df.loc[i, 'food_perc'],
                                          np.mean(df_sub['food_perc']))

Le sous-ensemble de la trame de données pour chaque itération n'est vraiment pas une solution évolutive. Malheureusement, je ne peux pas créer de bacs statiques de manière préventive (par exemple, 10 000 $ - 20 000 $, 20 001 $ - 30 000 $, etc.) pour le problème sur lequel je travaille.

Existe-t-il un moyen de faire une sorte de .groupby lorsque vous n'avez pas de clé discrète? Sinon, je ne sais pas quoi faire, à part peut-être trier les lignes par salary au préalable et modifier l'étape de sous-ensemble afin qu'il ne recherche pas dans l'ensemble de la trame de données lors de la construction de la cohorte. Merci!

3
Matt Sosna 7 mars 2019 à 00:57

2 réponses

Meilleure réponse

Pour obtenir un compte de chaque groupe de pairs, vous pouvez utiliser ceci:

data['sal_peer_group_count'] = \
     data['salary'].apply(lambda x: len(data.loc[(data['salary']>.9*x) & \
                                       (data['salary']<1.1*x)]))

Pour obtenir la moyenne du groupe de pairs de sal_perc

data['peer_group_food_perc_mean'] = \
     data['salary'].apply(lambda x: data.loc[(data['salary'] >.9*x) & \
                                             (data['salary'] < 1.1*x), 'food_perc'].mean())

Gardez à l'esprit que si vous avez des éléments de salary qui sont égaux à zéro et que vous souhaitez qu'ils soient dans le même groupe, vous devrez modifier l'instruction pour qu'elle soit:

data['peer_group_food_perc_mean'] = \
     data['salary'].apply(lambda x: data.loc[(data['salary'] >.9*x) & \
                                             (data['salary'] < 1.1*x) \
                                              if x != 0 else \
                                              (data['salary'] == 0), 'food_perc'].mean())
6
Natalie Olivo 24 juin 2019 à 02:45

pd.cut a été conçu pour ce genre de chose : http://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.cut.html

df.groupby(pd.cut(df["salary"], np.arange(0, df["salary"].max(), 1.0e5)))

1
rgk 6 mars 2019 à 22:02