1 Case Study about Personal Life using 7 QC Tools

Problem Statement:

Dalam kehidupan sehari-hari, sering kali kita merasa kelelahan, kurang produktif, atau tidak mencapai target pribadi meskipun sudah menjalani rutinitas yang terasa sibuk. Untuk mengatasi hal ini secara sistematis, kita menggunakan 7 QC Tools untuk mengidentifikasi, menganalisis, dan mengatasi akar permasalahannya.

Tujuan Analisis:

Meningkatkan kualitas hidup pribadi dengan cara:

✅Mengidentifikasi aktivitas yang menyita waktu paling banyak

✅Menganalisis hubungan antara tidur dan energi

✅Menelusuri penyebab utama stres dan kelelahan

✅Menstabilkan berat badan secara mingguan

✅Mengatur keuangan harian lebih baik

Logo

1.1 Data Dummy

Variabel:

  1. Tanggal (Date)

  2. Durasi Tidur (Sleep_Duration:jam)

  3. Level Energi (Energy_Level: skala 1-10)

  4. Jenis Aktivitas Harian (Activity_Type: tidur, kerja, olahraga, dsb)

  5. Durasi Aktivitas (jam) (Activity_hours)

  6. Berat Badan Mingguan (Weight_Weekly)

  7. Biaya Harian (Daily_Expense)

  8. Penyebab Stres (Stress_Causes)

# Ensure all required packages are installed
packages <- c("dplyr", "stringi", "lubridate", "DT")
new_packages <- packages[!(packages %in% installed.packages()[, "Package"])]
if(length(new_packages)) install.packages(new_packages)

# Load libraries
library(dplyr)
library(stringi)
library(lubridate)
library(DT)

# Set seed & generate dates
set.seed(123)
n <- 180  # 6 months of data
dates <- seq.Date(from = as.Date("2024-01-01"), by = "day", length.out = n)

# Generate dummy data
sleep_duration <- round(rnorm(n, mean = 6.5, sd = 1.2), 1)
energy_level <- round(10 - abs(sleep_duration - 7) + rnorm(n, 0, 1), 1)
energy_level <- pmax(pmin(energy_level, 10), 1)

activity_types <- c("Work", "Exercise", "Sleep", "Leisure", "Housework")
activity_data <- sample(activity_types, n, replace = TRUE)
activity_hours <- round(runif(n, 0.5, 8), 1)

weekly_weight <- round(rnorm(n, mean = 65, sd = 3), 1)
daily_expense <- round(rnorm(n, mean = 100000, sd = 25000), 0)

stress_causes <- c("Workload", "Lack of sleep", "Traffic", "Deadlines", "Financial")
stress_cause <- sample(stress_causes, n, replace = TRUE)

# Combine into one dataset
personal_life_data <- tibble(
  Date = dates,
  Sleep_Duration = sleep_duration,
  Energy_Level = energy_level,
  Activity_Type = activity_data,
  Activity_Hours = activity_hours,
  Weight_Weekly = weekly_weight,
  Daily_Expense = daily_expense,
  Stress_Cause = stress_cause
)

# Show the dataset
datatable(
  personal_life_data,
  extensions = 'Buttons',
  options = list(
    dom = 'Bfrtip',
    buttons = c('copy', 'csv', 'excel', 'pdf', 'print'),
    scrollY = "400px",
    scrollCollapse = TRUE,
    paging = FALSE
  ),
  caption = htmltools::tags$caption(
    style = 'caption-side: top; text-align: left; 
             font-size: 18px; font-weight: bold;',
    "Personal Life Monitoring Dataset"
  ),
  class = 'stripe hover compact'
)

1.2 Checksheet

Tujuan:

Mencatat variabel kesehatan harian secara menyeluruh guna mengidentifikasi pola, anomali, dan faktor-faktor yang berpengaruh terhadap kondisi fisik dan kesejahteraan.

Variabel yang Dicatat:

  • Tanggal

  • Usia

  • BMI (Indeks Massa Tubuh)

  • Tekanan Darah (Sistolik)

  • Kadar Kolesterol (mg/dL)

  • Kadar Glukosa (mg/dL)

  • Denyut Jantung (bpm)

  • Lokasi Tinggal

  • Kondisi Kesehatan Umum

    (Seperti: Sehat, Hipertensi, Diabetes, Obesitas, Penyakit Kardiovaskular)

  • *Musim (Hujan, Kemarau, Peralihan)**

