Слияние панд данных Фреймы данных используют слишком много памяти - PullRequest
0 голосов
/ 08 октября 2018

Я работаю над этим соревнованием Kaggle как финальным проектом для курса, который я беру, и для этого я пытался скопировать этот ноутбук , но естьфункция, которую он использует, чтобы получить отстающие функции, которые просто используют слишком много памяти для меня.Вот его код:

def lag_feature(df, lags, col):
    tmp = df[['date_block_num','shop_id','item_id',col]]
    for i in lags:
        shifted = tmp.copy()
        shifted.columns = ['date_block_num','shop_id','item_id', col+'_lag_'+str(i)]
        shifted['date_block_num'] += i
        df = pd.merge(df, shifted, on=['date_block_num','shop_id','item_id'], how='left')
    return df

После неудачного запуска с его кодом я сделал несколько небольших изменений, чтобы попытаться уменьшить использование памяти, и я начал использовать Google Colab, потому что он имеет больше памяти, чем мой ноутбук, поэтому здесьмой код:

def lag_feature(df, lags, col):
  df = dd.from_pandas(df, chunksize=1000)
  tmp = df[['date_block_num','shop_id','item_id',col]]
  for i in lags:
    shifted = tmp[tmp.date_block_num + i <= 34].copy()
    shifted.columns = ['date_block_num','shop_id','item_id', col+'_lag_'+str(i)]
    shifted['date_block_num'] += i
    df = dd.merge(df, shifted, on=['date_block_num','shop_id','item_id'], how='left')
  return df.compute()

Но все еще использует слишком много памяти, дошло до того, что мой код использовал 10 ГБ памяти, которую Google предлагает для вызова этой функции

sales_train = lag_feature(sales_train, [1, 2, 3, 12, 20], 'item_cnt_month')

есть ли способы уменьшить использование памяти?Просто чтобы показать, что это мой фрейм данных:

Int64Index: 2829445 entries, 0 to 3134798
Data columns (total 8 columns):
date                object
date_block_num      int8
item_cnt_day        float16
item_id             int16
item_price          float16
shop_id             int8
item_cnt_month      float16
item_category_id    int8
dtypes: float16(3), int16(1), int8(3), object(1)
memory usage: 152.9+ MB

Просто чтобы добавить больше информации, в столбце date_block_num хранится число, которое определяет, в каком месяце произошла эта функция, и я пытаюсь получить несколькоданные за предыдущий месяц в эту строку.Итак, если у меня была задержка 1, это означает, что я хочу получить данные за месяц назад для каждого продукта в моем фрейме данных и добавить их в другой столбец с именем «feature_lag_1».Например, с этим фреймом данных:

         date  date_block_num  item_cnt_day  item_id  item_price  shop_id  \
0  14.09.2013               8           1.0     2848        99.0       24   
1  14.09.2013               8           1.0     2848        99.0       24   
2  14.09.2013               8           1.0     2848        99.0       24   
3  01.09.2013               8           1.0     2848        99.0       24   
4  01.09.2013               8           1.0     2848        99.0       24   

   item_cnt_month  item_category_id
0             2.0                30
1             2.0                30 
2             2.0                30 
3             2.0                30 
4             2.0                30

и вызовом этой функции:

sales_train = lag_feature(sales_train, [1], 'item_cnt_month')

Я хочу этот вывод:

         date  date_block_num  item_cnt_day  item_id  item_price  shop_id  \
0  14.09.2013               8           1.0     2848        99.0       24   
1  14.09.2013               8           1.0     2848        99.0       24   
2  14.09.2013               8           1.0     2848        99.0       24   
3  01.09.2013               8           1.0     2848        99.0       24   
4  01.09.2013               8           1.0     2848        99.0       24   

   item_cnt_month  item_category_id  item_cnt_month_lag_1  
0             2.0                30                   3.0  
1             2.0                30                   3.0  
2             2.0                30                   3.0  
3             2.0                30                   3.0  
4             2.0                30                   3.0  

Ответы [ 3 ]

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

Функция может быть переписана в Python 3.6+ следующим образом (требуется предварительная сортировка кадра данных):

df = df.sort_values(['date_block_num']).reset_index(drop=True)

