1. Обзор
- Walmart — это хорошо известная розничная сеть, работающая во многих странах. Walmart хочет предсказать продажи своих быстроходных товаров, особенно во время сильного снегопада, дождя или любых других экстремальных погодных условий.
- Компания хочет, чтобы мы прогнозировали продажи 111 товаров для 45 магазинов. Каждый магазин связан с метеостанцией, а всего таких станций 20.
- Этот прогноз продаж поможет менеджеру по запасам поддерживать запасы, чтобы избежать их отсутствия или избытка во время или после шторма.
- Целью этого тематического исследования является прогнозирование продаж товаров до и после любого погодного явления; где погодное событие представляет экстремальные погодные условия. Например, в любой день, когда выпало более 2 дюймов снега, или в любой дождливый день, когда выпало более 1 дюйма дождя или около того. Таким образом, мы поможем менеджеру запасов заказать достаточное количество товара в таких погодных условиях в течение +/- 3 дней.
- Данные о продажах не фиксируют разницу между запасами и спросом. Другими словами, количество продаж 0 не обязательно означает, что на этот продукт не было спроса; это может означать, что товар был в наличии, но ни один из них не был продан, или это может означать, что товар отсутствует на складе или снят с производства и недоступен.
- Набор данных состоит из —
- Train.csv — этот файл содержит количество проданных единиц для всех комбинаций магазинов/товаров/дат.
- Test.csv — этот файл содержит магазины/элементы/даты для прогнозирования.
- Key.csv — этот файл содержит взаимосвязь между номером станции и магазинами.
- Weather.csv — этот файл содержит информацию о погоде на уровне дня/станции и множество категориальных характеристик, представляющих тип события, таких как FZ (заморозки), SN (снег), RN (дождь) и т. д., а также числовые характеристики, такие как осадки (измерение дождя в дюймы) снегопад (измерение снегопада в дюймах) и т. д.
8. Это в основном проблема регрессии. Метрика для оценки предоставляется как RMSLE. Итак, мы будем работать с RMSLE в качестве метрики.
9. Деловые ограничения —
- Низкая задержка не требуется.
- Цена ошибки будет высокой, так как это приведет к неправильному прогнозу, что, в свою очередь, приведет к избыточным или коротким акциям.
2. Понимание разницы между RMSE и RMSLE
RMSE означает корень из среднего квадрата ошибок.
RMSE имеет много недостатков
- Он не устойчив к выбросам.
- Это не относительный показатель, т. е. величина чисел будет влиять на результаты.
- Штрафы не имеют смещения в сторону недооценки по сравнению с завышением.
Чтобы справиться со всеми этими недостатками, будет использоваться RMSLE, и он преодолел все вышеупомянутые недостатки. Вот форум для RMSLE
pi: предсказанные значения; ai: фактические значенияn: количество точек данных
- В то время как на RMSE сильно влияют выбросы, с другой стороны, на RMSLE не влияют такие большие значения, поскольку логарифмическая шкала обрабатывает высокие значения.
- RMSLE использует логарифмическое свойство как log(x) — log(y) = log(x/y); это означает, что окончательное значение рассчитывается относительно напр. Это не будет иметь никакого значения, если фактическое и прогнозируемое значения равны (100,90) или (10000,9000), но значение RMSLE останется прежним.
- RMSLE подвергается большему штрафу за недооценку фактической переменной, чем за переоценку. Если значение (x/y) меньше, то конечные значения log(‹1) будут больше, чем log(›1).
3. Загрузка наборов данных:
- Набор данных ключей:
keys_df = pd.read_csv(“key.csv”)
- Набор данных о погоде:
#Loading weather data with missing values. missing_values = ["M","-","*" ] weather_df = pd.read_csv("weather.csv" , na_values = missing_values )
# Weather data has some values represented as " T" which means that on that perticular day there were immeasurable traces of snowfall or of preciptotal(rain)Hence by using this function we are changing the values of T to 0.001 def change_snowfall(x): if x == " T": return 0.001 else: return float(x) def change_preciptotal(x): if x == " T": return 0.001 else: return float(x) # Applying the above written functions on snowfall & preciptotal. weather_df["snowfall"] = weather_df["snowfall"].map(change_snowfall) weather_df["preciptotal"]= weather_df["preciptotal"].map(change_preciptotal) # Chaning the datatype of snowfall and date columnweather_df['snowfall'] = weather_df["snowfall"].astype(float) weather_df["date"] = weather_df["date"].map(pd.to_datetime)
Столбец Codesum представляет конкретный код погодных условий в течение дня. здесь мы преобразуем коды в двоичный вектор с 1-горячим кодированием для каждого кода.
# making a set of values of the "codesum" column. unique_codesum = set(' '.join( set(weather_df["codesum"].map(str) )).strip().split()) print("total unique codesum is : ", len(unique_codesum)) print("Unique codes are : \n " , unique_codesum) # from pandas.core.arrays.categorical import contains cond = ( weather_df["codesum"].str.contains('FG+' , na = False) ) weather_df.loc[cond]
# Filling the values of the codesum_df dataframe before merging it with weather_df with 1-hot encoding. # for all the unique codes for col in codesum_df.columns: # for every row of the codesum_df for i in range(len(codesum_df.index)): if str(col) in str(weather_df["codesum"][i]): codesum_df[col][i] = 1 codesum_df.head()
- Обучение набора данных:
train_df = pd.read_csv("train.csv") train_df["date"] = train_df["date"].map(pd.to_datetime) train_df.head()
Теперь нам нужно объединить эти наборы данных и объединить их в один для выполнения EDA и обработки нулевых значений и дальнейшей обработки.
temp_df = pd.merge(keys_df , train_df , on = ["store_nbr"] ) final_df = pd.merge(temp_df , weather_df , on = ['station_nbr','date'] )
4. ЭДА
График различных столбцов данных о погоде, чтобы проверить, есть ли какая-либо годовая закономерность в сравнении с данными о продажах для некоторой даты/станции/уровня предметов.
Я использовал поле station_nbr вместо store_nbr, потому что с 1 станцией связано много магазинов, а данные сильно несбалансированы, поэтому получить запись, в которой продажи больше нуля, очень редко.
print("number of sales Not equals to zero ",final_df[final_df.units > 0 ].shape[0] , round(100*(final_df[final_df.units > 0 ].shape[0] / final_df.shape[0]),2) , " percent ") print("number of sales equals to zero ",final_df[final_df.units == 0 ].shape[0] , round(100*(final_df[final_df.units == 0 ].shape[0] / final_df.shape[0]),2 ) , " percent") print("__"*100)
На приведенных выше рисунках делается вывод о том, что данные о продажах сильно несбалансированы. В будущем мы увидим, как бороться с таким несбалансированным набором данных с нулевым завышением.
Блочная диаграмма для понимания «продаж» в магазине
Заключение :
- Ось X показывает номер магазина, а ось Y показывает количество проданных товаров.
- Глядя на диаграмму для магазина, мы можем понять, что большая часть продаж для всех магазинов близка к нулю.
2. Только 4–5 магазинов могли пересечь проданное количество более 300 штук.
3. Магазин № 39 имеет наименьшие продажи, а магазины № 16, 17 и 33 демонстрируют самые высокие продажи.
4. Нам нужно проверить блок-график, отфильтровав данные с проданным количеством больше нуля.
Box Plot с количеством проданных товаров больше нуля и сгруппированным по магазинам.
Заключение :
1. Теперь мы видим, что только для 5 магазинов IQR пересекает отметку в 100 шт. Это магазины 2, 16, 17, 30, 33.
2. Для магазина 39 максимальная стоимость продажи ниже 60.
3. Кажется, что магазин 33 является высокопроизводительным магазином, потому что его IQR составляет от 50 до 180 единиц.
Коробчатая диаграмма для понимания «продаж» по каждой позиции
Заключение:
1. Из 111 наименований только у 16 наименований продажи составляют более 100 единиц, у большинства наименований продажи менее 100 единиц.
2. Элементы 48 и 102 показывают наименьшее значение Slaes для коробчатых диаграмм.
3. Пункты 49, 5 и 9 показывают, что IQR выше 0.
4. Нам нужно установить флажок на графике с отфильтрованными данными, где проданное количество будет больше нуля.
После наблюдения за приведенным выше графиком, выбора магазина и товаров, которые показали некоторые измеримые продажи, и построения графика распределения проданных единиц для различных погодных условий.
График продаж для столбца «preciptotal», номера магазина и некоторых случайных предметов.
Заключение :
- распределение осадков в течение года показывает, что в отдельные дни для станции № 3 это значение больше нуля.
- Для насыщения номер 3 объем продаж по годам составляет от 300 до 1000.
- Для товара № 5 и станции № 3 продажи в основном колеблются от 0 до 100.
- Для товара № 8 и станции № 3 продажи в основном колеблются от 0 до 100.
- Для товара № 44 и станции № 3 продажи в основном колеблются от 200 до 500.
- Для товара № 45 и станции № 3 продажи в основном колеблются от 0 до 100.
- Для товара № 95 и станции № 3 продажи почти равны нулю.
- Для товара № 25 и станции № 3 продажи почти равны нулю.
- Между «предварительным итогом» и продажами товаров видна корреляция.
Таким же образом мы можем построить модель продаж для различных погодных условий, магазина и номера товара, чтобы понять влияние погодных условий на продажи.
Поскольку эти данные очень случайны и очень несбалансированы, мы не получаем никакой визуальной закономерности продаж для комбинации магазин/товар/дата.
Чтобы проверить разные участки для разных погодных условий, вы можете перейти в раздел EDA этой записной книжки ссылка.
После удаления дубликатов и выбросов и обработки нулевых значений с помощью опции «bfill» с помощью метода fillna мы можем перейти к моделированию.
5. Особенности
В существующий фрейм данных добавляются новые функции: «дата», «год», «месяц», «неделя месяца», «день недели» и т. д.
def extract_date_features(df): ''' This function extracts the date feature from date column ''' df['date']= pd.to_datetime(df['date']) df['date_year'] = df['date'].dt.year #Year df['date_month'] = df['date'].dt.month #Month df['date_week'] = df['date'].dt.week #Week df['date_day'] = df['date'].dt.day #Day # df['date_hour'] = df['date'].dt.hour #Hour # df['date_minute'] = df['date'].dt.minute #minute df['date_dayofweek'] = df['date'].dt.dayofweek #dayofweek df['date_is_weekend'] = np.where(df['date_dayofweek'].isin(['Sunday', 'Saturday']), 1,0) #date is weekend or not df['date_week'] = df['date'].dt.week #week of the year df['quarter'] = df['date'].dt.quarter #Quater of the year df['semester'] = np.where(df['quarter'].isin([1,2]), 1, 2) #semester of the year # df.drop(['date'], axis=1, inplace=True) return df
6. Моделирование
Как мы видели, наш набор данных сильно несбалансирован, ненулевое количество составляет всего ~ 2,5%, а продажи с нулевым количеством составляют почти 97,5%. Чтобы иметь дело с таким набором данных, мы можем использовать Zero Inflated Regressor, который разделяет данные с нулевым количеством и ненулевым количеством.
Чтобы узнать больше о Zero Inflated Regressor, перейдите по этой ссылке.
zir = ZeroInflatedRegressor( classifier=RandomForestClassifier(), regressor= RandomForestRegressor()#LinearRegression() ) zir.fit(X_trains , y_trains)
Ниже приведен результат для этой подгонки, а RMSLE составляет 0,554.
После применения регрессии XGBOOST я получил лучшую производительность модели с RMSLE 0,0486
В таблице представлены результаты различных регрессионных моделей.
7. Заключение
Ребята считают, что эти простые методы характеристики помогли мне превзойти результаты исследовательской работы.Я наконец получил показатель RMSLE 0,0486.
Надеюсь вам, ребята, нравится это!!
Я действительно хочу, чтобы вы попробовали это на своем конце и прокомментировали свои оценки и какие различные функции вы использовали для этого. Все комментарии мы приветствуем здесь !!
Ссылки
- https://appliedaicourse.com
- https://charmila1997.medium.com/sales-prediction-98e0263b185e
- https://notebook.community/ternaus/kaggle_wallmart/Wallmart_analysis
- https://github.com/threecourse/kaggle-walmart-recruiting-sales-in-stormy-weather
- Для полного блокнота, пожалуйста, нажмите на ссылку ниже
https://gist.github.com/arunbohare/86b5057b512beaec896bb1ee22476fc2