Group: Group 5
| Name | Matric No |
|---|---|
| Lee Jih Shian | 17126198 |
| Melanie Ng Huei Yee | 17072752 |
| Chong Jia En | 23059042 |
| Duan Xuanrui | 22099265 |
| Khai Yao Wong | S2179520 |
In today’s highly competitive business environment, understanding customer behavior and accurately predicting sales are crucial for making informed strategic decisions. Businesses are increasingly leveraging data analytics to gain insights into their customers’ purchasing patterns and forecast future sales trends. This project aims to harness the power of data science and machine learning to enhance business intelligence through sales prediction and customer segmentation.
To develop predictive models to forecast future sales, enabling better inventory management, production planning, and marketing campaign design.
To develop segmentation model to segment customers into distinct groups, facilitating targeted marketing efforts and personalized customer service.
To compare and evaluate the performance of different models in predicting sales and customer segmentation.
Analyze past marketing campaigns to learn what strategies have been most effective in attracting new customers. Data mining can help refine these strategies to improve the efficiency of future campaigns.
Through effective data mining, customers can be divided into different levels based on purchase history, behavior, etc. Companies can develop marketing strategies. To meet the needs and preferences of each group and improve customer satisfaction and loyalty.
Data mining focuses on ranking and segmentation of customers, helping to identify high-value customers who are likely to respond positively to promotions and offers to prevent customer churn.
The sample sales dataset obtained from Kaggle https://www.kaggle.com/datasets/kyanyoga/sample-sales-data
Data contains purchase information of a fictional store named Steel Wheels. Each record refers to a specific product that was sold to a customer in a specific order.
| Variable | Explaination |
|---|---|
| ORDERNUMBER | Unique ID for each order made by a customer |
| QUANTITYORDERED | Quantity of the product item included in the considered order specified by ORDERNUMBER |
| PRICEEACH | Price of product item |
| ORDERLINENUMBER | Line number of the product in each order number |
| SALES | Total price of the product item included in the considered order |
| ORDERDATE | Date of the order |
| STATUS | Order status of the purchase |
| QTR_ID | Quarter of the product purchased |
| MONTH_ID | Month of the product purchased |
| YEAR_ID | Year of product purchased |
| PRODUCTLINE | Type of product |
| MSRP | Manufacturer’s Suggested Retail Price |
| PRODUCTCODE | Product code of the product item |
| CUSTOMERNAME | Name of the customer of the considered order |
| PHONE | Contact number of customer |
| ADDRESSLINE1 | Address details of customer |
| ADDRESSLINE2 | Address details of customer |
| CITY | Address details of customer |
| STATE | Address details of customer |
| POSTALCODE | Address details of customer |
| COUNTRY | Address details of customer |
| TERRITORY | Address details of customer |
| CONTACTLASTNAME | Contact person details of customer |
| CONTACTFIRSTNAME | Contact person details of customer |
| DEALSIZE | Magnitude of business transactions |
sales <- read.csv("/Users/zhikiat/sales_data_sample.csv", header = T, stringsAsFactors = T)
# Structure of dataframe
str(sales)
## 'data.frame': 2823 obs. of 25 variables:
## $ ORDERNUMBER : int 10107 10121 10134 10145 10159 10168 10180 10188 10201 10211 ...
## $ QUANTITYORDERED : int 30 34 41 45 49 36 29 48 22 41 ...
## $ PRICEEACH : num 95.7 81.3 94.7 83.3 100 ...
## $ ORDERLINENUMBER : int 2 5 2 6 14 1 9 1 2 14 ...
## $ SALES : num 2871 2766 3884 3747 5205 ...
## $ ORDERDATE : Factor w/ 252 levels "1/10/2003 0:00",..: 113 186 205 227 24 40 49 57 83 5 ...
## $ STATUS : Factor w/ 6 levels "Cancelled","Disputed",..: 6 6 6 6 6 6 6 6 6 6 ...
## $ QTR_ID : int 1 2 3 3 4 4 4 4 4 1 ...
## $ MONTH_ID : int 2 5 7 8 10 10 11 11 12 1 ...
## $ YEAR_ID : int 2003 2003 2003 2003 2003 2003 2003 2003 2003 2004 ...
## $ PRODUCTLINE : Factor w/ 7 levels "Classic Cars",..: 2 2 2 2 2 2 2 2 2 2 ...
## $ MSRP : int 95 95 95 95 95 95 95 95 95 95 ...
## $ PRODUCTCODE : Factor w/ 109 levels "S10_1678","S10_1949",..: 1 1 1 1 1 1 1 1 1 1 ...
## $ CUSTOMERNAME : Factor w/ 92 levels "Alpha Cognac",..: 47 68 48 87 24 81 27 42 58 9 ...
## $ PHONE : Factor w/ 91 levels "(02) 5554 67",..: 49 55 17 77 78 80 41 22 79 4 ...
## $ ADDRESSLINE1 : Factor w/ 92 levels "?kergatan 24",..: 59 42 23 56 53 60 9 69 39 19 ...
## $ ADDRESSLINE2 : Factor w/ 10 levels "","2nd Floor",..: 1 1 1 1 1 1 1 1 1 1 ...
## $ CITY : Factor w/ 73 levels "Aaarhus","Allentown",..: 49 57 53 54 60 13 29 5 60 53 ...
## $ STATE : Factor w/ 17 levels "","BC","CA","CT",..: 11 1 1 3 3 3 1 1 3 1 ...
## $ POSTALCODE : Factor w/ 74 levels "","10022","10100",..: 2 29 43 51 1 56 33 66 1 42 ...
## $ COUNTRY : Factor w/ 19 levels "Australia","Austria",..: 19 7 7 19 19 19 7 12 19 7 ...
## $ TERRITORY : Factor w/ 3 levels "APAC","EMEA",..: NA 2 2 NA NA NA 2 2 NA 2 ...
## $ CONTACTLASTNAME : Factor w/ 77 levels "Accorti","Ashworth",..: 77 29 18 76 9 31 58 53 49 54 ...
## $ CONTACTFIRSTNAME: Factor w/ 72 levels "Adrian","Akiko",..: 37 55 12 32 32 33 44 66 32 15 ...
## $ DEALSIZE : Factor w/ 3 levels "Large","Medium",..: 3 3 2 2 2 2 3 2 3 2 ...
# Get the data types of each column
column_types <- sapply(sales, class)
# Display column names and data types side by side
column_info <- data.frame(
Column_Name = names(column_types),
Data_Type = as.character(column_types),
stringsAsFactors = FALSE
)
# Count how many columns for each data type
data_type_counts <- table(column_info$Data_Type)
print(data_type_counts)
##
## factor integer numeric
## 16 7 2
From the above summary we could observe that:
The dataset consists of customer transaction information used to perform RFM (Recency, Frequency, Monetary) analysis.
| Variable | Explaination |
|---|---|
| CUSTOMERNAME | Identifier for each customer. |
| ORDERNUMBER | Unique identifier for each order. |
| ORDERDATE | Date when the order was placed. |
| SALES | Total sales amount for each order. |
| Recency | Number of days since the customer’s last purchase. |
| Frequency | Total number of orders placed by the customer. |
| Monetary_value | Total amount of money spent by the customer. |
| r_quartile | Quartile ranking for Recency, where 4 is most recent. |
| f_quartile | Quartile ranking for Frequency, where 4 is most frequent. |
| m_quartile | Quartile ranking for Monetary_value, where 4 is highest spending. |
| RFM_Score | Sum of r_quartile, f_quartile, and m_quartile. |
| RFM_Value | Customer segment based on RFM_Score (High, Mid, Low Value). |
RFM <- read.csv("/Users/zhikiat/RFM_table.csv", header = T, stringsAsFactors = T)
# Structure of dataframe
str(RFM)
## 'data.frame': 86 obs. of 10 variables:
## $ X : int 1 2 3 4 5 6 7 8 9 10 ...
## $ CUSTOMERNAME : Factor w/ 86 levels "Alpha Cognac",..: 1 2 3 4 5 6 9 7 8 10 ...
## $ Recency : int 64 264 83 187 22 118 179 232 54 195 ...
## $ Frequency : int 20 26 46 7 23 15 8 18 27 51 ...
## $ Monetary_value: num 70488 94117 153996 24180 64591 ...
## $ r_quartile : int 4 1 3 2 4 3 3 1 4 2 ...
## $ f_quartile : int 2 2 4 1 2 1 1 1 3 4 ...
## $ m_quartile : int 2 3 4 1 1 1 1 1 3 4 ...
## $ RFM_Score : int 5 9 10 5 4 4 4 6 7 11 ...
## $ RFM_Value : Factor w/ 3 levels "High Value Customer",..: 2 3 1 2 2 2 2 3 3 1 ...
# Get the data types of each column
column_types <- sapply(RFM, class)
# Display column names and data types side by side
column_info <- data.frame(
Column_Name = names(column_types),
Data_Type = as.character(column_types),
stringsAsFactors = FALSE
)
# Count how many columns for each data type
data_type_counts <- table(column_info$Data_Type)
print(data_type_counts)
##
## factor integer numeric
## 2 7 1
From the above summary we could observe that:
library(vcd)
library(ggplot2)
library(reshape2)
library(dplyr)
library(tidyverse)
library(viridis)
library(corrplot)
library(scales)
library(plotly)
options(scipen = 999)
# Identify if there is missing value in the dataframe (general)
paste0("The total number of rows with missing values(s): ", sum(complete.cases(sales)))
## [1] "The total number of rows with missing values(s): 1749"
# Convert empty string as NA values
sales[sales == ""] <- NA
# Check for missing / empty values by column
missing_values_summary <- function(sales) {
missing_counts <- colSums(is.na(sales))
total_rows <- nrow(sales)
# Calculate % of missing / empty values
missing_percentage <- round((missing_counts / total_rows) * 100, 4)
# Create a summary of missing / empty values
summary_sales <- data.frame(
Column_Name = names(missing_counts),
Missing_Count = missing_counts,
Missing_Percentage = paste0(missing_percentage, "%")
)
print(summary_sales)
}
missing_values_summary(sales)
## Column_Name Missing_Count Missing_Percentage
## ORDERNUMBER ORDERNUMBER 0 0%
## QUANTITYORDERED QUANTITYORDERED 0 0%
## PRICEEACH PRICEEACH 0 0%
## ORDERLINENUMBER ORDERLINENUMBER 0 0%
## SALES SALES 0 0%
## ORDERDATE ORDERDATE 0 0%
## STATUS STATUS 0 0%
## QTR_ID QTR_ID 0 0%
## MONTH_ID MONTH_ID 0 0%
## YEAR_ID YEAR_ID 0 0%
## PRODUCTLINE PRODUCTLINE 0 0%
## MSRP MSRP 0 0%
## PRODUCTCODE PRODUCTCODE 0 0%
## CUSTOMERNAME CUSTOMERNAME 0 0%
## PHONE PHONE 0 0%
## ADDRESSLINE1 ADDRESSLINE1 0 0%
## ADDRESSLINE2 ADDRESSLINE2 2521 89.3022%
## CITY CITY 0 0%
## STATE STATE 1486 52.639%
## POSTALCODE POSTALCODE 76 2.6922%
## COUNTRY COUNTRY 0 0%
## TERRITORY TERRITORY 1074 38.0446%
## CONTACTLASTNAME CONTACTLASTNAME 0 0%
## CONTACTFIRSTNAME CONTACTFIRSTNAME 0 0%
## DEALSIZE DEALSIZE 0 0%
# Drop irrelevant columns
## Dropping identifiers (PII)
df1 <- sales[, !(names(sales) %in% c('PHONE','ADDRESSLINE1','ADDRESSLINE2','STATE','POSTALCODE','TERRITORY','PRODUCTCODE','CONTACTFIRSTNAME','CONTACTLASTNAME','ORDERLINENUMBER'
))]
# Check for missing / empty values after filling missing / empty / null values
missing_values_summary(df1)
## Column_Name Missing_Count Missing_Percentage
## ORDERNUMBER ORDERNUMBER 0 0%
## QUANTITYORDERED QUANTITYORDERED 0 0%
## PRICEEACH PRICEEACH 0 0%
## SALES SALES 0 0%
## ORDERDATE ORDERDATE 0 0%
## STATUS STATUS 0 0%
## QTR_ID QTR_ID 0 0%
## MONTH_ID MONTH_ID 0 0%
## YEAR_ID YEAR_ID 0 0%
## PRODUCTLINE PRODUCTLINE 0 0%
## MSRP MSRP 0 0%
## CUSTOMERNAME CUSTOMERNAME 0 0%
## CITY CITY 0 0%
## COUNTRY COUNTRY 0 0%
## DEALSIZE DEALSIZE 0 0%
# Convert order date to date time format in R programming
df1$ORDERDATE <- mdy_hm(df1$ORDERDATE)
invalid_dates <- df1$ORDERDATE[is.na(df1$ORDERDATE)]
## Priceeach field does not seem to be accurate if the value is 100, replace the column values by dividing sales by quantityordered
df1$PRICEEACH <- df1$SALES / df1$QUANTITYORDERED
# RFM part
sales_data <- df1
# Select relevant columns
rfm_data <- sales_data[, c('CUSTOMERNAME', 'ORDERNUMBER', 'ORDERDATE', 'SALES')]
# Calculate Recency, Frequency, and Monetary Value
NOW <- max(as.Date(rfm_data$ORDERDATE)) # Most recent date
RFM_table <- rfm_data %>%
group_by(CUSTOMERNAME) %>%
summarize(
Recency = as.numeric(difftime(NOW, max(as.Date(ORDERDATE)), units = "days")),
Frequency = n(),
Monetary_value = sum(SALES)
)
# Dividing into segments
RFM_table <- RFM_table %>%
mutate(
r_quartile = cut(Recency, breaks = quantile(Recency, probs = 0:4/4), labels = c(4:1)),
f_quartile = cut(Frequency, breaks = quantile(Frequency, probs = 0:4/4), labels = c(1:4)),
m_quartile = cut(Monetary_value, breaks = quantile(Monetary_value, probs = 0:4/4), labels = c(1:4))
)
# Calculate RFM Score
RFM_table <- RFM_table %>%
mutate(
RFM_Score = as.numeric(r_quartile) + as.numeric(f_quartile) + as.numeric(m_quartile)
)
# Assign RFM Value to Customers
RFM_table <- RFM_table %>%
mutate(
RFM_Value = case_when(
RFM_Score >= 10 ~ 'High Value Customer',
RFM_Score < 10 & RFM_Score >= 6 ~ 'Mid Value Customer',
TRUE ~ 'Low Value Customer'
)
)
# Filtered for non-NA RFM_Score
RFM_table <- RFM_table %>%
filter(!is.na(RFM_Score))
# Calculate Q1 (25th percentile) and Q3 (75th percentile)
Q1 <- quantile(RFM_table$Monetary_value, 0.25)
Q3 <- quantile(RFM_table$Monetary_value, 0.75)
# Calculate Interquartile Range (IQR)
IQR <- Q3 - Q1
# Define lower and upper bounds for outliers
lower_bound <- Q1 - 1.5 * IQR
upper_bound <- Q3 + 1.5 * IQR
# Filter the RFM_table to exclude outliers
RFM_table <- RFM_table %>%
filter(Monetary_value >= lower_bound & Monetary_value <= upper_bound)
# Remove corresponding records in df1
df1 <- df1 %>%
filter(CUSTOMERNAME %in% RFM_table$CUSTOMERNAME)
str(df1)
## 'data.frame': 2225 obs. of 15 variables:
## $ ORDERNUMBER : int 10107 10121 10134 10145 10159 10168 10180 10188 10201 10211 ...
## $ QUANTITYORDERED: int 30 34 41 45 49 36 29 48 22 41 ...
## $ PRICEEACH : num 95.7 81.4 94.7 83.3 106.2 ...
## $ SALES : num 2871 2766 3884 3747 5205 ...
## $ ORDERDATE : POSIXct, format: "2003-02-24" "2003-05-07" ...
## $ STATUS : Factor w/ 6 levels "Cancelled","Disputed",..: 6 6 6 6 6 6 6 6 6 6 ...
## $ QTR_ID : int 1 2 3 3 4 4 4 4 4 1 ...
## $ MONTH_ID : int 2 5 7 8 10 10 11 11 12 1 ...
## $ YEAR_ID : int 2003 2003 2003 2003 2003 2003 2003 2003 2003 2004 ...
## $ PRODUCTLINE : Factor w/ 7 levels "Classic Cars",..: 2 2 2 2 2 2 2 2 2 2 ...
## $ MSRP : int 95 95 95 95 95 95 95 95 95 95 ...
## $ CUSTOMERNAME : Factor w/ 92 levels "Alpha Cognac",..: 47 68 48 87 24 81 27 42 58 9 ...
## $ CITY : Factor w/ 73 levels "Aaarhus","Allentown",..: 49 57 53 54 60 13 29 5 60 53 ...
## $ COUNTRY : Factor w/ 19 levels "Australia","Austria",..: 19 7 7 19 19 19 7 12 19 7 ...
## $ DEALSIZE : Factor w/ 3 levels "Large","Medium",..: 3 3 2 2 2 2 3 2 3 2 ...
### Plotting Distribution for All Quantitative Variables
# Line charts
quantitative_variable <- c('QUANTITYORDERED', 'PRICEEACH', 'SALES', 'MSRP')
par(mfrow = c(2, 2))
for (i in 1:length(quantitative_variable)) {
density_values <- density(sales_data[[quantitative_variable[i]]])
plot(density_values, main = quantitative_variable[i], xlab = "", ylab = "Density", col = viridis(4)[i], lwd = 3)
}
par(mfrow = c(1, 1))
# Boxplots
quantitative_variable <- c('QUANTITYORDERED', 'PRICEEACH', 'SALES', 'MSRP')
par(mfrow = c(2, 2))
for (i in 1:length(quantitative_variable)) {
boxplot(sales_data[[quantitative_variable[i]]], main = quantitative_variable[i], col = viridis(4)[i])
}
par(mfrow = c(1, 1))
# Frequency distribution of status
status <- table(df1$STATUS) / nrow(df1) # Calculate relative frequencies
pie(status,
main = "Pie Chart for Status of Orders",
labels = paste(names(status), ": ", round(status * 100, 1), "%", sep = ""),
col = viridis_pal()(length(status)), # Use rainbow colors
cex = 0.8, # Adjust label size
)
# Checking for time frame of the data
df1 %>% group_by(YEAR_ID) %>% summarise(num_unique_months = n_distinct(MONTH_ID))
## # A tibble: 3 × 2
## YEAR_ID num_unique_months
## <int> <int>
## 1 2003 12
## 2 2004 12
## 3 2005 5
#Year Frequency
yearly_orders <- df1 %>%
group_by(YEAR_ID) %>%
summarise(count = n())
# Create the bar chart
ggplot(yearly_orders, aes(x = YEAR_ID, y = count)) +
geom_bar(stat = "identity", fill = "steelblue") +
geom_text(aes(label = count), vjust = -0.3, color = "black", size = 3.5) +
labs(title = "Number of Orders by Year",
x = "Year",
y = "Frequency") +
theme_minimal() +
scale_y_continuous(labels = scales::comma)
#Quarter Frequency
quarterly_orders <- df1 %>%
group_by(YEAR_ID, QTR_ID) %>%
summarise(count = n(), .groups = "drop") %>%
ungroup()
qtr_names <- c("QTR 1", "QTR 2", "QTR 3", "QTR 4")
quarterly_orders$QTR_NAME <- qtr_names[quarterly_orders$QTR_ID]
# Create the bar chart
ggplot(quarterly_orders, aes(x = QTR_NAME, y = count, fill = as.factor(YEAR_ID))) +
geom_bar(stat = "identity", position = position_dodge()) +
geom_text(aes(label = count),
position = position_dodge(width = 0.9),
vjust = -0.5,
size = 3.5) +
labs(x = "Quarter", y = "Frequency", title = "Number of Orders by Quarter") +
scale_fill_viridis_d(name = "Year") +
theme_minimal() +
scale_y_continuous(labels = comma) +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
#Month Frequency
monthly_orders <- df1 %>%
group_by(YEAR_ID, MONTH_ID) %>%
summarise(count = n(), .groups = "drop") %>%
ungroup()
# Create a vector with month names
month_names <- c("January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December")
# Map MONTH_ID to month names for plotting
monthly_orders$MONTH_NAME <- factor(month_names[monthly_orders$MONTH_ID], levels = month_names)
# Create the bar chart
ggplot(monthly_orders, aes(x = MONTH_NAME, y = count, fill = as.factor(YEAR_ID))) +
geom_bar(stat = "identity", position = position_dodge()) +
geom_text(aes(label = count),
position = position_dodge(width = 0.9),
vjust = -0.5,
size = 3.5) +
labs(x = "Month", y = "Frequency", title = "Number of Orders by Month") +
scale_fill_viridis_d(name = "Year") +
theme_minimal() +
scale_y_continuous(labels = comma) +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
# Get the hour for each sale timestamp
df1$dayofweek <- weekdays(df1$ORDERDATE)
day_order <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
df1$dayofweek <- factor(df1$dayofweek, levels = day_order)
par(mfrow = c(1, 1))
par(mar = c(5, 5, 4, 4))
barplot(table(df1$dayofweek),
main = "Count of Orders by Day of Week",
xlab = "Day of Week",
ylab = "Number of Orders",
col = viridis(length(unique(df1$dayofweek))),
ylim = c(0, 700),
las = 2)
par(mfrow = c(1, 1))
grid(nx = 0, ny = 10, col = "black", lty = "dotted")
## EDA for RFM Table (boxplots)
quantitative_variable2 <- c('Recency', 'Frequency', 'Monetary_value')
par(mfrow = c(2, 2))
for (i in 1:length(quantitative_variable2)) {
boxplot(RFM_table[[quantitative_variable2[i]]], main = quantitative_variable2[i], col = viridis(3)[i])
}
par(mfrow = c(1, 1))
## SCATTER PLOTS
# 2 continuous variable
# QUANTITYORDERED & SALES
ggplot(df1, aes(x = QUANTITYORDERED, y = SALES)) +
geom_point() +
geom_smooth(method = "lm", formula = y ~ x) +
ggtitle("QUANTITYORDERED vs SALES") +
xlab("QUANTITYORDERED") +
ylab("SALES")
# PRICEEACH & SALES
ggplot(df1, aes(x = PRICEEACH, y = SALES)) +
geom_point() +
geom_smooth(method = "lm", formula = y ~ x) +
ggtitle("PRICEEACH vs SALES") +
xlab("PRICEEACH") +
ylab("SALES")
# MSRP & SALES
ggplot(df1, aes(x = MSRP, y = SALES)) +
geom_point() +
geom_smooth(method = "lm", formula = y ~ x) +
ggtitle("MSRP vs SALES") +
xlab("MSRP") +
ylab("SALES")
## BARPLOTS
# Productline Sales
par(mar = c(10, 12, 4, 2))
sales_per_city <- aggregate(SALES ~ PRODUCTLINE, data = df1, FUN = "sum")
sales_per_city <- sales_per_city[order(-sales_per_city$SALES), ]
top_cities <- head(sales_per_city, 10)
par(mfrow = c(1, 1), mar = c(9, 9, 4, 2), las = 2)
par(mgp = c(8, 1, 0))
max_sales <- max(top_cities$SALES)
barplot(rev(top_cities$SALES),
names.arg = rev(top_cities$PRODUCTLINE),
horiz = TRUE,
col = viridis(10),
main = "Productline Sales",
xlab = "Total Sales",
ylab = "Product",
xlim = c(0, max_sales * 1.1))
# Country Sales
par(mar = c(5, 10, 4, 2))
sales_per_country <- aggregate(SALES ~ COUNTRY, data = df1, FUN = sum)
sales_per_country <- sales_per_country[order(-sales_per_country$SALES), ]
top_countries <- head(sales_per_country, 10)
par(mfrow = c(1, 1), mar = c(5, 10, 4, 2), las = 2)
barplot(rev(top_countries$SALES),
names.arg = rev(top_countries$COUNTRY),
horiz = TRUE,
col = viridis(10),
main = "Top 10 Countries with Most Sales",
xlab = "Total Sales",
ylab = "Country")
# City Sales
par(mar = c(5, 10, 4, 2))
sales_per_city <- aggregate(SALES ~ CITY, data = df1, FUN = sum)
sales_per_city <- sales_per_city[order(-sales_per_city$SALES), ]
top_cities <- head(sales_per_city, 10)
par(mfrow = c(1, 1), mar = c(5, 10, 4, 2), las = 2)
barplot(rev(top_cities$SALES),
names.arg = rev(top_cities$CITY),
horiz = TRUE,
col = viridis(10),
main = "Top 10 Cities with Most Sales",
xlab = "Total Sales",
ylab = "City")
# DEALSIZE & SALES
par(mar = c(5, 4, 4, 2))
ggplot(df1, aes(x = DEALSIZE, y = SALES, fill = DEALSIZE)) +
geom_bar(stat ="identity") +
labs(title = "Deal Size vs Sales", x = "Deal Size" , y = "Sales")
#FORMATTING
qtr_labels <- c("Q1","Q2","Q3","Q4")
df1$QTR_ID <- factor(df1$QTR_ID, labels = qtr_labels)
month_labels <- c("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
df1$MONTH_ID <- factor(df1$MONTH_ID, labels = month_labels)
year_labels <- c("2003","2004","2005")
df1$YEAR_ID <- factor(df1$YEAR_ID, labels = year_labels)
# QTR & SALES
ggplot(df1, aes(x = as.factor(QTR_ID) , y = SALES, fill = QTR_ID)) +
geom_bar(stat ="identity") +
labs(title = "Plot of Sales per Quarter", x = "Quarter" , y = "Sales")
# Quarterly Revenue
quarterly_revenue <- df1 %>%
group_by(YEAR_ID, QTR_ID) %>%
summarise(total_sales = sum(SALES), .groups = "drop") %>%
ungroup()
ggplot(quarterly_revenue, aes(x = QTR_ID, y = total_sales, color = as.factor(YEAR_ID), group = YEAR_ID)) +
geom_line(linewidth = 1.2) +
labs(x = "Quarter", y = "Sales", title = "Quarterly Revenue") +
scale_color_viridis_d() +
theme_minimal() +
scale_y_continuous(labels = scales::comma_format())
# MONTH & SALES
ggplot(df1, aes(x = MONTH_ID, y = SALES, fill = MONTH_ID)) +
geom_bar(stat ="identity") + theme_minimal() +
labs(title = "Plot of Sales per Month", x = "Month" , y = "Sales")
# Monthly Revenue
monthly_revenue <- df1 %>%
group_by(YEAR_ID, MONTH_ID) %>%
summarise(total_sales = sum(SALES), .groups = 'drop')
ggplot(monthly_revenue, aes(x = MONTH_ID, y = total_sales, color = as.factor(YEAR_ID),group = YEAR_ID)) +
geom_line(size = 1.2) +
labs(x = "Month", y = "Sales", title = "Monthly Revenue") +
scale_color_viridis_d() +
theme_minimal() +
scale_y_continuous(labels = scales::comma_format())
# YEAR & SALES
ggplot(df1, aes(x = YEAR_ID, y = SALES, fill = YEAR_ID)) +
geom_bar(stat ="identity") + theme_minimal() +
labs(title = "Plot of Sales per Year", x = "Year" , y = "Sales")
# Barchart
RFM_table$RFM_Value <- factor(RFM_table$RFM_Value, levels = c("Low Value Customer","Mid Value Customer","High Value Customer"))
# Calculate average Recency, average Frequency, average Monetary Value for each group
RFM_AVG <- RFM_table %>%
group_by(RFM_Value) %>% # Group by the value column (high, medium, low)
summarize(avg_Recency = mean(Recency),avg_Frequency = mean(Frequency),avg_Monetary = mean(Monetary_value))
DF_RFM<-data.frame(RFM_AVG)
print(DF_RFM)
## RFM_Value avg_Recency avg_Frequency avg_Monetary
## 1 Low Value Customer 94.4000 17.20000 59731.72
## 2 Mid Value Customer 212.0877 24.96491 88809.85
## 3 High Value Customer 196.0714 38.85714 137096.62
# RECENCY VS RFM VALUE
ggplot(DF_RFM, aes(x = RFM_Value, y = avg_Recency, fill = RFM_Value)) +
geom_bar(stat ="identity") +
labs(title = "Average Recency vs RFM Value", x = "RFM Value" , y = "Recency")
# FREQUENCY VS RFM VALUE
ggplot(DF_RFM, aes(x = RFM_Value, y = avg_Frequency, fill = RFM_Value)) +
geom_bar(stat ="identity") +
labs(title = "Average Frequency vs RFM Value", x = "RFM Value" , y = "Frequency")
# Monetary VALUE VS RFM VALUE
ggplot(DF_RFM, aes(x = RFM_Value, y = avg_Monetary, fill = RFM_Value)) +
geom_bar(stat ="identity") +
labs(title = "Average Monetary Value vs RFM Value", x = "RFM Value" , y = "Monetary Value")
# R QUARTILE VS RFM VALUE
RFM_table$r_quartile <- factor(RFM_table$r_quartile, levels = c("1", "2", "3", "4"))
ggplot(RFM_table, aes(x = r_quartile , y = "Count" , fill = RFM_Value)) +
geom_bar(stat ="identity") +
labs(title = "R_Quartile vs RFM Value", x = "R Quartile" , y = "RFM Value")
# F QUARTILE VS RFM VALUE
RFM_table$f_quartile <- factor(RFM_table$f_quartile, levels = c("1", "2", "3", "4"))
ggplot(RFM_table, aes(x = f_quartile , y = "Count" , fill = RFM_Value)) +
geom_bar(stat ="identity") +
labs(title = "F_Quartile vs RFM Value", x = "F Quartile" , y = "RFM Value")
# M QUARTILE VS RFM VALUE
RFM_table$m_quartile <- factor(RFM_table$m_quartile, levels = c("1", "2", "3", "4"))
ggplot(RFM_table, aes(x = m_quartile , y = "Count" , fill = RFM_Value)) +
geom_bar(stat ="identity") +
labs(title = "M_Quartile vs RFM Value", x = "M Quartile" , y = "RFM Value")
# 3D scatter plot
plot_ly(data = RFM_table,
x = ~Recency,
y = ~Monetary_value,
z = ~Frequency,
color = ~RFM_Value,
type = 'scatter3d',
mode = 'markers') %>%
layout(title = '3D Scatter Plot of RFM Table',
scene = list(
xaxis = list(title = 'Recency'),
yaxis = list(title = 'Monetary Value'),
zaxis = list(title = 'Frequency')
))
# Select numeric columns and calculate correlation matrix
numeric_columns <- df1 %>%
select_if(is.numeric)
correlation_matrix <- cor(numeric_columns, use = "complete.obs")
melted_corr_matrix <- melt(correlation_matrix)
# Create the numeric heatmap
heatmap_plot <- ggplot(data = melted_corr_matrix, aes(x = Var1, y = Var2, fill = value)) +
geom_tile(color = "white") +
geom_text(aes(label = round(value, 2)), size = 3) +
scale_fill_gradient2(low = "blue", high = "red", mid = "white",
midpoint = 0, limit = c(-1, 1), space = "Lab",
name = "Correlation") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, vjust = 1,
size = 12, hjust = 1)) +
coord_fixed() +
ggtitle("Correlation Heatmap for Numeric Variables") +
theme(plot.title = element_text(hjust = 0.5))
# Print heatmap plot
print(heatmap_plot)
# Select categorical columns and calculate Cramér's V matrix
categorical_columns <- df1 %>%
select_if(is.factor)
cramers_v <- function(x, y) {
tbl <- table(x, y)
chisq <- chisq.test(tbl)
n <- sum(tbl)
phi2 <- chisq$statistic / n
k <- min(dim(tbl)) - 1
v <- sqrt(phi2 / k)
return(v)
}
categorical_vars <- colnames(categorical_columns)
n <- length(categorical_vars)
cramers_v_matrix <- matrix(0, n, n, dimnames = list(categorical_vars, categorical_vars))
for (i in 1:n) {
for (j in i:n) {
if (i == j) {
cramers_v_matrix[i, j] <- 1
} else {
cramers_v_matrix[i, j] <- cramers_v(categorical_columns[[i]], categorical_columns[[j]])
cramers_v_matrix[j, i] <- cramers_v_matrix[i, j]
}
}
}
cramers_v_df <- as.data.frame(as.table(cramers_v_matrix))
# Create the categorical heatmap
categorical_heatmap_plot <- ggplot(data = cramers_v_df, aes(Var1, Var2, fill = Freq)) +
geom_tile(color = "white") +
geom_text(aes(label = round(Freq, 2)), size = 3) +
scale_fill_gradient2(low = "blue", high = "red", mid = "white",
midpoint = 0.5, limit = c(0, 1), space = "Lab",
name = "Cramer's V") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, vjust = 1, size = 12, hjust = 1)) +
coord_fixed() +
ggtitle("Cramér's V Heatmap for Categorical Variables") +
theme(plot.title = element_text(hjust = 0.5))
# Print categorical heatmap plot
print(categorical_heatmap_plot)
# Calculate correlations with SALES for numeric variables
correlation_with_sales <- cor(numeric_columns, use = "complete.obs")[, "SALES"]
# Convert to data frame for plotting
correlation_with_sales_df <- data.frame(Variable = names(correlation_with_sales), Correlation = correlation_with_sales)
correlation_with_sales_df <- correlation_with_sales_df %>% filter(Variable != "SALES")
# Create bar chart for numeric correlations
bar_chart_plot <- ggplot(data = correlation_with_sales_df, aes(x = reorder(Variable, Correlation), y = Correlation)) +
geom_bar(stat = "identity") +
coord_flip() +
ggtitle("Correlation with SALES for Numeric Variables") +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5)) +
xlab("Variable") +
ylab("Correlation")
# Print bar chart plot
print(bar_chart_plot)
# Select numeric columns and calculate correlation matrix
numeric_columns <- RFM_table %>%
select_if(is.numeric)
correlation_matrix <- cor(numeric_columns, use = "complete.obs")
# Melt the correlation matrix for visualization
melted_corr_matrix <- melt(correlation_matrix)
# Create the heatmap using ggplot2
heatmap_plot <- ggplot(data = melted_corr_matrix, aes(x = Var1, y = Var2, fill = value)) +
geom_tile(color = "white") +
geom_text(aes(label = round(value, 2)), size = 3) +
scale_fill_gradient2(low = "blue", high = "red", mid = "white",
midpoint = 0, limit = c(-1, 1), space = "Lab",
name = "Correlation") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, vjust = 1,
size = 12, hjust = 1)) +
coord_fixed() +
ggtitle("Correlation Heatmap for RFM Variables") +
theme(plot.title = element_text(hjust = 0.5))
# Print the heatmap
print(heatmap_plot)
#categorical
RFM_table$RFM_Score <- as.factor(RFM_table$RFM_Score)
RFM_table$RFM_Value <- as.factor(RFM_table$RFM_Value)
RFM_table$CUSTOMERNAME <- as.character(RFM_table$CUSTOMERNAME)
# Select categorical columas.character()# Select categorical columns and calculate Cramér's V matrix
categorical_columns <- RFM_table %>%
select_if(is.factor)
categorical_vars <- colnames(categorical_columns)
n <- length(categorical_vars)
cramers_v_matrix <- matrix(0, n, n, dimnames = list(categorical_vars, categorical_vars))
for (i in 1:n) {
for (j in i:n) {
if (i == j) {
cramers_v_matrix[i, j] <- 1
} else {
cramers_v_matrix[i, j] <- cramers_v(categorical_columns[[i]], categorical_columns[[j]])
cramers_v_matrix[j, i] <- cramers_v_matrix[i, j]
}
}
}
cramers_v_df <- as.data.frame(as.table(cramers_v_matrix))
# Create the categorical heatmap
categorical_heatmap_plot <- ggplot(data = cramers_v_df, aes(Var1, Var2, fill = Freq)) +
geom_tile(color = "white") +
geom_text(aes(label = round(Freq, 2)), size = 3) +
scale_fill_gradient2(low = "blue", high = "red", mid = "white",
midpoint = 0.5, limit = c(0, 1), space = "Lab",
name = "Cramer's V") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, vjust = 1, size = 12, hjust = 1)) +
coord_fixed() +
ggtitle("Cramér's V Heatmap for Categorical Variables") +
theme(plot.title = element_text(hjust = 0.5))
# Print categorical heatmap plot
print(categorical_heatmap_plot)
# Import library
library(caret) # for modeling
library(gbm) # for Gradient Boosting
library(rpart) # for Decision Tree
library(e1071) # for SVM
library(reshape2)
# Specify the columns to encode
columns_to_encode <- c("STATUS", "QTR_ID", "MONTH_ID", "PRODUCTLINE", "DEALSIZE", "CITY", "COUNTRY", "dayofweek")
# Perform one-hot encoding
encoded_data <- model.matrix(~ . - 1, data = df1[, columns_to_encode])
# Combine the encoded data with the SALES column
df1_encoded <- cbind(df1["SALES"], encoded_data)
# Split data into training and testing sets
set.seed(123) # for reproducibility
train_index <- createDataPartition(df1_encoded$SALES, p = 0.8, list = FALSE)
train_data <- df1_encoded[train_index, ]
test_data <- df1_encoded[-train_index, ]
# Function to calculate evaluation metrics
evaluate_model <- function(true_values, predictions) {
rmse <- sqrt(mean((true_values - predictions)^2))
mae <- mean(abs(true_values - predictions))
r2 <- cor(true_values, predictions)^2
mape <- mean(abs((true_values - predictions) / true_values)) * 100
return(c(RMSE = rmse, MAE = mae, R2 = r2, MAPE = mape))
}
# Build and evaluate models
# Multiple Regression model
lm_model <- lm(SALES ~ ., data = train_data)
lm_predictions <- predict(lm_model, newdata = test_data)
lm_metrics <- evaluate_model(test_data$SALES, lm_predictions)
# Decision Tree model
dt_model <- rpart(SALES ~ ., data = train_data)
dt_predictions <- predict(dt_model, newdata = test_data)
dt_metrics <- evaluate_model(test_data$SALES, dt_predictions)
# Support Vector Machine (SVM) model
svm_model <- svm(SALES ~ ., data = train_data)
svm_predictions <- predict(svm_model, newdata = test_data)
svm_metrics <- evaluate_model(test_data$SALES, svm_predictions)
# Gradient Boosting model
gbm_model <- gbm(SALES ~ ., data = train_data, distribution = "gaussian", n.trees = 100)
gbm_predictions <- predict(gbm_model, newdata = test_data, n.trees = 100)
gbm_metrics <- evaluate_model(test_data$SALES, gbm_predictions)
# Create a summary table of metrics
model_performance <- data.frame(
Model = c("Multiple Regression", "Decision Tree", "Support Vector Machine", "Gradient Boosting"),
RMSE = c(lm_metrics["RMSE"], dt_metrics["RMSE"], svm_metrics["RMSE"], gbm_metrics["RMSE"]),
MAE = c(lm_metrics["MAE"], dt_metrics["MAE"], svm_metrics["MAE"], gbm_metrics["MAE"]),
R2 = c(lm_metrics["R2"], dt_metrics["R2"], svm_metrics["R2"], gbm_metrics["R2"]),
MAPE = c(lm_metrics["MAPE"], dt_metrics["MAPE"], svm_metrics["MAPE"], gbm_metrics["MAPE"])
)
# Print the summary table
print(model_performance)
## Model RMSE MAE R2 MAPE
## 1 Multiple Regression 883.3190 711.6334 0.7688384 24.75773
## 2 Decision Tree 870.4328 697.1713 0.7754687 23.90577
## 3 Support Vector Machine 1870.4091 1397.5743 0.3997581 47.53081
## 4 Gradient Boosting 1009.9271 779.3114 0.7200052 26.09811
# Visualize model performance
model_performance_melt <- melt(model_performance, id.vars = "Model")
ggplot(model_performance_melt, aes(x = Model, y = value, fill = Model)) +
geom_bar(stat = "identity", position = "dodge") +
facet_wrap(~ variable, scales = "free_y") +
theme_minimal() +
ggtitle("Model Performance Comparison") +
ylab("Metric Value") +
xlab("Model") +
theme(axis.text.x = element_blank())
library(dplyr)
library(caret)
library(e1071)
library(rpart)
library(nnet)
library(kernlab)
# Features and target variable
features <- c("Recency", "Frequency", "Monetary_value", "r_quartile", "f_quartile", "m_quartile", "RFM_Score")
X <- RFM_table[features]
y <- RFM_table$RFM_Value
# Split the data into training and testing sets
set.seed(42)
split <- 0.7
trainIndex <- createDataPartition(y, p = split, list = FALSE)
X_train <- X[trainIndex,]
X_test <- X[-trainIndex,]
y_train <- y[trainIndex]
y_test <- y[-trainIndex]
# Print the size of training and test sets
cat("Size of training set:", nrow(X_train), "\n")
## Size of training set: 61
cat("Size of test set:", nrow(X_test), "\n")
## Size of test set: 25
# Set up cross-validation
cv_control <- trainControl(method = "cv", number = 10)
# Train the Decision Tree model with cross-validation
dt_model_cv <- train(RFM_Value ~ ., data = data.frame(X_train, RFM_Value = y_train),
method = "rpart",
trControl = cv_control)
print(dt_model_cv)
## CART
##
## 61 samples
## 7 predictor
## 3 classes: 'Low Value Customer', 'Mid Value Customer', 'High Value Customer'
##
## No pre-processing
## Resampling: Cross-Validated (10 fold)
## Summary of sample sizes: 55, 55, 55, 55, 55, 55, ...
## Resampling results across tuning parameters:
##
## cp Accuracy Kappa
## 0.0000000 0.6404762 0.2288889
## 0.1666667 0.6904762 0.1536508
## 0.3333333 0.6571429 0.0000000
##
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was cp = 0.1666667.
# Train the SVM model with cross-validation
svm_model_cv <- train(RFM_Value ~ ., data = data.frame(X_train, RFM_Value = y_train),
method = "svmRadial",
trControl = cv_control)
## Warning in .local(x, ...): Variable(s) `' constant. Cannot scale data.
## Warning in .local(x, ...): Variable(s) `' constant. Cannot scale data.
## Warning in .local(x, ...): Variable(s) `' constant. Cannot scale data.
print(svm_model_cv)
## Support Vector Machines with Radial Basis Function Kernel
##
## 61 samples
## 7 predictor
## 3 classes: 'Low Value Customer', 'Mid Value Customer', 'High Value Customer'
##
## No pre-processing
## Resampling: Cross-Validated (10 fold)
## Summary of sample sizes: 55, 55, 55, 55, 54, 55, ...
## Resampling results across tuning parameters:
##
## C Accuracy Kappa
## 0.25 0.6571429 0.0000000
## 0.50 0.9023810 0.7530769
## 1.00 0.9523810 0.8730769
##
## Tuning parameter 'sigma' was held constant at a value of 0.02948147
## Accuracy was used to select the optimal model using the largest value.
## The final values used for the model were sigma = 0.02948147 and C = 1.
# Train the K-Nearest Neighbors model with cross-validation
knn_model_cv <- train(RFM_Value ~ ., data = data.frame(X_train, RFM_Value = y_train),
method = "knn",
trControl = cv_control)
print(knn_model_cv)
## k-Nearest Neighbors
##
## 61 samples
## 7 predictor
## 3 classes: 'Low Value Customer', 'Mid Value Customer', 'High Value Customer'
##
## No pre-processing
## Resampling: Cross-Validated (10 fold)
## Summary of sample sizes: 54, 55, 55, 55, 55, 55, ...
## Resampling results across tuning parameters:
##
## k Accuracy Kappa
## 5 0.6404762 0.03923077
## 7 0.6380952 0.08833333
## 9 0.6071429 -0.02666667
##
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was k = 5.
# Decision Tree predictions and evaluation
dt_predictions_cv <- predict(dt_model_cv, newdata = X_test)
dt_confusion_matrix_cv <- confusionMatrix(dt_predictions_cv, y_test)
print(dt_confusion_matrix_cv)
## Confusion Matrix and Statistics
##
## Reference
## Prediction Low Value Customer Mid Value Customer High Value Customer
## Low Value Customer 1 0 0
## Mid Value Customer 3 17 4
## High Value Customer 0 0 0
##
## Overall Statistics
##
## Accuracy : 0.72
## 95% CI : (0.5061, 0.8793)
## No Information Rate : 0.68
## P-Value [Acc > NIR] : 0.4253
##
## Kappa : 0.1784
##
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: Low Value Customer Class: Mid Value Customer
## Sensitivity 0.250 1.0000
## Specificity 1.000 0.1250
## Pos Pred Value 1.000 0.7083
## Neg Pred Value 0.875 1.0000
## Prevalence 0.160 0.6800
## Detection Rate 0.040 0.6800
## Detection Prevalence 0.040 0.9600
## Balanced Accuracy 0.625 0.5625
## Class: High Value Customer
## Sensitivity 0.00
## Specificity 1.00
## Pos Pred Value NaN
## Neg Pred Value 0.84
## Prevalence 0.16
## Detection Rate 0.00
## Detection Prevalence 0.00
## Balanced Accuracy 0.50
# SVM predictions and evaluation
svm_predictions_cv <- predict(svm_model_cv, newdata = X_test)
svm_confusion_matrix_cv <- confusionMatrix(svm_predictions_cv, y_test)
print(svm_confusion_matrix_cv)
## Confusion Matrix and Statistics
##
## Reference
## Prediction Low Value Customer Mid Value Customer High Value Customer
## Low Value Customer 4 0 0
## Mid Value Customer 0 17 0
## High Value Customer 0 0 4
##
## Overall Statistics
##
## Accuracy : 1
## 95% CI : (0.8628, 1)
## No Information Rate : 0.68
## P-Value [Acc > NIR] : 0.00006497
##
## Kappa : 1
##
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: Low Value Customer Class: Mid Value Customer
## Sensitivity 1.00 1.00
## Specificity 1.00 1.00
## Pos Pred Value 1.00 1.00
## Neg Pred Value 1.00 1.00
## Prevalence 0.16 0.68
## Detection Rate 0.16 0.68
## Detection Prevalence 0.16 0.68
## Balanced Accuracy 1.00 1.00
## Class: High Value Customer
## Sensitivity 1.00
## Specificity 1.00
## Pos Pred Value 1.00
## Neg Pred Value 1.00
## Prevalence 0.16
## Detection Rate 0.16
## Detection Prevalence 0.16
## Balanced Accuracy 1.00
# KNN predictions and evaluation
knn_predictions_cv <- predict(knn_model_cv, newdata = X_test)
knn_confusion_matrix_cv <- confusionMatrix(knn_predictions_cv, y_test)
print(knn_confusion_matrix_cv)
## Confusion Matrix and Statistics
##
## Reference
## Prediction Low Value Customer Mid Value Customer High Value Customer
## Low Value Customer 0 1 0
## Mid Value Customer 4 15 4
## High Value Customer 0 1 0
##
## Overall Statistics
##
## Accuracy : 0.6
## 95% CI : (0.3867, 0.7887)
## No Information Rate : 0.68
## P-Value [Acc > NIR] : 0.8576
##
## Kappa : -0.1062
##
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: Low Value Customer Class: Mid Value Customer
## Sensitivity 0.0000 0.8824
## Specificity 0.9524 0.0000
## Pos Pred Value 0.0000 0.6522
## Neg Pred Value 0.8333 0.0000
## Prevalence 0.1600 0.6800
## Detection Rate 0.0000 0.6000
## Detection Prevalence 0.0400 0.9200
## Balanced Accuracy 0.4762 0.4412
## Class: High Value Customer
## Sensitivity 0.0000
## Specificity 0.9524
## Pos Pred Value 0.0000
## Neg Pred Value 0.8333
## Prevalence 0.1600
## Detection Rate 0.0000
## Detection Prevalence 0.0400
## Balanced Accuracy 0.4762
# Function to calculate average metrics
calculate_average_metrics <- function(conf_matrix) {
sensitivity <- mean(conf_matrix$byClass[,"Sensitivity"], na.rm = TRUE)
specificity <- mean(conf_matrix$byClass[,"Specificity"], na.rm = TRUE)
return(c(Sensitivity = sensitivity, Specificity = specificity))
}
# Collect evaluation metrics
dt_metrics <- calculate_average_metrics(dt_confusion_matrix_cv)
svm_metrics <- calculate_average_metrics(svm_confusion_matrix_cv)
knn_metrics <- calculate_average_metrics(knn_confusion_matrix_cv)
# Collect evaluation metrics
evaluation_metrics <- data.frame(
Model = c("Decision Tree", "SVM", "KNN"),
Accuracy = c(dt_confusion_matrix_cv$overall['Accuracy'],
svm_confusion_matrix_cv$overall['Accuracy'],
knn_confusion_matrix_cv$overall['Accuracy']),
Kappa = c(dt_confusion_matrix_cv$overall['Kappa'],
svm_confusion_matrix_cv$overall['Kappa'],
knn_confusion_matrix_cv$overall['Kappa']),
Sensitivity = c(dt_metrics['Sensitivity'],
svm_metrics['Sensitivity'],
knn_metrics['Sensitivity']),
Specificity = c(dt_metrics['Specificity'],
svm_metrics['Specificity'],
knn_metrics['Specificity'])
)
# Print the evaluation metrics
print(evaluation_metrics)
## Model Accuracy Kappa Sensitivity Specificity
## 1 Decision Tree 0.72 0.1784038 0.4166667 0.7083333
## 2 SVM 1.00 1.0000000 1.0000000 1.0000000
## 3 KNN 0.60 -0.1061947 0.2941176 0.6349206
# Convert the data to long format for ggplot2
evaluation_metrics_long <- evaluation_metrics %>%
pivot_longer(cols = -Model, names_to = "Metric", values_to = "Value")
# Plot the comparison of metrics
ggplot(evaluation_metrics_long, aes(x = Model, y = Value, fill = Metric)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Model Performance Comparison", x = "Model", y = "Value") +
theme_minimal()
Our study on the sales dataset focused on two important fields: sales predicting using regression and customer segmentation using RFM analysis.
Overall, this research offers useful information on the sales performance and customer behavior.
By exploiting these data and adopting the chosen models, marketing activities may be streamlined, resulting in improved consumer engagement and sales growth.