import argparse
import json
import os
import sys
import numpy as np
import pandas as pd
from scipy import stats
def convert_categorical_to_numeric(df, dataset_name):
non_numeric_cols = df.select_dtypes(exclude=[np.number]).columns.tolist()
if non_numeric_cols:
print(f"INFO: Dataset '{dataset_name}' contains non-numeric columns: "
f"{', '.join(non_numeric_cols)}")
print("Converting categorical variables to numeric representations...")
for col in non_numeric_cols:
df[col], uniques = pd.factorize(df[col])
print(f" {col}: {len(uniques)} unique values -> integer level encoding")
return df
def parse_args():
parser = argparse.ArgumentParser(description='Shapiro-Wilk test validation')
parser.add_argument('--csv', required=True, help='Path to CSV file')
parser.add_argument('--output-dir', default='../../results/python', help='Path to output directory')
return parser.parse_args()
def main():
args = parse_args()
csv_file = args.csv
if not os.path.exists(csv_file):
print(f"Error: File not found: {csv_file}", file=sys.stderr)
sys.exit(1)
dataset_name = os.path.splitext(os.path.basename(csv_file))[0]
data = pd.read_csv(csv_file)
data = convert_categorical_to_numeric(data, dataset_name)
data = data.values
y = data[:, 0]
if data.shape[1] > 1:
x_vars = data[:, 1:]
else:
x_vars = None
if x_vars is None:
residuals = y - np.mean(y)
else:
X = np.column_stack([np.ones(len(y)), x_vars])
try:
beta = np.linalg.solve(X.T @ X, X.T @ y)
except np.linalg.LinAlgError:
beta = np.linalg.lstsq(X, y, rcond=None)[0]
residuals = y - X @ beta
w_statistic, p_value = stats.shapiro(residuals)
alpha = 0.05
passed = p_value > alpha
if passed:
interpretation = (
f"p-value = {p_value:.4f} is greater than {alpha:.2f}. "
f"Cannot reject H0. No significant evidence that residuals deviate from normality."
)
guidance = ("The normality assumption appears to be met. Shapiro-Wilk test does not detect "
"significant deviation from normal distribution.")
else:
interpretation = (
f"p-value = {p_value:.4f} is less than or equal to {alpha:.2f}. "
f"Reject H0. Significant evidence that residuals deviate from normality."
)
guidance = ("Consider transforming the dependent variable (e.g., log, Box-Cox transformation), "
"using robust standard errors, or applying a different estimation method.")
output = {
"test_name": "Shapiro-Wilk Test for Normality",
"statistic": float(w_statistic),
"p_value": float(p_value),
"is_passed": bool(passed),
"interpretation": interpretation,
"guidance": guidance
}
basename = os.path.splitext(os.path.basename(csv_file))[0]
output_file = os.path.join(args.output_dir, f"{basename}_shapiro_wilk.json")
if not os.path.exists(args.output_dir):
os.makedirs(args.output_dir, exist_ok=True)
with open(output_file, 'w') as f:
json.dump(output, f, indent=2)
print(f"Results written to: {output_file}")
print(f"W statistic: {w_statistic}")
print(f"p-value: {p_value}")
if __name__ == '__main__':
main()