Alasan Mencatat Semua Variabel: - Memberikan konteks lengkap untuk analisis mendalam di tahap selanjutnya (Histogram, Scatter Diagram, Control Chart, dll). - Mengidentifikasi pola interaksi antar variabel (misalnya hubungan antara tekanan darah dan musim). - Memungkinkan pembuatan multi-dimensional insights untuk pengambilan keputusan terkait gaya hidup atau kesehatan.

1.2.1 Data Check Sheet

Data mentah yang berisi catatan penyebab stres harian dalam kehidupan pribadi yang berguna untuk mendeteksi frekuensi dan pola:

# Tampilkan data hanya kolom tanggal dan penyebab stres
checksheet_data <- personal_life_data %>%
  select(Date, Stress_Cause)

datatable(
  checksheet_data,
  extensions = 'Buttons',
  options = list(
    dom = 'Bfrtip',
    buttons = c('copy', 'csv', 'excel', 'pdf', 'print'),
    pageLength = 10
  ),
  caption = htmltools::tags$caption(
    style = 'caption-side: top; text-align: left; 
             font-size: 18px; font-weight: bold;',
    "Check Sheet – Catatan Harian Penyebab Stres"
  ),
  class = 'stripe hover compact'
)

1.2.2 Frequency Tabulation:

Menampilkan jumlah kemunculan masing-masing penyebab stres dalam periode 6 bulan:

# Tabulasi frekuensi penyebab stres
stress_freq <- personal_life_data %>%
  count(Stress_Cause, sort = TRUE)

datatable(
  stress_freq,
  colnames = c("Penyebab Stres", "Frekuensi"),
  caption = htmltools::tags$caption(
    style = 'caption-side: top; text-align: left; 
             font-size: 18px; font-weight: bold;',
    "Check Sheet – Frekuensi Penyebab Stres"
  ),
  class = 'stripe hover compact'
)

1.2.3 Simple Visualization

# Pastikan plotly sudah terpasang
if(!require(plotly)) install.packages("plotly")
library(plotly)

# Rename untuk konsistensi
reason_summary <- personal_life_data %>%
  count(Stress_Cause, name = "Frequency") %>%
  rename(Reason = Stress_Cause)

# Plot interaktif horizontal
plot_ly(
  reason_summary,
  x = ~Frequency,
  y = ~reorder(Reason, Frequency),
  type = 'bar',
  orientation = 'h',
  marker = list(
    color = ~Frequency,
    colorscale = 'twilight',  # Ganti dengan twilight sesuai permintaan
    showscale = TRUE
  )
) %>%
  layout(
    title = list(text = "Check Sheet: Frekuensi Penyebab Stres", font = list(size = 18)),
    xaxis = list(title = "Frekuensi"),
    yaxis = list(title = "Penyebab"),
    margin = list(l = 120)
  )

1.3 Histogram

Untuk melihat distribusi waktu olahraga dalam sebulan. Dengan ini, kita bisa mengevaluasi apakah waktu olahraga kamu sudah konsisten atau masih fluktuatif.

# Pastikan plotly terinstal
if(!require(plotly)) install.packages("plotly")
library(plotly)

# Filter aktivitas olahraga selama 30 hari terakhir
exercise_data <- personal_life_data %>%
  filter(Activity_Type == "Exercise") %>%
  filter(Date >= max(Date) - lubridate::days(30))

# Ambil hanya nilai jam aktivitas
exercise_hours <- exercise_data$Activity_Hours

# Hitung kurva densitas
density_data <- density(exercise_hours)

# Plot histogram interaktif dengan density curve
plot_ly() %>%
  add_trace(
    x = exercise_hours,
    type = 'histogram',
    name = 'Durasi Olahraga',
    nbinsx = 20,
    marker = list(
      color = 'lightblue',
      line = list(color = 'black', width = 1)
    ),
    opacity = 0.6
  ) %>%
  add_trace(
    x = density_data$x,
    y = density_data$y * length(exercise_hours) * diff(range(exercise_hours)) / 20,  # Scaling
    type = 'scatter',
    mode = 'lines',
    name = 'Kurva Densitas',
    line = list(color = 'darkblue', width = 3)
  ) %>%
  layout(
    title = 'Histogram Interaktif – Durasi Olahraga (30 Hari Terakhir)',
    xaxis = list(title = 'Durasi (Jam)', showgrid = FALSE),
    yaxis = list(title = 'Frekuensi / Densitas', showgrid = FALSE),
    bargap = 0.1,
    plot_bgcolor = 'white',
    paper_bgcolor = 'white',
    legend = list(
      orientation = 'v',
      x = 0.98,
      xanchor = 'right',
      y = 0.98,
      yanchor = 'top',
      bgcolor = 'rgba(255,255,255,0.8)',
      bordercolor = 'black',
      borderwidth = 0.3
    )
  )

