Introduction

This statistical analysis examines the Chocolate Sales dataset to identify sales patterns, customer demand, and business performance across different countries, products, and salespersons. The dataset includes key variables such as sales amount, boxes shipped, product type, country, salesperson, and transaction date. The analysis begins with data cleaning and descriptive statistics to understand the characteristics of the dataset. It then applies various statistical techniques and visualisations, including histograms, boxplots, scatter plots, bar charts, correlation analysis, regression, and hypothesis testing. The findings provide valuable insights into sales trends, product performance, regional differences, and factors influencing revenue, supporting informed business decision-making.

Aim

The aim of this study is to perform a comprehensive statistical analysis of the Chocolate Sales dataset to identify sales patterns, evaluate product and salesperson performance, examine regional sales differences, and investigate the relationship between sales amount and boxes shipped using descriptive statistics, data visualisation, and inferential statistical techniques.

Objectives

To clean and prepare the Chocolate Sales dataset for statistical analysis. To summarise the dataset using descriptive statistical measures such as mean, median, standard deviation, and frequency distributions. To analyse sales performance across different countries, products, and salespersons. To identify trends in sales and shipments over time using date-based analysis. To examine the relationship between sales amount and boxes shipped through correlation and regression analysis. To compare sales performance among countries and products using appropriate statistical tests such as ANOVA and t-tests. To present the findings through effective data visualisations and provide business insights for decision-making.

##Research Questions What are the key characteristics of the Chocolate Sales dataset based on descriptive statistics? Which countries, products, and salespersons generate the highest sales revenue? How do chocolate sales vary over different time periods? Is there a significant relationship between the number of boxes shipped and the sales amount? Are there significant differences in sales performance across countries and product categories? What business insights can be obtained from the statistical analysis and visualisation of the Chocolate Sales dataset?

#Load Libraries

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.2.1     ✔ readr     2.2.0
## ✔ forcats   1.0.1     ✔ stringr   1.6.0
## ✔ ggplot2   4.0.3     ✔ tibble    3.3.1
## ✔ lubridate 1.9.5     ✔ tidyr     1.3.2
## ✔ purrr     1.2.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(lubridate)
library(psych)
## 
## Attaching package: 'psych'
## 
## The following objects are masked from 'package:ggplot2':
## 
##     %+%, alpha
library(skimr)
library(corrplot)
## corrplot 0.95 loaded
library(GGally)
library(PerformanceAnalytics)
## Loading required package: xts
## Loading required package: zoo
## 
## Attaching package: 'zoo'
## 
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
## 
## 
## ######################### Warning from 'xts' package ##########################
## #                                                                             #
## # The dplyr lag() function breaks how base R's lag() function is supposed to  #
## # work, which breaks lag(my_xts). Calls to lag(my_xts) that you type or       #
## # source() into this session won't work correctly.                            #
## #                                                                             #
## # Use stats::lag() to make sure you're not using dplyr::lag(), or you can add #
## # conflictRules('dplyr', exclude = 'lag') to your .Rprofile to stop           #
## # dplyr from breaking base R's lag() function.                                #
## #                                                                             #
## # Code in packages is not affected. It's protected by R's namespace mechanism #
## # Set `options(xts.warn_dplyr_breaks_lag = FALSE)` to suppress this warning.  #
## #                                                                             #
## ###############################################################################
## 
## Attaching package: 'xts'
## 
## The following objects are masked from 'package:dplyr':
## 
##     first, last
## 
## 
## Attaching package: 'PerformanceAnalytics'
## 
## The following object is masked from 'package:graphics':
## 
##     legend
library(viridis)
## Loading required package: viridisLite
library(scales)
## 
## Attaching package: 'scales'
## 
## The following object is masked from 'package:viridis':
## 
##     viridis_pal
## 
## The following objects are masked from 'package:psych':
## 
##     alpha, rescale
## 
## The following object is masked from 'package:purrr':
## 
##     discard
## 
## The following object is masked from 'package:readr':
## 
##     col_factor
library(plotly)
## 
## Attaching package: 'plotly'
## 
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## 
## The following object is masked from 'package:stats':
## 
##     filter
## 
## The following object is masked from 'package:graphics':
## 
##     layout
library(reshape2)
## 
## Attaching package: 'reshape2'
## 
## The following object is masked from 'package:tidyr':
## 
##     smiths

