"""Reproducible analysis for: Descriptive-Correlational Survey: Study Habits and Academic Performance

Generated by thericerca on 2026-10-24 19:14 UTC.
Regenerate the same statistical output on the same data by running this script (or the
matching .ipynb) with the third-party libraries at the top installed.

Statement of the problem:
  This study describes the study habits of college students and determines whether those habits are related to their academic performance.

Objectives:
  - To describe the profile of the respondents in terms of sex and year_level.
  - To describe the study habits of the respondents in terms of sets_a_study_schedule, takes_organized_notes, reviews_lessons_daily, studies_in_a_quiet_place, and avoids_distractions.
  - To determine the relationship between study_habits_score and general_weighted_average.
  - To determine whether general_weighted_average differs between the sex groups.

"""

import pandas as pd
import numpy as np
from scipy import stats
import statsmodels.api as sm
import statsmodels.formula.api as smf


# Load the dataset. Point this at your local copy of 'study_habits_survey.csv'.
df = pd.read_csv('study_habits_survey.csv')
print(f'Loaded {len(df)} rows, {len(df.columns)} columns.')
df.head()


# ------------------------------------------------------------------------------
# [1/5] Frequency & Percentage Distribution
#   Question: To describe the profile of the respondents in terms of sex and year_level.
# ------------------------------------------------------------------------------
# Frequency & percentage distribution for each categorical variable.
vc = df['sex'].value_counts(dropna=False)
print(pd.DataFrame({'n': vc, 'pct': (vc / vc.sum() * 100).round(2)}))
vc = df['year_level'].value_counts(dropna=False)
print(pd.DataFrame({'n': vc, 'pct': (vc / vc.sum() * 100).round(2)}))


# ------------------------------------------------------------------------------
# [2/5] Frequency & Percentage Distribution
#   Question: To describe the study habits of the respondents in terms of sets_a_study_schedule, takes_organized_notes, reviews_lessons_daily, studies_in_a_quiet_place, and avoids_distractions.
# ------------------------------------------------------------------------------
# Frequency & percentage distribution for each categorical variable.
vc = df['sets_a_study_schedule'].value_counts(dropna=False)
print(pd.DataFrame({'n': vc, 'pct': (vc / vc.sum() * 100).round(2)}))
vc = df['takes_organized_notes'].value_counts(dropna=False)
print(pd.DataFrame({'n': vc, 'pct': (vc / vc.sum() * 100).round(2)}))
vc = df['reviews_lessons_daily'].value_counts(dropna=False)
print(pd.DataFrame({'n': vc, 'pct': (vc / vc.sum() * 100).round(2)}))
vc = df['studies_in_a_quiet_place'].value_counts(dropna=False)
print(pd.DataFrame({'n': vc, 'pct': (vc / vc.sum() * 100).round(2)}))
vc = df['avoids_distractions'].value_counts(dropna=False)
print(pd.DataFrame({'n': vc, 'pct': (vc / vc.sum() * 100).round(2)}))


# ------------------------------------------------------------------------------
# [3/5] Weighted Mean with Verbal Interpretation
#   Question: To describe the study habits of the respondents in terms of sets_a_study_schedule, takes_organized_notes, reviews_lessons_daily, studies_in_a_quiet_place, and avoids_distractions.
# ------------------------------------------------------------------------------
# Weighted mean per item with a verbal interpretation, plus the overall weighted mean.
items = df[['sets_a_study_schedule', 'takes_organized_notes', 'reviews_lessons_daily', 'studies_in_a_quiet_place', 'avoids_distractions']].apply(pd.to_numeric, errors='coerce')
lo, hi = items.min().min(), items.max().max()  # scale taken from the responses
labels = ['Strongly Disagree', 'Disagree', 'Neutral', 'Agree', 'Strongly Agree']
width = (hi - lo) / len(labels)
edges = [lo + i * width for i in range(len(labels) + 1)]

def interpret(m):
    for i, label in enumerate(labels):
        if edges[i] <= m < edges[i + 1] or (i == len(labels) - 1 and m <= edges[-1]):
            return label
    return labels[0] if m < edges[0] else labels[-1]

means = items.mean()  # keep full precision: a mean of 3.3951 displays as 3.40 but is not 'Agree'
summary = pd.DataFrame({
    'n': items.count(),
    'weighted_mean': means.round(2),
    'median': items.median(),
    'sd': items.std(ddof=1).round(2),
})
summary['interpretation'] = means.map(interpret)
summary['rank'] = means.rank(ascending=False, method='min').astype(int)
print(summary)
overall = items.mean().mean()
print(f'Overall weighted mean = {overall:.2f} ({interpret(overall)})')


# ------------------------------------------------------------------------------
# [4/5] Spearman Rank Correlation
#   Question: To determine the relationship between study_habits_score and general_weighted_average.
# ------------------------------------------------------------------------------
a, b = df['study_habits_score'].dropna(), df['general_weighted_average'].dropna()
pair = pd.concat([a, b], axis=1).dropna()
rho, p_value = stats.spearmanr(pair.iloc[:, 0], pair.iloc[:, 1])
print(f'rho = {rho:.3f}, p = {p_value:.4g}, n = {len(pair)}')


# ------------------------------------------------------------------------------
# [5/5] Independent-Samples t-Test
#   Question: To determine whether general_weighted_average differs between the sex groups.
# ------------------------------------------------------------------------------
groups = [g.dropna().values for _, g in df.groupby('sex')['general_weighted_average']]
assert len(groups) == 2, 'Independent t-test needs exactly two groups.'
t, p_value = stats.ttest_ind(groups[0], groups[1], equal_var=True)
n1, n2 = len(groups[0]), len(groups[1])
sp = np.sqrt(((n1-1)*np.var(groups[0], ddof=1) + (n2-1)*np.var(groups[1], ddof=1)) / (n1+n2-2))
d = (np.mean(groups[0]) - np.mean(groups[1])) / sp
print(f't({n1+n2-2}) = {t:.3f}, p = {p_value:.4g}, Cohen d = {d:.3f}')


# ------------------------------------------------------------------------------
# End of thericerca reproducible analysis.
# ------------------------------------------------------------------------------
