Unlocking Insights from Walmart‘s Sales Data Through Visualization

As one of the world‘s largest retailers, Walmart collects a treasure trove of sales data across its many stores, departments, and products. Properly analyzing this data can yield valuable insights to help the company better forecast sales, optimize inventory, and make strategic business decisions. In this article, we‘ll walk through the process of examining a Walmart sales dataset using Python and various data visualization techniques to uncover key patterns and trends.

The Data Analysis Process

Before diving into the code, let‘s review the high-level steps we‘ll follow:

  1. Data collection – Obtain the relevant Walmart sales data in CSV format. Here we‘ll be working with separate files for training data, store information, features, and test data.

  2. Data cleaning – Explore the raw data to check for missing values, inconsistent formatting, irrelevant columns, etc. Clean and preprocess the data to get it into a suitable format for analysis.

  3. Data integration – Combine data from multiple tables as needed to bring in store details, holiday flags, and other relevant attributes.

  4. Data transformation – Manipulate the data by calculating new fields, aggregating records, or converting data types (e.g. converting date strings to datetime objects).

  5. Data visualization – Create charts and plots to visually represent the data and reveal insights not easily spotted in the raw numbers. We‘ll use libraries like Matplotlib, Seaborn, and Plotly.

  6. Insight interpretation – Analyze the visualizations and extracted metrics to derive meaningful, actionable conclusions about Walmart‘s sales trends that can inform business decisions.

By following this process, we can methodically explore the sales data to gauge the health of the business, identify top performing and underperforming segments, and generate ideas for improvement. The cleaned, transformed dataset will also be in good shape for training a machine learning model to forecast future sales.

Loading and Preparing the Data

Let‘s start by importing the necessary Python libraries and reading in the CSV files:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
import plotly.graph_objs as go

train_df = pd.read_csv(‘train.csv‘) 
features_df = pd.read_csv(‘features.csv‘)
stores_df = pd.read_csv(‘stores.csv‘)
test_df = pd.read_csv(‘test.csv‘)

We can inspect the first few rows of each dataframe using .head() to get a sense of the data:

train_df.head()

Gives us:

Store Dept Date Weekly_Sales IsHoliday
0 1 1 2010-02-05 24924.50 False
1 1 1 2010-02-12 46039.49 True
2 1 1 2010-02-19 41595.55 False
3 1 1 2010-02-26 19403.54 False
4 1 1 2010-03-05 21827.90 False

We can see the training data contains the store number, department number, date, weekly sales, and a boolean flag for whether the week included a holiday.

The shape of the training data shows it has 421,570 rows and 5 columns:

train_df.shape

(421570, 5)

Looking at the .info() output, we see the date column is stored as a string (object) datatype. We‘ll want to convert that to a proper datetime for easier manipulation later.

The .describe() summary statistics don‘t reveal any obvious outliers or issues. We can also check for null values:

train_df.isnull().sum()

Store            0
Dept             0
Date             0
Weekly_Sales     0
IsHoliday        0
dtype: int64

Looks like this training set is clean and complete, with no missing values to handle. Let‘s move on to inspecting the other dataframes.

features_df has additional data for each date and store, like temperature, fuel price, promotional markdowns, CPI, and unemployment rates:

Store Date Temperature Fuel_Price MarkDown1 MarkDown2 MarkDown3 MarkDown4 MarkDown5 CPI Unemployment IsHoliday
0 1 2010-02-05 42.31 2.572 NaN NaN NaN NaN NaN 211.0 8.106 False
1 1 2010-02-12 38.51 2.548 NaN NaN NaN NaN NaN 211.2 8.106 True
2 1 2010-02-19 39.93 2.514 NaN NaN NaN NaN NaN 211.3 8.106 False
3 1 2010-02-26 46.63 2.561 NaN NaN NaN NaN NaN 211.3 8.106 False
4 1 2010-03-05 46.50 2.625 NaN NaN NaN NaN NaN 211.3 8.106 False

The store details dataframe contains the store type and size in square feet:

stores_df.head()
Store Type Size
0 1 A 151315
1 2 A 202307
2 3 B 37392
3 4 A 205863
4 5 B 34875

Finally, the test set has the same structure as the training set but without the Weekly_Sales column. We‘ll use this later to evaluate our forecasting model after training it on the train set.

Data Visualization

Now that we‘ve loaded and validated the data, let‘s start visualizing it to spot interesting patterns. We‘ll use Seaborn and Plotly for interactive plots.

First, let‘s look at the distribution of store types:

labels = stores_df["Type"].value_counts().index
values = stores_df["Type"].value_counts().values

fig = go.Figure(data=[go.Pie(labels=labels, values=values)])
fig.show()

The resulting pie chart shows that Type A stores are most common, followed by Type B, with Type C making up the smallest proportion.

Next, let‘s merge the store details with the features data on the Store column so we have the store type available for further analysis:

dataset = features_df.merge(stores_df, how=‘inner‘, on=‘Store‘)

We‘ll convert the Date column to datetime:

dataset[‘Date‘] = pd.to_datetime(dataset[‘Date‘])

And add some new columns for the week and year of each record based on the date:

dataset[‘Week‘] = dataset.Date.dt.week
dataset[‘Year‘] = dataset.Date.dt.year

Merging this dataset with the training and test sets will let us slice the sales data by time period and store attributes.

After merging, we can visualize average weekly sales by department to see which categories generate the most revenue:

weekly_sales = train_merge[‘Weekly_Sales‘].groupby(train_merge[‘Dept‘]).mean()

plt.figure(figsize=(25,12))
sns.barplot(x=weekly_sales.index, y=weekly_sales.values, palette=‘dark‘)
plt.title(‘Average Sales per Department‘, fontsize=20)
plt.xlabel(‘Department‘, fontsize=16)
plt.ylabel(‘Sales‘, fontsize=16)
plt.show()

This shows that departments in the 90s tend to be top sellers. We could dive deeper to find the specific categories, but this gives a high level view.

Similarly, we can compare average sales across stores and see that Store 20 is a top performer:

weekly_sales = train_merge[‘Weekly_Sales‘].groupby(train_merge[‘Store‘]).mean()

plt.figure(figsize=(20,12))  
sns.barplot(x=weekly_sales.index, y=weekly_sales.values, palette=‘dark‘)
plt.title(‘Average Sales per Store‘, fontsize=20)
plt.xlabel(‘Store‘, fontsize=16)  
plt.ylabel(‘Sales‘, fontsize=16)
plt.show()

Plotting average weekly sales over time reveals some seasonal trends, like spikes around the holidays each year:

weekly_sales_2010 = train_merge[train_merge[‘Year‘]==2010][‘Weekly_Sales‘].groupby(train_merge[‘Week‘]).mean()
weekly_sales_2011 = train_merge[train_merge[‘Year‘]==2011][‘Weekly_Sales‘].groupby(train_merge[‘Week‘]).mean()
weekly_sales_2012 = train_merge[train_merge[‘Year‘]==2012][‘Weekly_Sales‘].groupby(train_merge[‘Week‘]).mean()

plt.figure(figsize=(20,8))
sns.lineplot(x=weekly_sales_2010.index, y=weekly_sales_2010.values)
sns.lineplot(x=weekly_sales_2011.index, y=weekly_sales_2011.values)  
sns.lineplot(x=weekly_sales_2012.index, y=weekly_sales_2012.values)
plt.title(‘Average Weekly Sales Per Year‘, fontsize=20)
plt.xlabel(‘Week‘, fontsize=16)
plt.ylabel(‘Sales‘, fontsize=16)
plt.legend([‘2010‘, ‘2011‘, ‘2012‘])
plt.show()

To see how different factors relate to sales, we can make a scatter plot for each variable:

def scatter(train_merge, column):
    plt.figure()
    plt.scatter(train_merge[column], train_merge[‘Weekly_Sales‘])
    plt.ylabel(‘Weekly_Sales‘)
    plt.xlabel(column)

scatter(train_merge, ‘Temperature‘) 
scatter(train_merge, ‘Fuel_Price‘)
scatter(train_merge, ‘CPI‘)
scatter(train_merge, ‘Unemployment‘)
scatter(train_merge, ‘Size‘)

These show a slight positive correlation between temperature and sales, while CPI and unemployment have a slight negative correlation. Store size also seems to have a positive relationship with sales, as we might expect.

Feature Selection and Model Prep

As a final step before building our forecasting model, let‘s check for correlations between the features that could introduce bias:

plt.figure(figsize=(12,10))
sns.heatmap(train_merge.corr(), annot=True, fmt=‘.2f‘, cmap=‘coolwarm‘, center=0)
plt.show()  

The heatmap shows that the various markdown fields are highly correlated with each other. To reduce multicollinearity, we‘ll drop these along with Fuel_Price which also shows high correlations:

train_merge = train_merge.drop(columns=[‘Fuel_Price‘, ‘MarkDown1‘, ‘MarkDown2‘, ‘MarkDown3‘, ‘MarkDown4‘, ‘MarkDown5‘])
test_merge = test_merge.drop(columns=[‘Fuel_Price‘, ‘MarkDown1‘,  ‘MarkDown2‘, ‘MarkDown3‘, ‘MarkDown4‘, ‘MarkDown5‘])

Conclusion and Next Steps

In this analysis, we walked through the process of loading, cleaning, transforming, and visualizing a Walmart sales dataset. Some key takeaways:

  • The data required some cleaning and type conversions to prepare it for analysis
  • Merging the separate tables allowed us to slice the data by time period and store attributes
  • Visualizations revealed top selling categories, stores, and seasonal sales trends
  • Scatter plots showed relationships between sales and factors like price, unemployment, and temperature
  • A correlation heatmap allowed us to identify redundant features to drop before modeling

With the dataset now cleaned and transformed, we‘re ready to move on to building a model to forecast future sales. Techniques like time series analysis and regression could help predict demand to optimize inventory and staffing.

The complete code for this analysis is available on GitHub: https://github.com/yourusername/walmart-sales-analysis

I hope this article helped demonstrate the value of visualization for deriving insights from raw data. Feel free to connect with me on LinkedIn with any questions or feedback!

How useful was this post?

Click on a star to rate it!

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.

Similar Posts