def lag_feature(df, lags, col):
    key_columns = ['shop_id', 'item_id']
    for lag in lags:
        all_but_col = list(df.columns.difference([col]))
        df[f'{col}_lag_{lag}'] = (df.set_index(all_but_col)
                                    .groupby(level=key_columns)
                                    .shift(lag)
                                    .reset_index(drop=True))
    return df
0 голосов
/ 11 октября 2018

Проблема памяти, с которой вы сталкиваетесь, может быть связана с наличием нескольких (под) копий одного и того же кадра данных.Нет необходимости делать это в пандах, как все остальные указывали, функция .shift может достичь того, что вам нужно.

Сначала создайте информационный фрейм панд, в котором есть два магазина, то есть 24 и 25.

df = pd.DataFrame({'shop_id':[24, 24, 24, 24, 24, 25, 25, 25, 25, 25],
                   'item_id': [2000, 2000, 2000, 3000, 3000, 1000, 1000, 1000, 1000, 1000], 
                   'date_block_num': [7, 8, 9, 7, 8, 5, 6, 7, 8, 9], 
                   'item_cnt_month': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]})

+-------+-------+--------------+--------------+
|shop_id|item_id|date_block_num|item_cnt_month|
+-------+-------+--------------+--------------+
|     24|   2000|             7|             1|
|     24|   2000|             8|             2|
|     24|   2000|             9|             3|
|     24|   3000|             7|             4|
|     24|   3000|             8|             5|
|     25|   1000|             5|             6|
|     25|   1000|             6|             7|
|     25|   1000|             7|             8|
|     25|   1000|             8|             9|
|     25|   1000|             9|            10|
+-------+-------+--------------+--------------+

В магазине 24 есть пункты 2000 и 3000.

Есть1 счет элемента 2000 в блоке дат 7, 2 счет блока 8 и т. Д.

Цель состоит в том, чтобы создать столбец задержки item_cnt_month, который имеет значение item_cnt_month n месяцев назад, для этого элемента в этом магазине,

Чтобы создать функции задержки, вы можете использовать функцию ниже.

def lag_features(df, lags, group_cols, shift_col):
    """
    Arguments:
        df (pd.DataFrame)
        lags (list((int)): the number of months to lag by
        group_cols (list(str)): the list of columns that need to be the merged key
        shift_col (str): the column name that is to be shifted by
    """

    for lag in lags:
        new_col = '{0}_lag_{1}'.format(shift_col, lag)
        df[new_col] = df.groupby(group_cols)[shift_col].shift(lag)

    return df

Путем вызова

lags = [1, 2]
group_cols = ['shop_id', 'item_id']
shift_col = 'item_cnt_month'
order_col = 'date_block_num' 

df = df.sort_values(by=group_cols+[order_col], ascending=True)
df = lag_features(df, lags, group_cols, shift_col)

В результате получается следующее:

+-------+-------+--------------+--------------+--------------------+--------------------+
|shop_id|item_id|date_block_num|item_cnt_month|item_cnt_month_lag_1|item_cnt_month_lag_2|
+-------+-------+--------------+--------------+--------------------+--------------------+
|     24|   2000|             7|             1|                 NaN|                 NaN|
|     24|   2000|             8|             2|                 1.0|                 NaN|
|     24|   2000|             9|             3|                 2.0|                 1.0|
|     24|   3000|             7|             4|                 NaN|                 NaN|
|     24|   3000|             8|             5|                 4.0|                 NaN|
|     25|   1000|             5|             6|                 NaN|                 NaN|
|     25|   1000|             6|             7|                 6.0|                 NaN|
|     25|   1000|             7|             8|                 7.0|                 6.0|
|     25|   1000|             8|             9|                 8.0|                 7.0|
|     25|   1000|             9|            10|                 9.0|                 8.0|
+-------+-------+--------------+--------------+--------------------+--------------------+

Обратите внимание, что, поскольку явного объединения нет, необходимо правильно упорядочить кадр данных.используя .sort_values(all key columns and date column)

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

Вызов df.compute() превращает ваш полный результат в кадр данных Pandas, поэтому, если ваш результат не помещается в память, Dask здесь вам не поможет.

Вместо этого чаще не вызывать вычисленияи вместо этого, в конце концов, вычислить некую агрегацию, которая хорошо помещается в памяти, или, если вам нужен полный фрейм данных, записать его на диск с чем-то вроде df.to_parquet()

...