1.4 Pareto Chart

untuk mengidentifikasi prioritas utama dari berbagai penyebab atau kategori berdasarkan dampaknya

# Load libraries
library(dplyr)
library(plotly)
library(RColorBrewer)

# Summarize the time spent on each activity
pareto_data <- personal_life_data %>%
  group_by(Activity_Type) %>%
  summarise(total_hours = sum(Activity_Hours)) %>%
  arrange(desc(total_hours)) %>%
  mutate(
    cum_freq = cumsum(total_hours) / sum(total_hours) * 100  # cumulative percentage
  )

# Create different colors for each Activity_Type
colors <- RColorBrewer::brewer.pal(n = length(pareto_data$Activity_Type), name = "Set3")

# Create Plotly Pareto Chart
fig <- plot_ly()

# Add Bar Chart (Total Hours) - with different colors
fig <- fig %>% add_bars(
  x = ~reorder(pareto_data$Activity_Type, -pareto_data$total_hours),
  y = ~pareto_data$total_hours,
  name = 'Total Hours Spent',
  marker = list(color = colors),
  yaxis = "y1"
)

# Add Cumulative Line
fig <- fig %>% add_lines(
  x = ~reorder(pareto_data$Activity_Type, -pareto_data$total_hours),
  y = ~pareto_data$cum_freq,
  name = 'Cumulative (%)',
  yaxis = "y2",
  line = list(color = 'red', dash = 'dash')
)

# Add Cut-off Line at 80%
fig <- fig %>% add_lines(
  x = ~reorder(pareto_data$Activity_Type, -pareto_data$total_hours),
  y = rep(80, length(pareto_data$Activity_Type)),
  name = 'Cut-off 80%',
  yaxis = "y2",
  line = list(color = 'green', dash = 'dot')
)

# Adjust layout
fig <- fig %>% layout(
  title = "Pareto Chart - Time Spent on Daily Activities",
  xaxis = list(
    title = "Activity Type",
    tickangle = -45   # tilt 45 degrees
  ),
  yaxis = list(title = "Total Hours Spent"),
  yaxis2 = list(
    title = "Cumulative (%)",
    overlaying = "y",
    side = "right",
    range = c(0, 100)
  ),
  legend = list(x = 0.8, y = 0.75),
  shapes = list(
    list(
      type = "line",
      x0 = -0.5,
      x1 = length(pareto_data$Activity_Type) - 0.5,
      y0 = 80,
      y1 = 80,
      yref = "y2",
      line = list(color = "green", width = 2, dash = "dot")
    )
  )
)

# Show chart
fig

1.5 Fishbone

untuk mengidentifikasi akar penyebab dari stres atau rasa lelah yang sering muncul dalam kehidupan pribadi, menggunakan pendekatan visual Fishbone Diagram (Diagram Ishikawa). Data yang digunakan berasal dari pemantauan harian selama enam bulan.

if (!require(DiagrammeR)) install.packages("DiagrammeR")
library(DiagrammeR)

