Как заменить лямбду и группировку для повышения производительности с помощью Pandas DataFrame - PullRequest
0 голосов
/ 28 октября 2018

Возможно, мой вопрос выглядит сложным, но по сути простым. Я новичок в Python, и теперь я сталкиваюсь с проблемой слишком медленного кода. Ниже приведена оптимизированная версия кода. Буду благодарен за небольшой обзор кода и рекомендации по его ускорению. Я думаю, что самые медленные операции - .apply(lambda и группировка, но я не знаю, как их заменить.

...
for raw_file in raw_files:
    reader = pd.read_csv(raw_file, chunksize=100000)
    for chunk in reader:
        processed_data = task(chunk)
        for name, data in processed_data:
            save_data(name, data) # some method which saves DataFrame correctly
...


def task(data):
    data = data[data['Quantity'] != 0] # remove zero items
    # add date parts as columns
    data[['dt_year', 'dt_month', 'dt_day', 'dt_day_of_year', 'dt_day_of_week', 'dt_hour']] = \
                data.apply(lambda df: to_date_parts(df['SalesDate']), axis=1)
    # group by location-item to aggregate in different files
    grouped = data.groupby(['LocationID','ItemID'])
    result = []
    for name, group in grouped:
        result += [(name, group)]
    return result



def to_date_parts(str_date):
    date = dt.datetime.strptime(str_date.split(".")[0], '%Y-%m-%d %H:%M:%S')
    dt_year = date.year
    dt_month = date.month
    dt_day = date.day
    dt_day_of_year = date.toordinal() - dt.datetime(date.year, 1, 1).toordinal() + 1
    dt_day_of_week = date.weekday()
    dt_hour = date.hour
    return pd.Series([dt_year, dt_month, dt_day, dt_day_of_year, dt_day_of_week, dt_hour])

1 Ответ

0 голосов
/ 28 октября 2018

Питон datetime против Панд datetime

Есть две взаимосвязанные причины, по которым вы видите низкую производительность:

  1. Вы используете встроенные в Python datetime объекты вместо эффективных серий Pandas datetime для хранения дат.
  2. Вы используете петли for уровня Python вместо векторизованных операций, поддерживаемых сериями Pandas datetime.

Итак, сначала преобразуйте вашу серию в серию Панд datetime:

date_format = '%Y-%m-%d %H:%M:%S'
df['SalesDate'] = pd.to_datetime(df['SalesDate'], format=date_format, errors='coerce')

Затем извлеките атрибуты прямо из вашей серии:

from operator import attrgetter

# list attributes
fields = ['year', 'month', 'day', 'dayofyear', 'dayofweek', 'hour']

# extract attributes
attributes = pd.concat(attrgetter(*fields)(df['SalesDate'].dt), axis=1, keys=fields)

# join attributes to dataframe
df = df.join(attributes)

Панды GroupBy объекты

Это объединение элементов в list не нужно:

grouped = data.groupby(['LocationID','ItemID'])
result = []
for name, group in grouped:
    result += [(name, group)]
return result

Поскольку data.groupby(...) является итеративным, вы можете просто return объект GroupBy:

return data.groupby(['LocationID','ItemID'])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...