#Import Dataset

sales <- read.csv("C:/Users/User/Downloads/Chocolate Sales.csv", stringsAsFactors = FALSE)

#Data Cleaning

#Convert Amount to numeric

sales$Amount <- gsub("\\$", "", sales$Amount)
sales$Amount <- gsub(",", "", sales$Amount)
sales$Amount <- as.numeric(sales$Amount)

#Convert Date

sales$Date <- dmy(sales$Date)

#Convert categorical variables

sales$Country <- as.factor(sales$Country)
sales$Product <- as.factor(sales$Product)
sales$Sales.Person <- as.factor(sales$Sales.Person)

#If your column name contains a space

names(sales)
## [1] "Sales.Person"  "Country"       "Product"       "Date"         
## [5] "Amount"        "Boxes.Shipped"
names(sales)[1] <- "SalesPerson"

#Then

sales$SalesPerson <- as.factor(sales$SalesPerson)

#Missing Values

colSums(is.na(sales))
##   SalesPerson       Country       Product          Date        Amount 
##             0             0             0             0             0 
## Boxes.Shipped 
##             0
any(is.na(sales))
## [1] FALSE

#Duplicate Records

sum(duplicated(sales))
## [1] 0

#Descriptive Statistic

summary(sales)
##               SalesPerson         Country                   Product   
##  Kelci Walkden      : 54   Australia  :205   50% Dark Bites     : 60  
##  Brien Boise        : 53   Canada     :175   Eclairs            : 60  
##  Van Tuxwell        : 51   India      :184   Smooth Sliky Salty : 59  
##  Beverie Moffet     : 50   New Zealand:173   White Choc         : 58  
##  Dennison Crosswaite: 49   UK         :178   Drinking Coco      : 56  
##  Oby Sorrel         : 49   USA        :179   Spicy Special Slims: 54  
##  (Other)            :788                     (Other)            :747  
##       Date                Amount      Boxes.Shipped  
##  Min.   :2022-01-03   Min.   :    7   Min.   :  1.0  
##  1st Qu.:2022-03-02   1st Qu.: 2390   1st Qu.: 70.0  
##  Median :2022-05-11   Median : 4868   Median :135.0  
##  Mean   :2022-05-03   Mean   : 5652   Mean   :161.8  
##  3rd Qu.:2022-07-04   3rd Qu.: 8027   3rd Qu.:228.8  
##  Max.   :2022-08-31   Max.   :22050   Max.   :709.0  
## 
describe(sales)
## Warning in FUN(newX[, i], ...): no non-missing arguments to min; returning Inf
## Warning in FUN(newX[, i], ...): no non-missing arguments to max; returning -Inf
##               vars    n    mean      sd median trimmed     mad min   max range
## SalesPerson*     1 1094   12.94    7.17   13.0   12.93    8.90   1    25    24
## Country*         2 1094    3.44    1.73    3.0    3.42    2.97   1     6     5
## Product*         3 1094   11.70    6.48   12.0   11.74    8.90   1    22    21
## Date             4 1094     NaN      NA     NA     NaN      NA Inf  -Inf  -Inf
## Amount           5 1094 5652.31 4102.44 4868.5 5221.58 4052.69   7 22050 22043
## Boxes.Shipped    6 1094  161.80  121.54  135.0  147.30  111.19   1   709   708
##                skew kurtosis     se
## SalesPerson*   0.00    -1.22   0.22
## Country*       0.03    -1.30   0.05
## Product*      -0.04    -1.23   0.20
## Date             NA       NA     NA
## Amount         0.89     0.44 124.03
## Boxes.Shipped  1.11     1.15   3.67
skim(sales)
Data summary
Name sales
Number of rows 1094
Number of columns 6
_______________________
Column type frequency:
Date 1
factor 3
numeric 2
________________________
Group variables None