grViz("
digraph fishbone {
  graph [rankdir = LR, layout = dot]
  node [shape = box, style = filled, fillcolor = lightgray]

  main [label = 'Stress / Fatigue', shape = ellipse, fillcolor = lightblue, fontsize=14]

  work [label = 'Work']
  physical [label = 'Physical']
  environment [label = 'Environment']
  financial [label = 'Financial']

  workload [label = 'Workload']
  deadlines [label = 'Deadlines']
  sleep [label = 'Lack of Sleep']
  traffic [label = 'Traffic']
  money [label = 'Financial Issues']

  main -> work
  main -> physical
  main -> environment
  main -> financial

  work -> workload
  work -> deadlines
  physical -> sleep
  environment -> traffic
  financial -> money
}
")
if (!require(DiagrammeR)) install.packages("DiagrammeR")
library(DiagrammeR)

grViz("
digraph fishbone {
  graph [layout = dot, rankdir = LR]

  node [fontname=Helvetica, fontsize=22, style=filled]

  # Masalah utama
  Problem [label='Stress / Fatigue', shape=ellipse, fillcolor=lightblue, width=5.0, height=1.2]

  # Kategori utama
  node [shape=diamond, width=2.5, height=1.0, fillcolor='#FFD700']
  A1 [label='Work']
  A2 [label='Physical']
  A3 [label='Environment']
  A4 [label='Financial']
  A5 [label='Social']
  A6 [label='Lifestyle']

  # Subfaktor
  node [shape=ellipse, width=2.5, height=0.6, fillcolor='#90EE90']
  A1a [label='Heavy Workload']
  A1b [label='Tight Deadlines']

  A2a [label='Lack of Sleep']
  A2b [label='Poor Diet']

  A3a [label='Traffic']
  A3b [label='Noise Pollution']

  A4a [label='Debt Pressure']
  A4b [label='Low Income']

  A5a [label='Family Conflict']
  A5b [label='Lack of Support']

  A6a [label='Lack of Exercise']
  A6b [label='Poor Time Management']

  # Hubungan utama ke kategori
  A1 -> Problem
  A2 -> Problem
  A3 -> Problem
  A4 -> Problem
  A5 -> Problem
  A6 -> Problem

  # Subfaktor ke kategori
  A1a -> A1
  A1b -> A1

  A2a -> A2
  A2b -> A2

  A3a -> A3
  A3b -> A3

  A4a -> A4
  A4b -> A4

  A5a -> A5
  A5b -> A5

  A6a -> A6
  A6b -> A6
}
")

1.6 Scatter Diagram

untuk melihat apakah ada tren atau korelasi yang jelas antara kedua variabel tersebut. Apakah durasi tidur yang lebih lama berhubungan dengan level energi yang lebih tinggi? Dengan menambahkan garis regresi linier, scatter plot ini juga menunjukkan apakah hubungan itu linear atau tidak.

# Install dan load paket yang dibutuhkan
if (!require(plotly)) install.packages("plotly")
library(plotly)

# Buat data contoh dengan hubungan antara durasi tidur dan level energi
set.seed(42)  # Untuk reprodusibilitas
data_tidur_energi <- data.frame(
  Durasi_Tidur = c(5, 6, 7, 8, 9, 10, 11, 5.5, 6.5, 7.5, 
                   8.5, 9.5, 6, 7, 8, 9, 10, 11, 6.5, 7.5),
  Level_Energi = c(3, 4, 5, 6, 7, 8, 9, 3.5, 4.5, 5.5, 
                   6.5, 7.5, 4, 5, 6, 7, 8, 9, 4.5, 5.5)
)

# Menambahkan sedikit noise untuk mendapatkan korelasi sekitar 0.8
data_tidur_energi$Level_Energi <- data_tidur_energi$Level_Energi + rnorm(n = 20, mean = 0, sd = 0.5)

# Hitung koefisien korelasi antara durasi tidur dan level energi
korelasi_value <- cor(data_tidur_energi$Durasi_Tidur, data_tidur_energi$Level_Energi)

# Buat scatter plot menggunakan Plotly dengan garis regresi linier
fig <- plot_ly(data_tidur_energi, 
               x = ~Durasi_Tidur, 
               y = ~Level_Energi, 
               type = 'scatter', 
               mode = 'markers',
               marker = list(color = 'blue', size = 10)) %>%
  add_lines(x = data_tidur_energi$Durasi_Tidur, 
            y = predict(lm(Level_Energi ~ Durasi_Tidur, data = data_tidur_energi)), 
            line = list(color = 'red', dash = 'solid', width = 2)) %>%
  layout(title = paste("Scatter Plot: Durasi Tidur vs Level Energi\nKorelasi: ", round(korelasi_value, 2)),
         xaxis = list(title = "Durasi Tidur (Jam)"),
         yaxis = list(title = "Level Energi (Skala 1-10)"))

# Tampilkan plot
fig

1.7 Control Chart

untuk memantau apakah berat badan mingguan berada dalam batas kontrol statistik yang sehat dan stabil. Ini membantu mendeteksi perubahan signifikan yang mungkin perlu tindakan, seperti pola makan atau olahraga.

# Install dan load paket yang dibutuhkan
if (!require(plotly)) install.packages("plotly")
library(plotly)
library(dplyr)
library(lubridate)

# Agregasi data berat badan per minggu
weekly_weight_data <- personal_life_data %>%
  mutate(Week = floor_date(Date, unit = "week")) %>%
  group_by(Week) %>%
  summarise(Avg_Weight = mean(Weight_Weekly)) %>%
  ungroup()

# Tentukan batas kendali
CL <- mean(weekly_weight_data$Avg_Weight)
UCL <- CL + 2 * sd(weekly_weight_data$Avg_Weight)  # Upper control limit (UCL)
LCL <- CL - 2 * sd(weekly_weight_data$Avg_Weight)  # Lower control limit (LCL)

# Tandai outliers
weekly_weight_data <- weekly_weight_data %>%
  mutate(Outlier = ifelse(Avg_Weight > UCL | Avg_Weight < LCL, "Ya", "Tidak"))

# Buat plot dengan Plotly
plot_ly(weekly_weight_data, x = ~Week, y = ~Avg_Weight, type = 'scatter', mode = 'lines+markers',
        line = list(color = 'blue'), 
        marker = list(size = 8, color = ifelse(weekly_weight_data$Outlier == "Ya", "red", "blue")),
        hoverinfo = 'text',
        text = ~paste("Minggu:", format(Week, "%d-%b-%Y"), "<br>Rata-rata Berat:", round(Avg_Weight, 1), "kg")) %>%
  add_lines(y = rep(CL, length(weekly_weight_data$Week)), name = "CL", line = list(color = 'green', dash = 'dot')) %>%
  add_lines(y = rep(UCL, length(weekly_weight_data$Week)), name = "UCL", line = list(color = 'red', dash = 'dot')) %>%
  add_lines(y = rep(LCL, length(weekly_weight_data$Week)), name = "LCL", line = list(color = 'red', dash = 'dot')) %>%
  layout(title = "Control Chart – Weekly Average Weight Tracking",
         xaxis = list(title = "Minggu"),
         yaxis = list(title = "Berat Mingguan (kg)"),
         legend = list(orientation = 'h', x = 0.3, y = -0.2))

1.8 Flowchart

library(DiagrammeR)

grViz("
digraph daily_routine {
  graph [layout=dot]
  node [style=filled, fontname='Helvetica']

  # Bagian kiri
  subgraph cluster_left {
    label = 'Pagi - Siang'
    rankdir = TB

    Start [label='Start', shape=ellipse, fillcolor=orange]
    Wake [label='Wake Up', shape=box, fillcolor=lightblue]
    Alarm [label='Alarm Rings', shape=box, fillcolor=lightblue]
    OnTime [label='On Time Check', shape=box, fillcolor=lightblue]
    MorningRoutine [label='Morning Routine', shape=box, fillcolor=lightblue]
    Shower [label='Shower', shape=box, fillcolor=lightblue]
    Breakfast [label='Breakfast', shape=box, fillcolor=lightblue]
    WorkMorning [label='Work (Morning)', shape=box, fillcolor=lightblue]
    StayFocused [label='Focus Level', shape=box, fillcolor=lightblue]
    Meeting [label='Meetings', shape=box, fillcolor=lightblue]
    BreakTime [label='Break Time', shape=box, fillcolor=lightblue]
    Connector1 [label='', shape=circle, width=0.3, fillcolor=gray]

    Start -> Wake -> Alarm -> OnTime -> MorningRoutine
    MorningRoutine -> Shower -> Breakfast -> WorkMorning
    WorkMorning -> StayFocused -> Meeting -> BreakTime -> Connector1
  }

  # Bagian kanan
  subgraph cluster_right {
    label = 'Siang - Malam'
    rankdir = TB

    Connector2 [label='', shape=circle, width=0.3, fillcolor=gray]
    Lunch [label='Lunch', shape=box, fillcolor=lightblue]
    Scroll [label='Scroll Phone', shape=box, fillcolor=lightblue]
    Chat [label='Chat with Friends', shape=box, fillcolor=lightblue]
    WorkAfternoon [label='Work (Afternoon)', shape=box, fillcolor=lightblue]
    ResumeWork [label='Resume Work', shape=box, fillcolor=lightblue]
    Tired [label='Feeling Tired', shape=box, fillcolor=lightblue]
    EveningRoutine [label='Evening Routine', shape=box, fillcolor=lightblue]
    Dinner [label='Dinner', shape=box, fillcolor=lightblue]
    Relax [label='Relax / Netflix', shape=box, fillcolor=lightblue]
    TrySleep [label='Try to Sleep', shape=box, fillcolor=lightblue]
    Sleep [label='Go to Sleep', shape=box, fillcolor=lightblue]
    End [label='Finish', shape=ellipse, fillcolor=orange]

    Connector2 -> Lunch -> Scroll -> Chat -> WorkAfternoon
    WorkAfternoon -> ResumeWork -> Tired -> EveningRoutine
    EveningRoutine -> Dinner -> Relax -> TrySleep -> Sleep -> End
  }

  # Sambungan horizontal
  Connector1 -> Connector2 [arrowhead=none, style=dashed, constraint=false]
}
")