Spaces:
Sleeping
Sleeping
import streamlit as st | |
import pandas as pd | |
import numpy as np | |
import seaborn as sns | |
import matplotlib.pyplot as plt | |
# from phik.report import plot_correlation_matrix | |
from PIL import Image | |
st.set_option('deprecation.showPyplotGlobalUse', False) | |
#membuat function untuk nantinya dipanggil di app.py | |
def run(): | |
st.title('Welcome to Exploratory Data Analysis') | |
# Load Data from CSV | |
df = pd.read_csv('customer_churn.csv') | |
# Central Tendency | |
st.title('Central Tendency Data') | |
# Checking Central Tendency Numerical Data | |
df_describe = df.describe().T | |
df_describe = df_describe.apply(lambda x: x.map('{:.2f}'.format)) | |
df_describe = pd.DataFrame(df_describe) | |
df_describe | |
# Showing Explanation | |
with st.expander('Explanation'): | |
st.caption("From central tendency we can get information related to count, mean, standard deviation, min, max, q1, q2, q3 from each column containing numeric data. The std values of the columns are quite large, meaning that the range between data values is large, indicating that there are outliers in some columns. The min and max values in Price's column are quite far away.") | |
# Target Visualization | |
st.title('Target Exploration Churn Pie & Bar Chart') | |
# Setting up the figure for subplots | |
plt.figure(figsize=(14, 7)) | |
# Subplot 1: Pie chart for distribution of non-default payments | |
plt.subplot(1, 2, 1) # 1 row, 2 columns, 1st subplot | |
non_default_counts = df['Churn'].value_counts(normalize=True) | |
plt.pie(non_default_counts, labels=['Not Churn (' + str(non_default_counts[0]*100)[:4] + '%)', 'Churn (' + str(non_default_counts[1]*100)[:4] + '%)'], autopct='%1.1f%%', startangle=140, colors=['crimson', 'coral']) | |
plt.title('Distribution of Customer Churn') | |
# Subplot 2: Bar chart for count of non-default vs default payments | |
plt.subplot(1, 2, 2) # 1 row, 2 columns, 2nd subplot | |
barplot = sns.countplot(x='Churn', data=df, palette=['crimson', 'coral']) | |
plt.title('Count of Customer Churn') | |
plt.xticks([0, 1], ['Not Churn', 'Churn']) | |
plt.xlabel('Churn Status') | |
plt.ylabel('Count') | |
# Adding count labels above each bar | |
for p in barplot.patches: | |
barplot.annotate(format(p.get_height(), '.0f'), | |
(p.get_x() + p.get_width() / 2., p.get_height()), | |
ha = 'center', | |
va = 'center', | |
xytext = (0, 10), | |
textcoords = 'offset points') | |
# Show the plot | |
plt.tight_layout() | |
st.pyplot() | |
# Showing Explanation | |
with st.expander('Explanation'): | |
st.caption('From the visualization, we can see that a large number of customers Not Churn 33881 (52.6%) and those who will be Churn 30493 (47.4%). In my opinion, this number is a pretty bad number for the company, because customers who Not Churn and those who do Churn are only a very small difference so it is necessary to improve both technically and non-technically.') | |
# Age Distribution | |
st.title('Age Distribution by Customer Churn') | |
# Histogram for the 'age' column | |
plt.figure(figsize=(14, 7)) | |
sns.histplot(x='Age', hue='Churn', data=df , bins=30, kde=True) | |
plt.title('Age Distribution by Customer Churn') | |
plt.xlabel('Age') | |
plt.ylabel('Frequency') | |
st.pyplot() | |
# Showing Explanation | |
with st.expander('Explanation'): | |
st.caption('The distribution of ages appears roughly symmetrical, with a slight right skew. We can see that the frequency of churn is less than the frequency of continued service across all age groups.') | |
# Gender | |
st.title('Customer Churn by Gender') | |
# Churn rates by gender from the previous calculation | |
churn_rates = { | |
'Female': 0.587951, | |
'Male': 0.412049 | |
} | |
# Data to plot | |
labels = churn_rates.keys() | |
sizes = churn_rates.values() | |
colors = ['#ff9999','#66b3ff'] # pink for female, light blue for male | |
explode = (0.1, 0) # explode 1st slice for emphasis | |
# Plotting the pie chart | |
plt.figure(figsize=(8, 6)) | |
plt.pie(sizes, explode=explode, labels=labels, colors=colors, autopct='%1.1f%%', | |
shadow=True, startangle=140) | |
plt.axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle. | |
plt.title('Churn Rate by Gender') | |
st.pyplot() | |
# Showing Explanation | |
with st.expander('Explanation'): | |
st.caption('We can see from the results of the pierchart visualization above, where the possibility of churn rates in the female gender tends to be more than men, where women 58.8% and men 41.2% of the total data, from these results we can later make improvements to maintain female gender customers.') | |
# Hist | |
st.title('Customer Churn by Subscription Type') | |
# Calculate churn rate by subscription type | |
churn_rate_by_subscription = df.groupby('Subscription Type')['Churn'].mean() | |
# normalized the calculation | |
churn_rate_by_subscription_normalized = churn_rate_by_subscription / churn_rate_by_subscription.sum() | |
# Plot the churn rate by subscription type | |
plt.figure(figsize=(14, 7)) | |
churn_rate_by_subscription_normalized.plot(kind='bar', color='lightsalmon', title='Churn Rate by Subscription Type') | |
plt.xlabel('Subscription Type') | |
plt.ylabel('Churn Rate') | |
plt.xticks(rotation=0) | |
# Add labels on each bar | |
for i, rate in enumerate(churn_rate_by_subscription_normalized): | |
plt.text(i, rate, f'{rate:.4f}', ha='center', va='bottom') | |
st.pyplot() | |
# Showing Explanation | |
with st.expander('Explanation'): | |
st.caption('For Further Analysis Since churn rates are similar, it suggests that factors other than subscription type may have a more significant impact on churn. And for Business Strategy A churn rate approaching 50% warrants a detailed examination of customer service practices, product quality, pricing strategy, and competitive pressures. Strategies need to be implemented to enhance customer satisfaction and loyalty across all subscription types.') | |
# Contract Length | |
st.title('Customer Churn by Contract Length') | |
# Group the data by 'Contract Length' and calculate the mean churn for each contract length | |
churn_rate_by_contract_length = df.groupby('Contract Length')['Churn'].mean() | |
# normalized the calculation | |
churn_rate_by_contract_length_normalized = churn_rate_by_contract_length / churn_rate_by_contract_length.sum() | |
# Plot the churn rate by contract length | |
plt.figure(figsize=(10, 6)) | |
sns.barplot(x=churn_rate_by_contract_length_normalized.index, y=churn_rate_by_contract_length_normalized.values) | |
plt.title('Churn Rate by Contract Length') | |
plt.xlabel('Contract Length (months)') | |
plt.ylabel('Churn Rate') | |
plt.xticks(rotation=0) # If there are many contract lengths, rotating the x-ticks can help with readability | |
plt.tight_layout() # This will ensure that the labels and titles fit well in the plot area | |
# Add labels on each bar | |
for i, rate in enumerate(churn_rate_by_contract_length_normalized): | |
plt.text(i, rate, f'{rate:.4f}', ha='center', va='bottom') | |
st.pyplot() | |
# Showing Explanation | |
with st.expander('Explanation'): | |
st.caption("The company might consider encouraging customers to sign up for longer contracts through incentives, as this could help reduce churn rates. However, since even annual contracts have a relatively high churn rate, it's essential to explore why customers are leaving and address those issues directly.") | |
# Total Spend | |
st.title('Customer Churn by Total Spend') | |
# Histogram for the 'Total Spend' column | |
# Set the color palette | |
plt.figure(figsize=(14, 7)) | |
sns.histplot(x='Total Spend', hue='Churn', data=df , bins=30, kde=True) | |
plt.title('Total Spend Distribution by Customer Churn') | |
plt.xlabel('Total Spend') | |
plt.ylabel('Frequency') | |
st.pyplot() | |
# Showing Explanation | |
with st.expander('Explanation'): | |
st.caption('The company might consider focusing retention efforts on customers in the lower to mid spend ranges, where the churn seems to be more prevalent. Incentivizing increased spend among these customers might be one strategy if indeed higher spend is associated with lower churn.') | |