Variable type: Date

skim_variable n_missing complete_rate min max median n_unique
Date 0 1 2022-01-03 2022-08-31 2022-05-11 168

Variable type: factor

skim_variable n_missing complete_rate ordered n_unique top_counts
SalesPerson 0 1 FALSE 25 Kel: 54, Bri: 53, Van: 51, Bev: 50
Country 0 1 FALSE 6 Aus: 205, Ind: 184, USA: 179, UK: 178
Product 0 1 FALSE 22 50%: 60, Ecl: 60, Smo: 59, Whi: 58

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
Amount 0 1 5652.31 4102.44 7 2390.5 4868.5 8027.25 22050 ▇▆▂▁▁
Boxes.Shipped 0 1 161.80 121.54 1 70.0 135.0 228.75 709 ▇▅▂▁▁

#Mean Median SD

mean(sales$Amount)
## [1] 5652.308
median(sales$Amount)
## [1] 4868.5
sd(sales$Amount)
## [1] 4102.442
var(sales$Amount)
## [1] 16830030
max(sales$Amount)
## [1] 22050
min(sales$Amount)
## [1] 7
range(sales$Amount)
## [1]     7 22050

#Frequency Tables

##Country

##Product

##Sales Person

#Histograms

##Amount

ggplot(sales,aes(Amount))+
  geom_histogram(fill="steelblue",bins=30)+
  theme_minimal()

##Boxes

ggplot(sales,aes(Boxes.Shipped))+
  geom_histogram(fill="orange",bins=30)+
  theme_minimal()

##Density Plot

ggplot(sales,aes(Amount))+
  geom_density(fill="skyblue",alpha=.6)

##Boxplots

ggplot(sales,aes(y=Amount))+
  geom_boxplot(fill="red")

###By Country

ggplot(sales,aes(Country,Amount,fill=Country))+
  geom_boxplot()

###By Product

ggplot(sales,aes(Product,Amount,fill=Product))+
  geom_boxplot()+
  theme(axis.text.x=element_text(angle=45,hjust=1))

##Scatter Plot

ggplot(sales,aes(Boxes.Shipped,Amount))+
  geom_point(color="blue")+
  geom_smooth(method="lm")
## `geom_smooth()` using formula = 'y ~ x'

##Correlation

numeric_data <- sales %>%
  select(Amount,Boxes.Shipped)

cor(numeric_data)
##                    Amount Boxes.Shipped
## Amount         1.00000000   -0.01882685
## Boxes.Shipped -0.01882685    1.00000000
corrplot(cor(numeric_data),
         method="color",
         addCoef.col="black")

##Correlation Matrix

ggpairs(numeric_data)

###Sales by Country

country_sales <- sales %>%
  group_by(Country) %>%
  summarise(TotalSales=sum(Amount))

country_sales
## # A tibble: 6 × 2
##   Country     TotalSales
##   <fct>            <dbl>
## 1 Australia      1137367
## 2 Canada          962899
## 3 India          1045800
## 4 New Zealand     950418
## 5 UK             1051792
## 6 USA            1035349

##Bar Chart

ggplot(country_sales,
       aes(reorder(Country,TotalSales),
           TotalSales,
           fill=Country))+
  geom_col()+
  coord_flip()

###Sales by Product

product_sales <- sales %>%
  group_by(Product) %>%
  summarise(TotalSales=sum(Amount))

ggplot(product_sales,
       aes(reorder(Product,TotalSales),
           TotalSales,
           fill=Product))+
  geom_col()+
  coord_flip()

###Sales by Sales Person

person_sales <- sales %>%
  group_by(SalesPerson) %>%
  summarise(TotalSales=sum(Amount))

person_sales <- sales %>%
  group_by(SalesPerson) %>%
  summarise(TotalSales=sum(Amount))

###Monthly Sales

sales$Month <- month(sales$Date,label=TRUE)

monthly_sales <- sales %>%
  group_by(Month)%>%
  summarise(TotalSales=sum(Amount))

