Check quality
No nulls and no duplicates. I used describe() to look for odd values and found a negative age.
Why do patients miss their appointments? I cleaned 110,000+ records, tested seven ideas, and found that waiting time matters far more than anything else.
No nulls and no duplicates. I used describe() to look for odd values and found a negative age.
1 patient with age −1, and 5 appointments scheduled after the appointment day (all five were no-shows).
Why: they can’t be real, and keeping them would distort the rates.
Renamed misspelt columns (Handcap, Hipertension, No-show), split date and time, and dropped the appointment time because it was always midnight.
The Handicap column held 0–4. The dataset describes it as true/false, so I turned it into 0/1 like the other condition columns.
Why: consistent flags make fair comparisons possible.
No. Women had a 20.3% no-show rate and men 20.0%, a negligible gap.
Yes. Ages 10–29 miss the most (about 24–25%). Ages 50–89 miss the least (about 15–17%).
Patients with chronic conditions attend more: hypertension 17.3% vs 20.9%, diabetes 18.0% vs 20.4%.
Surprisingly, SMS recipients missed more (27.6% vs 16.7%). That led me to question causation.
Strongly. 4.6% for same-day, 24.1% for 1–7 days, 31.7% for 8–30 days and 33.0% for 31+ days.
Somewhat: 8.6% to 28.9% among areas with 30+ appointments. I excluded tiny areas (1–2 appointments) that gave misleading 0% and 100% rates.
Attendance improves as conditions increase: 20.9% with none, 15.7% with three or more.





# one record with a negative age
data.drop(data[data["Age"] < 0].index, inplace=True)
# fix column-name typos
data.rename(columns={"Handcap": "Handicap", "Hipertension": "Hypertension", "No-show": "No_show"}, inplace=True)
# appointments scheduled AFTER the appointment day make no sense
data.drop(data[data["Scheduled_Date"] > data["Appointment_Date"]].index, inplace=True)
# handicap should be yes/no like the other flags, not a count
data["Handicap"] = data["Handicap"].apply(lambda x: 1 if x > 0 else 0)data["Waiting_Days"] = (pd.to_datetime(data["Appointment_Date"]) - pd.to_datetime(data["Scheduled_Date"])).dt.days
bins = [-1, 0, 7, 30, 179]
labels = ["Same day", "1-7 days", "8-30 days", "31+ days"]
data["Waiting_Group"] = pd.cut(data["Waiting_Days"], bins=bins, labels=labels)
noshow_by_waiting = data.groupby("Waiting_Group")["No_show"].apply(lambda x: (x == "Yes").mean() * 100).round(1)
print(noshow_by_waiting)Longer delays lead to many more missed appointments.
Older patients attend more consistently.
Probably because of routine follow-ups.
Gender-targeted campaigns aren’t justified.
Offer earlier slots or extra reminders for appointments booked more than 7 days ahead.
Send more than one reminder for long-wait appointments (at booking and a few days before).
Try channels young patients use, such as app notifications or WhatsApp.
Santos Dumont and Santa Cecília (about 28%) may have access barriers.
Use similar tracking and reminder systems for all patients.