Избегайте итерации по каждой строке в Pandas для пользовательской агрегации - PullRequest
3 голосов
/ 07 марта 2019

Допустим, у меня есть пандас DataFrame с двумя столбцами: salary и food_perc (процент зарплаты, которую вы тратите на еду).Каждая строка соответствует отдельному человеку.

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)})

Я хочу новый столбец под названием food_compare, где для каждого человека я вижу, как его food_perc сравнивается с людьми с аналогичным доходом (+/- 10%).

Поскольку когорта +/- 10% будет отличаться для каждого человека, я не вижу способа избежать повторения в каждой строке и создания когорты каждый раз, как показано ниже.

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']))

Подмножество данных для каждой итерации на самом деле не является масштабируемым решением. К сожалению, я не могу предварительно создать статические корзины (например, 10 000 - 20 000 долларов, 20 001 - 30 000 долларов и т. Д.) Для проблемы, над которой я работаю.

Есть ли способ сделатькакой-то .groupby когда у вас нет дискретного ключа?В противном случае я не уверен, что делать, кроме, возможно, предварительной сортировки строк по salary и изменения шага поднабора, чтобы он не перебирал весь фрейм данных при создании когорты.Спасибо!

Ответы [ 2 ]

5 голосов
/ 07 марта 2019

Чтобы получить счетчик каждой группы пиров, вы можете использовать это:

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

Чтобы получить в среднем по группе равных 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())

Имейте в виду, что если у вас есть какие-либо элементы salary, равные нулю, и вы хотите, чтобы они были в одной группе, вам необходимо изменить выражение так:

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())
1 голос
/ 07 марта 2019

pd.cut был разработан для такого рода вещей: 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)))

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...