ggplot(monthly_sales,
       aes(Month,TotalSales,group=1))+
  geom_line(size=1.2)+
  geom_point(size=3)
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

###Monthly Boxes

monthly_boxes <- sales %>%
  group_by(Month)%>%
  summarise(Boxes=sum(Boxes.Shipped))

monthly_boxes <- sales %>%
  group_by(Month)%>%
  summarise(Boxes=sum(Boxes.Shipped))

##Pie Chart

ggplot(country_sales,
       aes("",TotalSales,fill=Country))+
  geom_bar(stat="identity",width=1)+
  coord_polar("y")

##Heatmap

heat <- sales %>%
  group_by(Country,Product)%>%
  summarise(Sales=sum(Amount))
## `summarise()` has regrouped the output.
## ℹ Summaries were computed grouped by Country and Product.
## ℹ Output is grouped by Country.
## ℹ Use `summarise(.groups = "drop_last")` to silence this message.
## ℹ Use `summarise(.by = c(Country, Product))` for per-operation grouping
##   (`?dplyr::dplyr_by`) instead.
ggplot(heat,
       aes(Product,
           Country,
           fill=Sales))+
  geom_tile()

##IQR Method

Q1 <- quantile(sales$Amount,.25)

Q3 <- quantile(sales$Amount,.75)

IQR_value <- IQR(sales$Amount)

Lower <- Q1-1.5*IQR_value

Upper <- Q3+1.5*IQR_value

sales %>%
  filter(Amount<Lower | Amount>Upper)
##            SalesPerson     Country              Product       Date Amount
## 1          Brien Boise      Canada      99% Dark & Pure 2022-05-18  16793
## 2          Van Tuxwell   Australia  Organic Choco Syrup 2022-08-10  19453
## 3        Kelci Walkden         USA   Manuka Honey Choco 2022-02-16  17318
## 4          Van Tuxwell       India  Organic Choco Syrup 2022-05-16  19929
## 5       Marney O'Breen          UK   Smooth Sliky Salty 2022-05-13  18991
## 6         Ches Bonnell       India  Organic Choco Syrup 2022-03-08  16569
## 7       Dotty Strutley         USA Caramel Stuffed Bars 2022-04-15  16982
## 8         Jan Morforth New Zealand      Mint Chip Choco 2022-06-30  18340
## 9         Ches Bonnell       India  Peanut Butter Cubes 2022-01-27  22050
## 10      Curtice Advani       India   Smooth Sliky Salty 2022-04-19  19327
## 11        Jan Morforth   Australia      Mint Chip Choco 2022-02-22  17626
## 12 Rafaelita Blaksland New Zealand              Eclairs 2022-02-07  19481
## 13         Brien Boise       India        85% Dark Bars 2022-08-09  18032
## 14       Kelci Walkden      Canada          After Nines 2022-01-13  16702
## 15 Dennison Crosswaite         USA  Baker's Choco Chips 2022-08-11  17465
## 16         Kaine Padly          UK          After Nines 2022-01-21  18697
##    Boxes.Shipped Month
## 1            416   May
## 2             14   Aug
## 3             87   Feb
## 4            174   May
## 5             88   May
## 6             99   Mar
## 7             76   Apr
## 8            285   Jun
## 9            208   Jan
## 10           135   Apr
## 11           103   Feb
## 12            51   Feb
## 13           205   Aug
## 14           198   Jan
## 15           271   Aug
## 16           176   Jan

##Regression

model <- lm(Amount~Boxes.Shipped,data=sales)

summary(model)
## 
## Call:
## lm(formula = Amount ~ Boxes.Shipped, data = sales)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -5694.7 -3246.1  -769.4  2345.9 16427.1 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   5755.1237   206.6254  27.853   <2e-16 ***
## Boxes.Shipped   -0.6355     1.0212  -0.622    0.534    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 4104 on 1092 degrees of freedom
## Multiple R-squared:  0.0003545,  Adjusted R-squared:  -0.000561 
## F-statistic: 0.3872 on 1 and 1092 DF,  p-value: 0.5339