# Transwell migration, knockdown vs control: the same counts analysed five ways. Python 3.13, NumPy, pandas, SciPy.
import numpy as np, pandas as pd, warnings
from scipy import stats
warnings.simplefilter("ignore", RuntimeWarning)                    # SciPy warns that the fixed 100% column has no variance
d = pd.read_csv("transwell.csv")                     # one row per field: experiment, condition, insert, field, cells
ins = d.groupby(["experiment", "condition", "insert"], as_index=False).cells.mean()       # mean cells per field, per insert
ex = ins.groupby(["experiment", "condition"]).cells.mean().unstack()                      # one mean per condition per experiment
for e, r in ex.iterrows():
    print(f"Experiment {e}: control {r.control:.1f} cells per field, knockdown {r.knockdown:.1f}, knockdown {100 * r.knockdown / r.control:.0f}% of control")
kd, ct = d.cells[d.condition == "knockdown"], d.cells[d.condition == "control"]
t = stats.ttest_ind(kd, ct, equal_var=False)
print(f"A. Fields as n ({len(kd)} vs {len(ct)}), Welch t-test: knockdown / control {kd.mean() / ct.mean():.2f}, p = {t.pvalue:.2g}")
ik, ic = ins.cells[ins.condition == "knockdown"], ins.cells[ins.condition == "control"]
t = stats.ttest_ind(ik, ic, equal_var=False)
print(f"B. Inserts as n ({len(ik)} vs {len(ic)}), raw counts, Welch t-test: knockdown / control {ik.mean() / ic.mean():.2f}, p = {t.pvalue:.2g}")
pc = 100 * ex.knockdown / ex.control
t = stats.ttest_ind(pc, np.full(len(pc), 100.0))     # control column set to 100% in every experiment; Student's t-test
print(f"C. Percent of control, control fixed at 100% (n = {len(pc)} per group), Student's t-test: knockdown {pc.mean():.0f}%, p = {t.pvalue:.2g}")
t = stats.ttest_1samp(pc, 100)
print(f"D. Percent of control, one-sample t-test against 100% (n = {len(pc)}): knockdown {pc.mean():.0f}%, p = {t.pvalue:.2g}")
r = np.log(ex.knockdown / ex.control); t = stats.ttest_1samp(r, 0); ci = t.confidence_interval()
print(f"E. Log ratio per experiment (paired, n = {len(r)}): knockdown / control {np.exp(r.mean()):.2f} (95% CI {np.exp(ci.low):.2f} to {np.exp(ci.high):.2f}), p = {t.pvalue:.2g}")
