|
|
|
import streamlit as st |
|
import pandas as pd |
|
import altair as alt |
|
import matplotlib.pyplot as plt |
|
import seaborn as sns |
|
|
|
|
|
@st.cache_data |
|
def load_data(): |
|
|
|
file_path = 'https://raw.githubusercontent.com/aaubs/ds-master/main/apps/M1-attrition-streamlit/HR-Employee-Attrition-synth.csv' |
|
|
|
|
|
df = pd.read_csv(file_path) |
|
|
|
|
|
bin_edges = [18, 25, 35, 45, 60] |
|
bin_labels = ['18-24', '25-34', '35-44', '45-60'] |
|
df['AgeGroup'] = pd.cut(df['Age'], bins=bin_edges, labels=bin_labels, right=False) |
|
|
|
return df |
|
|
|
|
|
df = load_data() |
|
|
|
|
|
st.title("Employee Attrition Dashboard ππ") |
|
st.sidebar.header("Filters π") |
|
|
|
|
|
|
|
|
|
|
|
st.markdown(""" |
|
Welcome to the HR Attrition Dashboard. In the backdrop of rising employee turnovers, HR departments are stressing the significance of predicting and understanding employee departures. Through the lens of data analytics, this dashboard unveils the deeper causes of employee churn and proposes strategies to boost employee retention. |
|
""") |
|
with st.expander("π **Objective**"): |
|
st.markdown(""" |
|
At the heart of this dashboard is the mission to visually decode data, equipping HR experts with insights to tackle these queries: |
|
- Which company factions face a greater likelihood of employee exits? |
|
- What might be pushing these individuals to part ways? |
|
- Observing the discerned trends, what incentives might hold the key to decreasing the attrition rate? |
|
""" |
|
) |
|
|
|
|
|
with st.expander("How to Use the Dashboard π"): |
|
st.markdown(""" |
|
1. **Filter Data** - Use the sidebar filters to narrow down specific data sets. |
|
2. **Visualize Data** - From the dropdown, select a visualization type to view patterns. |
|
3. **Insights & Recommendations** - Scroll down to see insights derived from the visualizations and actionable recommendations. |
|
""") |
|
|
|
|
|
|
|
selected_age_group = st.sidebar.multiselect("Select Age Groups π°οΈ", df['AgeGroup'].unique().tolist(), default=df['AgeGroup'].unique().tolist()) |
|
if not selected_age_group: |
|
st.warning("Please select an age group from the sidebar β οΈ") |
|
st.stop() |
|
filtered_df = df[df['AgeGroup'].isin(selected_age_group)] |
|
|
|
|
|
departments = df['Department'].unique().tolist() |
|
selected_department = st.sidebar.multiselect("Select Departments π’", departments, default=departments) |
|
if not selected_department: |
|
st.warning("Please select a department from the sidebar β οΈ") |
|
st.stop() |
|
filtered_df = filtered_df[filtered_df['Department'].isin(selected_department)] |
|
|
|
|
|
min_income = int(df['MonthlyIncome'].min()) |
|
max_income = int(df['MonthlyIncome'].max()) |
|
income_range = st.sidebar.slider("Select Monthly Income Range π°", min_income, max_income, (min_income, max_income)) |
|
filtered_df = filtered_df[(filtered_df['MonthlyIncome'] >= income_range[0]) & (filtered_df['MonthlyIncome'] <= income_range[1])] |
|
|
|
|
|
satisfaction_levels = sorted(df['JobSatisfaction'].unique().tolist()) |
|
selected_satisfaction = st.sidebar.multiselect("Select Job Satisfaction Levels π", satisfaction_levels, default=satisfaction_levels) |
|
if not selected_satisfaction: |
|
st.warning("Please select a job satisfaction level from the sidebar β οΈ") |
|
st.stop() |
|
filtered_df = filtered_df[filtered_df['JobSatisfaction'].isin(selected_satisfaction)] |
|
|
|
|
|
st.header("Attrition Analysis π") |
|
|
|
|
|
visualization_option = st.selectbox( |
|
"Select Visualization π¨", |
|
["Attrition by Age Group", |
|
"KDE Plot: Distance from Home by Attrition", |
|
"Attrition by Job Role", |
|
"Attrition Distribution by Gender", |
|
"MonthlyRate and DailyRate by JobLevel"] |
|
) |
|
|
|
|
|
if visualization_option == "Attrition by Age Group": |
|
|
|
chart = alt.Chart(filtered_df).mark_bar().encode( |
|
x='AgeGroup', |
|
y='count()', |
|
color='Attrition' |
|
).properties( |
|
title='Attrition Rate by Age Group' |
|
) |
|
st.altair_chart(chart, use_container_width=True) |
|
|
|
elif visualization_option == "KDE Plot: Distance from Home by Attrition": |
|
|
|
plt.figure(figsize=(10, 6)) |
|
sns.kdeplot(data=filtered_df, x='DistanceFromHome', hue='Attrition', fill=True, palette='Set2') |
|
plt.xlabel('Distance From Home') |
|
plt.ylabel('Density') |
|
plt.title('KDE Plot of Distance From Home by Attrition') |
|
st.pyplot(plt) |
|
|
|
elif visualization_option == "Attrition by Job Role": |
|
|
|
chart = alt.Chart(filtered_df).mark_bar().encode( |
|
y='JobRole', |
|
x='count()', |
|
color='Attrition' |
|
).properties( |
|
title='Attrition by Job Role' |
|
) |
|
st.altair_chart(chart, use_container_width=True) |
|
|
|
elif visualization_option == "Attrition Distribution by Gender": |
|
|
|
pie_chart_data = filtered_df[filtered_df['Attrition'] == 'Yes']['Gender'].value_counts().reset_index() |
|
pie_chart_data.columns = ['Gender', 'count'] |
|
|
|
chart = alt.Chart(pie_chart_data).mark_arc().encode( |
|
theta='count:Q', |
|
color='Gender:N', |
|
tooltip=['Gender', 'count'] |
|
).properties( |
|
title='Attrition Distribution by Gender', |
|
width=300, |
|
height=300 |
|
).project('identity') |
|
st.altair_chart(chart, use_container_width=True) |
|
|
|
elif visualization_option == "MonthlyRate and DailyRate by JobLevel": |
|
|
|
fig, ax = plt.subplots(1, 2, figsize=(15, 7)) |
|
|
|
|
|
sns.boxplot(x="JobLevel", y="MonthlyRate", data=filtered_df, ax=ax[0], hue="JobLevel", palette='Set2', legend=False) |
|
ax[0].set_title('MonthlyRate by JobLevel') |
|
ax[0].set_xlabel('Job Level') |
|
ax[0].set_ylabel('Monthly Rate') |
|
|
|
|
|
sns.boxplot(x="JobLevel", y="DailyRate", data=filtered_df, ax=ax[1], hue="JobLevel", palette='Set2', legend=False) |
|
ax[1].set_title('DailyRate by JobLevel') |
|
ax[1].set_xlabel('Job Level') |
|
ax[1].set_ylabel('Daily Rate') |
|
|
|
plt.tight_layout() |
|
st.pyplot(fig) |
|
|
|
|
|
st.header("Dataset Overview") |
|
st.dataframe(df.describe()) |
|
|
|
|
|
|
|
with st.expander("Insights from Visualization π§ "): |
|
st.markdown(""" |
|
1. **Age Groups & Attrition** - The 'Attrition by Age Group' plot showcases which age brackets face higher attrition. |
|
2. **Home Distance's Impact** - The 'KDE Plot: Distance from Home by Attrition' visualizes if being farther away influences leaving tendencies. |
|
3. **Roles & Attrition** - 'Attrition by Job Role' reveals which roles might be more attrition-prone. |
|
4. **Gender & Attrition** - The pie chart for 'Attrition Distribution by Gender' provides insights into any gender-based patterns. |
|
5. **Earnings Patterns** - 'MonthlyRate and DailyRate by JobLevel' boxplots display the compensation distribution across job levels. |
|
""") |
|
|
|
|
|
with st.expander("Recommendations for Action π"): |
|
st.markdown(""" |
|
- π **Incentive Programs:** Introduce incentives tailored for groups showing higher attrition tendencies. |
|
- π‘ **Remote Work Options:** Providing flexibility, especially for those living farther from the workplace, could reduce attrition. |
|
- π **Training & Growth:** Invest in employee development, especially in roles with higher attrition rates. |
|
- π« **Gender Equality:** Foster an environment that supports equal opportunities regardless of gender. |
|
- πΈ **Compensation Review:** Regularly review and adjust compensation structures to stay competitive and retain talent. |
|
""") |