OSCR

Cerebellar and frontal lobe alterations in pulmonary hypertension implicate an inflammatory lung vascular/brain axis.

Code ↔ Paper

2 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 2 matches
  1. [1] § Results › Deficits in the L-CRBL–L-SFG axis are specific for PH. ↔ function_module.py, lines 448 to 502 · score 0.75 · central systolic blood, LV cardiac, blood pressure, ventricular rate · Report a mismatch
  2. [2] § Results › A multicohort human PH study of brain structure and function performed across discovery and validation cohorts. ↔ function_module.py, lines 448 to 502 · score 0.53 · college degree, IQR, female, diabetes, median, BMI · Report a mismatch

Paper

Loaded from Europe PMC by your browser; OSCR does not store it: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

Python · 1,235 lines · 72 KB · no license · 2 matches

  1. import sys,os
  2. import pandas as pd
  3. import numpy as np
  4. import re
  5. import seaborn as sns
  6. import matplotlib.backends.backend_pdf
  7. import matplotlib.pyplot as plt
  8. import statsmodels.api as sm
  9. import statsmodels.stats as ss
  10. from statsmodels.formula.api import ols, logit, glm
  11. from statsmodels.genmod import families
  12. from statsmodels.stats.multicomp import pairwise_tukeyhsd
  13. from statsmodels.stats.nonparametric import rank_compare_2indep
  14. from statsmodels.stats.contingency_tables import mcnemar
  15. from sklearn.impute import KNNImputer
  16. from statsmodels.discrete.conditional_models import ConditionalLogit
  17. import statsmodels.formula.api as smf
  18. from statsmodels.tools.sm_exceptions import ConvergenceWarning
  19. import pickle
  20. from IPython.display import display
  21. from statsmodels.miscmodels.ordinal_model import OrderedModel
  22. import scipy.stats as st
  23. from statsmodels.stats.weightstats import ztest
  24. from statsmodels.stats import weightstats as sms
  25. from statsmodels.graphics.regressionplots import plot_partregress_grid
  26. from random import sample
  27. from scipy.stats import shapiro
  28. from scipy import stats
  29. def filterData(df, kinship=True, onlyWhiteBritish=True):
  30. if onlyWhiteBritish:
  31. df = df[df['22006-0.0']==1] # only Caucasian ancestry (In_white_british_ancestry_subset)
  32. df = df[df['31-0.0'].notna()] # sex
  33. df = df[df['31-0.0']==df['22001-0.0']]
  34. df = df[df['22019-0.0'].isna()]
  35. if kinship:
  36. df = df[df['22020-0.0']==1]
  37. return(df)
  38. def booleanizeEducation(df): # reference no college degree
  39. df['6138-0.0'] = df['6138-0.0'].isin([1]).astype(int)
  40. return(df)
  41. def booleanizeEthnicity(df): # reference white
  42. df['21000-0.0'] = (~df['21000-0.0'].isin([1001])).astype(int)
  43. return(df)
  44. def booleanizeSelfReportedDF20002(df, codes, field_name): # reference non diabetes
  45. df[field_name] = df['20002-0.0'].isin(codes).astype(int)
  46. return(df)
  47. def runLogit_caseControl_formula(X2, formula, dv, returnFullResult=False, printResult=True, l1=True):
  48. try:
  49. res = logit(formula, X2).fit()
  50. except np.linalg.LinAlgError as err:
  51. if 'Singular matrix' in str(err):
  52. return(pd.DataFrame([]))
  53. else:
  54. if printResult==True:
  55. print(res.summary())
  56. t = res.summary2().tables[1][['Coef.','Std.Err.','P>|z|','[0.025','0.975]']]
  57. t = t.fillna(1)
  58. t = t.drop('Intercept')
  59. t = pd.concat([pd.DataFrame({'Coef.':[dv, res.nobs, np.sum(X2['Case']==1)], 'Std.Err.':["","",""], 'P>|z|':["","",""], '[0.025':["","",""], '0.975]':["","",""] },index=['Dep_Variable:','Sample_Count','Sample_Count_Case']),t])
  60. return(t)
  61. def runGLMLogit_severity_formula(X2, formula, dv, returnFullResult=False, printResult=True, l1=True, offset=None):
  62. if isinstance(offset, type(None)):
  63. try:
  64. res = glm(formula, data=X2, family=families.Binomial()).fit()
  65. except sm.tools.sm_exceptions.PerfectSeparationError as err:
  66. if 'Perfect separation' in str(err):
  67. return pd.DataFrame([]), pd.DataFrame([])
  68. else:
  69. t = res.summary2().tables[1][['Coef.','Std.Err.','P>|z|','[0.025','0.975]']]
  70. else:
  71. try:
  72. res = glm(formula, offset=offset, data=X2, family=families.Binomial()).fit()
  73. except sm.tools.sm_exceptions.PerfectSeparationError as err:
  74. if 'Perfect separation' in str(err):
  75. return pd.DataFrame([]), pd.DataFrame([])
  76. else:
  77. t = res.summary2().tables[1][['Coef.','Std.Err.','P>|z|','[0.025','0.975]']]
  78. if printResult==True:
  79. print(res.summary())
  80. t = t.fillna(1)
  81. if t.index.isin(['Intercept']).sum() >0:
  82. t = t.drop('Intercept')
  83. if 'TimeOffset' in X2.columns:
  84. Coef_sx = t['Coef.']*X2.drop(['TimeOffset','IDF'],axis=1).std(axis=0)
  85. else:
  86. Coef_sx = t['Coef.']*X2.drop(['IDF'],axis=1).std(axis=0)
  87. coefs = pd.concat([Coef_sx, Coef_sx / X2['IDF'].std()],axis=1)
  88. coefs.rename({0:'Coef.sx',1:'Coef_sxsy'},axis=1,inplace=True)
  89. t = pd.concat([t, coefs],axis=1)
  90. t = pd.concat([pd.DataFrame({'Coef.':[dv, X2.shape[0], res.nobs], 'Std.Err.':["","",""], 'P>|z|':["","",""], '[0.025':["","",""], '0.975]':["","",""], 'Coef.sx':["","",""], 'Coef_sxsy':["","",""]},index=['Dep_Variable:','Sample_Count','Sample_Count_Case']),t])
  91. return(res, t)
  92. def bootstrapGLMLogitregression(X2, formula, dvmax, resT, pcol, ntrials=10000, timeOffset=False):
  93. if timeOffset:
  94. params = pd.DataFrame([],index=X2.columns.drop(['IDF','TimeOffset']),columns=list(range(0,ntrials)))
  95. else:
  96. params = pd.DataFrame([],index=X2.columns.drop(['IDF']),columns=list(range(0,ntrials)))
  97. for trial in range(ntrials):
  98. data_sample = X2.sample(frac=1, replace=True)
  99. if timeOffset:
  100. fitmodel,res = runGLMLogit_severity_formula(data_sample, formula, dvmax, offset=data_sample['TimeOffset'], printResult=False, l1=False)
  101. else:
  102. fitmodel,res = runGLMLogit_severity_formula(data_sample, formula, dvmax, printResult=False, l1=False)
  103. params[trial] = res['Coef.'][3:]
  104. point_estimate = np.mean(params,axis=1)
  105. bootstrap_standard_error = np.std(params,ddof=1,axis=1)
  106. z_critical = stats.norm.ppf(1 - (1 - 0.95) / 2) # confidence_level = 0.95
  107. resT['[0.025'][3:] = point_estimate - z_critical * bootstrap_standard_error
  108. resT['0.975]'][3:] = point_estimate + z_critical * bootstrap_standard_error
  109. shapiroP = stats.shapiro(params.loc[caseCol,:])[1]
  110. print('Shapiro test:'); print(shapiroP)
  111. if pvalMethod=='ztest':
  112. pval = ztest(params.loc[caseCol,:], value=0)
  113. resT.loc[caseCol,pcol] = pval[1]
  114. elif pvalMethod=='count-based':
  115. gt = (params.loc[caseCol,:] >0).sum()
  116. lt = (params.loc[caseCol,:] <0).sum()
  117. resT.loc[caseCol,pcol] = np.min([gt,lt]) / (gt+lt)
  118. return(resT)
  119. def permutationGLMLogitregression(X2, formula, dvmax, resT, caseCol, pcol, pvalMethod, ntrials, timeOffset=False):
  120. if timeOffset:
  121. params = pd.DataFrame([],index=X2.columns.drop(['IDF','TimeOffset']),columns=list(range(0,ntrials)))
  122. else:
  123. params = pd.DataFrame([],index=X2.columns.drop(['IDF']),columns=list(range(0,ntrials)))
  124. for trial in range(ntrials):
  125. data_sample = X2.copy()
  126. pred = data_sample['Predictor'].sample(frac=1)
  127. pred.index = data_sample.index
  128. data_sample['Predictor'] = pred
  129. if timeOffset:
  130. fitmodel,res = runGLMLogit_severity_formula(data_sample, formula, dvmax, offset=data_sample['TimeOffset'], printResult=False, l1=False)
  131. else:
  132. fitmodel,res = runGLMLogit_severity_formula(data_sample, formula, dvmax, printResult=False, l1=False)
  133. params[trial] = res['Coef.'][3:]
  134. params = params[params.isna().sum(axis=1)!=ntrials]
  135. sorted_perm_stats = np.sort(np.array(params.loc[caseCol,:]))
  136. sorted_perm_stats = sorted_perm_stats - resT.loc[caseCol,'Coef.']
  137. resT.loc[caseCol,'[0.025'] = np.percentile(sorted_perm_stats, 2.5)
  138. resT.loc[caseCol,'0.975]'] = np.percentile(sorted_perm_stats, 97.5)
  139. shapiroP = stats.shapiro(params.loc[caseCol,:])[1]
  140. print('Shapiro test:'); print(shapiroP)
  141. if pvalMethod=='ztest':
  142. pval = ztest(params.loc[caseCol,:], value=resT.loc[caseCol,'Coef.'])
  143. resT.loc[caseCol,pcol] = pval[1]
  144. elif pvalMethod=='count-based':
  145. gt = (params.loc[caseCol,:] >resT.loc[caseCol,'Coef.']).sum()
  146. lt = (params.loc[caseCol,:] <resT.loc[caseCol,'Coef.']).sum()
  147. resT.loc[caseCol,pcol] = np.min([gt,lt]) / (gt+lt)
  148. return(resT)
  149. def bootstrapLoRegression(X2, formula, dvmax, resT, caseCol, pcol, pvalMethod, ntrials):
  150. params = pd.DataFrame([],index=X2.columns[1:],columns=list(range(0,ntrials)))
  151. for trial in range(ntrials):
  152. data_sample = X2.sample(frac=1, replace=True)
  153. res = runLogit_caseControl_formula(data_sample, formula, dvmax, printResult=False, l1=False)
  154. if res.empty: # skip 0
  155. continue
  156. params[trial] = res['Coef.'][3:]
  157. params = params[params.isna().sum(axis=1)!=ntrials]
  158. params = params.loc[:,~params.loc['Case'].isna()] # remove NAs
  159. point_estimate = np.mean(params,axis=1)
  160. bootstrap_standard_error = np.std(params,ddof=1,axis=1)
  161. z_critical = stats.norm.ppf(1 - (1 - 0.95) / 2) # confidence_level = 0.95
  162. resT['[0.025'][3:] = point_estimate - z_critical * bootstrap_standard_error
  163. resT['0.975]'][3:] = point_estimate + z_critical * bootstrap_standard_error
  164. shapiroP = stats.shapiro(params.loc[caseCol,:])[1]
  165. print('Shapiro test:'); print(shapiroP)
  166. if pvalMethod=='ztest':
  167. pval = ztest(params.loc[caseCol,:], value=0)
  168. resT.loc[caseCol,pcol] = pval[1]
  169. elif pvalMethod=='count-based':
  170. gt = (params.loc[caseCol,:] >0).sum()
  171. lt = (params.loc[caseCol,:] <0).sum()
  172. resT.loc[caseCol,pcol] = np.min([gt,lt]) / (gt+lt)
  173. return(resT)
  174. def permutationLoRegression_ntrials(X2, formula, dvmax, resT, caseCol, pcol, pvalMethod, ntrials):
  175. params = pd.DataFrame([],index=X2.columns[1:],columns=list(range(0,ntrials)))
  176. for trial in range(ntrials):
  177. data_sample = X2.copy()
  178. data_sample[caseCol] = 0
  179. data_sample[caseCol].iloc[sample(range(X2.shape[0]), k=X2[caseCol].sum())] = 1
  180. res = runLogit_caseControl_formula(data_sample, formula, dvmax, printResult=False)
  181. params[trial] = res['Coef.'][3:]
  182. params = params[params.isna().sum(axis=1)!=ntrials]
  183. sorted_perm_stats = np.sort(np.array(params.loc[caseCol,:]))
  184. sorted_perm_stats = sorted_perm_stats - resT.loc[caseCol,'Coef.']
  185. resT.loc[caseCol,'[0.025'] = np.percentile(sorted_perm_stats, 2.5)
  186. resT.loc[caseCol,'0.975]'] = np.percentile(sorted_perm_stats, 97.5)
  187. shapiroP = stats.shapiro(params.loc[caseCol,:])[1]
  188. print('Shapiro test:'); print(shapiroP)
  189. if pvalMethod=='ztest':
  190. pval = ztest(params.loc[caseCol,:], value=resT.loc[caseCol,'Coef.'])
  191. resT.loc[caseCol,pcol] = pval[1]
  192. elif pvalMethod=='count-based':
  193. gt = (params.loc[caseCol,:] >resT.loc[caseCol,'Coef.']).sum()
  194. lt = (params.loc[caseCol,:] <resT.loc[caseCol,'Coef.']).sum()
  195. resT.loc[caseCol,pcol] = np.min([gt,lt]) / (gt+lt)
  196. return(resT)
  197. def permutationGroupMeanLoRegression(X2, formula, dvmax, resT, caseCol, pcol, pvalMethod, ntrials):
  198. resT.iloc[3:,:] = np.nan
  199. try:
  200. res = logit(formula, X2).fit()
  201. except np.linalg.LinAlgError as err:
  202. if 'Singular matrix' in str(err):
  203. return(pd.DataFrame([]))
  204. else:
  205. moT = logit(formula, X2).fit()
  206. temp = moT.predict(X2)
  207. temp[temp >=0.5] = 1
  208. temp[temp < 0.5] = 0
  209. print('Residual normality Shapiro test:'); print(stats.shapiro(moT.resid)[1])
  210. resT.loc[caseCol,'Coef.'] = temp[X2[caseCol]==1].mean() - temp[X2[caseCol]==0].mean()
  211. resT.loc[caseCol,'Std.Err.'] = pooledSD(temp[X2[caseCol]==1], temp[X2[caseCol]==0]) # pooledSD
  212. print('Cohens d:');
  213. print(resT.loc[caseCol,'Coef.'] / resT.loc[caseCol,'Std.Err.']) # cohen's d
  214. params = pd.DataFrame([],index=X2.columns[1:],columns=list(range(0,ntrials)))
  215. for trial in range(ntrials):
  216. data_sample = X2.copy()
  217. data_sample[caseCol] = 0
  218. data_sample[caseCol].iloc[sample(range(X2.shape[0]), k=X2[caseCol].sum())] = 1
  219. try:
  220. res = logit(formula, data_sample).fit()
  221. except np.linalg.LinAlgError as err:
  222. if 'Singular matrix' in str(err):
  223. continue
  224. else:
  225. temp = logit(formula, data_sample).fit().predict(data_sample)
  226. if temp.empty: # skip 0
  227. continue
  228. params.loc[caseCol,trial] = temp[data_sample[caseCol]==1].mean() - temp[data_sample[caseCol]==0].mean()
  229. params = params.loc[:,~params.loc['Case'].isna()] # remove NAs
  230. z_critical = stats.norm.ppf(1 - (1 - 0.95) / 2) # confidence_level = 0.95
  231. resT.loc[caseCol,'[0.025'] = resT.loc[caseCol,'Coef.'] - z_critical * resT.loc[caseCol,'Std.Err.']
  232. resT.loc[caseCol,'0.975]'] = resT.loc[caseCol,'Coef.'] + z_critical * resT.loc[caseCol,'Std.Err.']
  233. shapiroP = stats.shapiro(params.loc[caseCol,:])[1]
  234. print('Shapiro test:'); print(shapiroP)
  235. if pvalMethod=='ztest':
  236. pval = ztest(params.loc[caseCol,:], value=resT.loc[caseCol,'Coef.'])
  237. resT.loc[caseCol,pcol] = pval[1]
  238. elif pvalMethod=='count-based':
  239. gt = (params.loc[caseCol,:] >resT.loc[caseCol,'Coef.']).sum()
  240. lt = (params.loc[caseCol,:] <resT.loc[caseCol,'Coef.']).sum()
  241. resT.loc[caseCol,pcol] = np.min([gt,lt]) / (gt+lt)
  242. return(resT)
  243. def runGLMOLS_severity_formula(X2, formula, dv, returnFullResult=False, printResult=True, l1=True, offset=None):
  244. if isinstance(offset, type(None)):
  245. try:
  246. res = glm(formula, data=X2).fit()
  247. except sm.tools.sm_exceptions.PerfectSeparationError as err:
  248. if 'Perfect separation' in str(err):
  249. return pd.DataFrame([]), pd.DataFrame([])
  250. else:
  251. t = res.summary2().tables[1][['Coef.','Std.Err.','P>|z|','[0.025','0.975]']]
  252. else:
  253. try:
  254. res = glm(formula, offset=offset, data=X2).fit()
  255. except sm.tools.sm_exceptions.PerfectSeparationError as err:
  256. if 'Perfect separation' in str(err):
  257. return pd.DataFrame([]), pd.DataFrame([])
  258. else:
  259. t = res.summary2().tables[1][['Coef.','Std.Err.','P>|z|','[0.025','0.975]']]
  260. if printResult==True:
  261. print(res.summary())
  262. t = t.fillna(1)
  263. if t.index.isin(['Intercept']).sum() >0:
  264. t = t.drop('Intercept')
  265. if 'TimeOffset' in X2.columns:
  266. Coef_sx = t['Coef.']*X2.drop(['TimeOffset','IDF'],axis=1).std(axis=0)
  267. else:
  268. Coef_sx = t['Coef.']*X2.drop(['IDF'],axis=1).std(axis=0)
  269. coefs = pd.concat([Coef_sx, Coef_sx / X2['IDF'].std()],axis=1)
  270. coefs.rename({0:'Coef.sx',1:'Coef_sxsy'},axis=1,inplace=True)
  271. t = pd.concat([t, coefs],axis=1)
  272. t = pd.concat([pd.DataFrame({'Coef.':[dv, X2.shape[0], res.nobs], 'Std.Err.':["","",""], 'P>|z|':["","",""], '[0.025':["","",""], '0.975]':["","",""], 'Coef.sx':["","",""], 'Coef_sxsy':["","",""]},index=['Dep_Variable:','Sample_Count','Sample_Count_Case']),t])
  273. return(res, t)
  274. def bootstrapGLMOLSregression(X2, formula, dvmax, resT, caseCol, pcol, pvalMethod, ntrials, timeOffset=False):
  275. if timeOffset:
  276. params = pd.DataFrame([],index=X2.columns.drop(['IDF','TimeOffset']),columns=list(range(0,ntrials)))
  277. else:
  278. params = pd.DataFrame([],index=X2.columns.drop(['IDF']),columns=list(range(0,ntrials)))
  279. for trial in range(ntrials):
  280. data_sample = X2.sample(frac=1, replace=True)
  281. if timeOffset:
  282. fitmodel = runGLMOLS_severity_formula(data_sample, formula, dvmax, offset=data_sample['TimeOffset'], printResult=False, l1=False)
  283. if isinstance(fitmodel, tuple):
  284. fitmodel,res = runGLMOLS_severity_formula(data_sample, formula, dvmax, offset=data_sample['TimeOffset'], printResult=False, l1=False)
  285. params[trial] = res['Coef.'][3:]
  286. else:
  287. fitmodel = runGLMOLS_severity_formula(data_sample, formula, dvmax, printResult=False, l1=False)
  288. if isinstance(fitmodel, tuple):
  289. fitmodel,res = runGLMOLS_severity_formula(data_sample, formula, dvmax, printResult=False, l1=False)
  290. params[trial] = res['Coef.'][3:]
  291. params = params.loc[:,params.isna().sum(axis=0)!=params.shape[0]]
  292. if params.shape[1] < 10:
  293. return(resT)
  294. point_estimate = np.mean(params,axis=1)
  295. bootstrap_standard_error = np.std(params,ddof=1,axis=1)
  296. z_critical = stats.norm.ppf(1 - (1 - 0.95) / 2) # confidence_level = 0.95
  297. resT['[0.025'][3:] = point_estimate - z_critical * bootstrap_standard_error
  298. resT['0.975]'][3:] = point_estimate + z_critical * bootstrap_standard_error
  299. shapiroP = stats.shapiro(params.loc[caseCol,:])[1]
  300. print('Shapiro test:'); print(shapiroP)
  301. if pvalMethod=='ztest':
  302. pval = ztest(params.loc[caseCol,:], value=0)
  303. resT.loc[caseCol,pcol] = pval[1]
  304. elif pvalMethod=='count-based':
  305. gt = (params.loc[caseCol,:] >0).sum()
  306. lt = (params.loc[caseCol,:] <0).sum()
  307. resT.loc[caseCol,pcol] = np.min([gt,lt]) / (gt+lt)
  308. return(resT)
  309. def permutationGLMOLSregression(X2, formula, dvmax, resT, caseCol, pcol, pvalMethod, ntrials, timeOffset=False):
  310. if timeOffset: # timeoffset
  311. params = pd.DataFrame([],index=X2.columns.drop(['IDF','TimeOffset']),columns=list(range(0,ntrials)))
  312. else:
  313. params = pd.DataFrame([],index=X2.columns.drop(['IDF']),columns=list(range(0,ntrials)))
  314. for trial in range(ntrials):
  315. data_sample = X2.copy()
  316. pred = data_sample['Predictor'].sample(frac=1)
  317. pred.index = data_sample.index
  318. data_sample['Predictor'] = pred
  319. if timeOffset:
  320. fitmodel,res = runGLMOLS_severity_formula(data_sample, formula, dvmax, offset=data_sample['TimeOffset'], printResult=False, l1=False)
  321. else:
  322. fitmodel,res = runGLMOLS_severity_formula(data_sample, formula, dvmax, printResult=False, l1=False)
  323. params[trial] = res['Coef.'][3:]
  324. params = params[params.isna().sum(axis=1)!=ntrials]
  325. sorted_perm_stats = np.sort(np.array(params.loc[caseCol,:]))
  326. sorted_perm_stats = sorted_perm_stats - resT.loc[caseCol,'Coef.']
  327. resT.loc[caseCol,'[0.025'] = np.percentile(sorted_perm_stats, 2.5)
  328. resT.loc[caseCol,'0.975]'] = np.percentile(sorted_perm_stats, 97.5)
  329. shapiroP = stats.shapiro(params.loc[caseCol,:])[1]
  330. print('Shapiro test:'); print(shapiroP)
  331. if pvalMethod=='ztest':
  332. pval = ztest(params.loc[caseCol,:], value=resT.loc[caseCol,'Coef.'])
  333. resT.loc[caseCol,pcol] = pval[1]
  334. elif pvalMethod=='count-based':
  335. gt = (params.loc[caseCol,:] >resT.loc[caseCol,'Coef.']).sum()
  336. lt = (params.loc[caseCol,:] <resT.loc[caseCol,'Coef.']).sum()
  337. resT.loc[caseCol,pcol] = np.min([gt,lt]) / (gt+lt)
  338. return(resT)
  339. def runOLS_formula(X2, formula, dv, returnFullResult=False, printResult=True, l1=True):
  340. res = ols(formula, X2).fit()
  341. if printResult==True:
  342. print(res.summary())
  343. t = res.summary2().tables[1][['Coef.','Std.Err.','P>|t|','[0.025','0.975]']]
  344. t = t.fillna(1)
  345. t = t.drop('Intercept')
  346. t = pd.concat([pd.DataFrame({'Coef.':[dv, res.nobs, np.sum(X2['Case']==1)], 'Std.Err.':["","",""], 'P>|t|':["","",""], '[0.025':["","",""], '0.975]':["","",""]},index=['Dep_Variable:','Sample_Count','Sample_Count_Case']),t])
  347. return(t)
  348. def bootstrapOLSregression(X2, formula, dvmax, resT, caseCol, pcol, pvalMethod, ntrials):
  349. params = pd.DataFrame([],index=X2.columns[1:],columns=list(range(0,ntrials)))
  350. for trial in range(ntrials):
  351. data_sample = X2.sample(frac=1, replace=True)
  352. res = runOLS_formula(data_sample, formula, dvmax, printResult=False)
  353. params[trial] = res['Coef.'][3:]
  354. params = params[params.isna().sum(axis=1)!=ntrials]
  355. point_estimate = np.mean(params,axis=1)
  356. bootstrap_standard_error = np.std(params,ddof=1,axis=1)
  357. z_critical = stats.norm.ppf(1 - (1 - 0.95) / 2) # confidence_level = 0.95
  358. resT['[0.025'][3:] = point_estimate - z_critical * bootstrap_standard_error
  359. resT['0.975]'][3:] = point_estimate + z_critical * bootstrap_standard_error
  360. shapiroP = stats.shapiro(params.loc[caseCol,:])[1]
  361. print('Shapiro test:'); print(shapiroP)
  362. if pvalMethod=='ztest':
  363. pval = ztest(params.loc[caseCol,:], value=0)
  364. resT.loc[caseCol,pcol] = pval[1]
  365. elif pvalMethod=='count-based':
  366. gt = (params.loc[caseCol,:] >0).sum()
  367. lt = (params.loc[caseCol,:] <0).sum()
  368. resT.loc[caseCol,pcol] = np.min([gt,lt]) / (gt+lt)
  369. return(resT)
  370. def permutationOLSregression(X2, formula, dvmax, resT, caseCol, pcol, pvalMethod, ntrials):
  371. params = pd.DataFrame([],index=X2.columns[1:],columns=list(range(0,ntrials)))
  372. for trial in range(ntrials):
  373. data_sample = X2.copy()
  374. data_sample[caseCol] = 0
  375. data_sample[caseCol].iloc[sample(range(X2.shape[0]), k=X2[caseCol].sum())] = 1
  376. res = runOLS_formula(data_sample, formula, dvmax, printResult=False)
  377. params[trial] = res['Coef.'][3:]
  378. params = params[params.isna().sum(axis=1)!=ntrials]
  379. sorted_perm_stats = np.sort(np.array(params.loc[caseCol,:]))
  380. sorted_perm_stats = sorted_perm_stats - resT.loc[caseCol,'Coef.']
  381. resT.loc[caseCol,'[0.025'] = np.percentile(sorted_perm_stats, 2.5)
  382. resT.loc[caseCol,'0.975]'] = np.percentile(sorted_perm_stats, 97.5)
  383. shapiroP = stats.shapiro(params.loc[caseCol,:])[1]
  384. print('Shapiro test:'); print(shapiroP)
  385. if pvalMethod=='ztest':
  386. pval = ztest(params.loc[caseCol,:], value=resT.loc[caseCol,'Coef.'])
  387. resT.loc[caseCol,pcol] = pval[1]
  388. elif pvalMethod=='count-based':
  389. gt = (params.loc[caseCol,:] >resT.loc[caseCol,'Coef.']).sum()
  390. lt = (params.loc[caseCol,:] <resT.loc[caseCol,'Coef.']).sum()
  391. resT.loc[caseCol,pcol] = np.min([gt,lt]) / (gt+lt)
  392. return(resT)
  393. def pooledSD(d1, d2):
  394. n1, n2 = len(d1), len(d2)
  395. s1, s2 = np.var(d1, ddof=1), np.var(d2, ddof=1)
  396. return(np.sqrt(((n1 - 1) * s1 + (n2 - 1) * s2) / (n1 + n2 - 2)))
  397. def permutationGroupMeanOLSregression(X2, formula, dvmax, resT, caseCol, pcol, pvalMethod, ntrials):
  398. resT.iloc[3:,:] = np.nan
  399. moT = ols(formula, X2).fit()
  400. temp = moT.predict(X2)
  401. print('Residual normality Shapiro test:'); print(stats.shapiro(moT.resid)[1])
  402. resT.loc[caseCol,'Coef.'] = temp[X2[caseCol]==1].mean() - temp[X2[caseCol]==0].mean()
  403. resT.loc[caseCol,'Std.Err.'] = pooledSD(temp[X2[caseCol]==1], temp[X2[caseCol]==0]) # pooledSD
  404. print('Cohens d:')
  405. print(resT.loc[caseCol,'Coef.'] / resT.loc[caseCol,'Std.Err.']) # cohen's d
  406. params = pd.DataFrame([],index=X2.columns[1:],columns=list(range(0,ntrials)))
  407. for trial in range(ntrials):
  408. data_sample = X2.copy()
  409. data_sample[caseCol] = 0
  410. data_sample[caseCol].iloc[sample(range(X2.shape[0]), k=X2[caseCol].sum())] = 1
  411. temp = ols(formula, data_sample).fit().predict(data_sample)
  412. params.loc[caseCol,trial] = temp[data_sample[caseCol]==1].mean() - temp[data_sample[caseCol]==0].mean()
  413. params = params[params.isna().sum(axis=1)!=ntrials]
  414. params = params.dropna(axis=1)
  415. z_critical = stats.norm.ppf(1 - (1 - 0.95) / 2) # confidence_level = 0.95
  416. resT.loc[caseCol,'[0.025'] = resT.loc[caseCol,'Coef.'] - z_critical * resT.loc[caseCol,'Std.Err.']
  417. resT.loc[caseCol,'0.975]'] = resT.loc[caseCol,'Coef.'] + z_critical * resT.loc[caseCol,'Std.Err.']
  418. shapiroP = stats.shapiro(params.loc[caseCol,:])[1]
  419. print('Shapiro test:'); print(shapiroP)
  420. if pvalMethod=='ztest':
  421. pval = ztest(params.loc[caseCol,:], value=resT.loc[caseCol,'Coef.'])
  422. resT.loc[caseCol,pcol] = pval[1]
  423. elif pvalMethod=='count-based':
  424. gt = (params.loc[caseCol,:] >resT.loc[caseCol,'Coef.']).sum()
  425. lt = (params.loc[caseCol,:] <resT.loc[caseCol,'Coef.']).sum()
  426. resT.loc[caseCol,pcol] = np.min([gt,lt]) / (gt+lt)
  427. return(resT)
  428. def exportStats(X):
  429. x1 = X[X['Case']==1]
  430. x3 = X[X['Case']==0]
  431. num = x1.shape[0], x3.shape[0], "" # count
  432. temp = [num]; temp_index = ['Sample #']
  433. if 'Age' in x1.columns:
  434. age = str(int(np.round(x1['Age'].median(),0))) + " IQR[" + str(int(np.round(np.nanpercentile(x1['Age'],25),0))) +" "+ str(int(np.round(np.nanpercentile(x1['Age'],75),0))) +"]", str(int(np.round(x3['Age'].median(),0))) + " IQR[" + str(int(np.round(np.nanpercentile(x3['Age'],25),0))) +" "+ str(int(np.round(np.nanpercentile(x3['Age'],75),0))) +"]", (rank_compare_2indep(x1['Age'], x3['Age'])).pvalue
  435. temp.append(age); temp_index.append('Age (years)')
  436. if 'Age1' in x1.columns:
  437. age = str(np.round(x1['Age1'].mean(),2)) + " \xb1 " + str(np.round(x1['Age1'].std(),2)), str(np.round(x3['Age1'].mean(),2)) + " \xb1 " + str(np.round(x3['Age1'].std(),2)), (rank_compare_2indep(x1['Age1'], x3['Age1'])).pvalue
  438. temp.append(age); temp_index.append('Age1 (years)')
  439. if 'Age2' in x1.columns:
  440. age = str(np.round(x1['Age2'].mean(),2)) + " \xb1 " + str(np.round(x1['Age2'].std(),2)), str(np.round(x3['Age2'].mean(),2)) + " \xb1 " + str(np.round(x3['Age2'].std(),2)), (rank_compare_2indep(x1['Age2'], x3['Age2'])).pvalue
  441. temp.append(age); temp_index.append('Age2 (years)')
  442. if 'AgeDifference' in x1.columns:
  443. age = str(np.round(x1['AgeDifference'].mean(),2)) + " \xb1 " + str(np.round(x1['AgeDifference'].std(),2)), str(np.round(x3['AgeDifference'].mean(),2)) + " \xb1 " + str(np.round(x3['AgeDifference'].std(),2)), (rank_compare_2indep(x1['AgeDifference'], x3['AgeDifference'])).pvalue
  444. temp.append(age); temp_index.append('AgeDifference (years)')
  445. if 'Squared_AgeDifference' in x1.columns:
  446. age = str(np.round(x1['Squared_AgeDifference'].mean(),2)) + " \xb1 " + str(np.round(x1['Squared_AgeDifference'].std(),2)), str(np.round(x3['Squared_AgeDifference'].mean(),2)) + " \xb1 " + str(np.round(x3['Squared_AgeDifference'].std(),2)), (rank_compare_2indep(x1['Squared_AgeDifference'], x3['Squared_AgeDifference'])).pvalue
  447. temp.append(age); temp_index.append('Squared_AgeDifference (years)')
  448. if 'Sex' in x1.columns:
  449. sex = str((x1['Sex']==0).sum()) + ' [' + str(int(np.round((x1['Sex']==0).mean()*100))) + '%]', str((x3['Sex']==0).sum()) + ' [' + str(int(np.round((x3['Sex']==0).mean()*100))) + '%]', (rank_compare_2indep(x1['Sex'], x3['Sex'])).pvalue
  450. temp.append(sex); temp_index.append('Sex [female] (%)')
  451. if 'Ethnicity' in x1.columns:
  452. race = str((x1['Ethnicity']==0).sum()) + ' [' + str(int(np.round((x1['Ethnicity']==0).mean()*100))) + '%]', str((x3['Ethnicity']==0).sum()) + ' [' + str(int(np.round((x3['Ethnicity']==0).mean()*100))) + '%]', (rank_compare_2indep(x1['Ethnicity'], x3['Ethnicity'])).pvalue
  453. temp.append(race); temp_index.append('Ethnicity [white] (%)')
  454. if 'Education' in x1.columns:
  455. edu = str((x1['Education']==1).sum()) + ' [' + str(int(np.round((x1['Education']==1).mean()*100))) + '%]', str((x3['Education']==1).sum()) + ' [' + str(int(np.round((x3['Education']==1).mean()*100))) + '%]', (rank_compare_2indep(x1['Education'], x3['Education'])).pvalue
  456. temp.append(edu); temp_index.append('Education [college degree] (%)')
  457. if 'Ever_smoked' in x1.columns:
  458. smoke = str((x1['Ever_smoked']==1).sum()) + ' [' + str(int(np.round((x1['Ever_smoked']==1).mean()*100))) + '%]', str((x3['Ever_smoked']==1).sum()) + ' [' + str(int(np.round((x3['Ever_smoked']==1).mean()*100))) + '%]', (rank_compare_2indep(x1['Ever_smoked'], x3['Ever_smoked'])).pvalue
  459. temp.append(smoke); temp_index.append('Ever smoked (%)')
  460. if 'BMI' in x1.columns:
  461. bmi = str(np.round(x1['BMI'].median(),2)) + " IQR[" + str(np.round(np.nanpercentile(x1['BMI'],25),2)) +" "+ str(np.round(np.nanpercentile(x1['BMI'],75),2)) +"]", str(np.round(x3['BMI'].median(),2)) + " IQR[" + str(np.round(np.nanpercentile(x3['BMI'],25),2)) +" "+ str(np.round(np.nanpercentile(x3['BMI'],75),2)) +"]", (rank_compare_2indep(x1['BMI'], x3['BMI'])).pvalue
  462. temp.append(bmi); temp_index.append('BMI')
  463. if '1707-0.0' in x1.columns:
  464. handedness = str((x1['1707-0.0']==1).sum()) + ' [' + str(int(np.round((x1['1707-0.0']==1).mean()*100))) + '%]', str((x3['1707-0.0']==1).sum()) + ' [' + str(int(np.round((x3['1707-0.0']==1).mean()*100))) + '%]', (rank_compare_2indep(x1['1707-0.0'], x3['1707-0.0'])).pvalue
  465. temp.append(handedness); temp_index.append('Handedness [right] (%)')
  466. if 'Self_diabeticCondition' in x1.columns:
  467. diabet = str((x1['Self_diabeticCondition']==1).sum()) + ' [' + str(float(np.round((x1['Self_diabeticCondition']==1).mean()*100,3))) + '%]', str((x3['Self_diabeticCondition']==1).sum()) + ' [' + str(float(np.round((x3['Self_diabeticCondition']==1).mean()*100,3))) + '%]', (rank_compare_2indep(x1['Self_diabeticCondition'], x3['Self_diabeticCondition'])).pvalue
  468. temp.append(diabet); temp_index.append('Self-reported diabetic condition (%)')
  469. if '24104-2.0' in x1.columns:
  470. LV_cardiac_output = str(np.round(x1['24104-2.0'].median(),2)) + " IQR[" + str(np.round(np.nanpercentile(x1['24104-2.0'],25),2)) +" "+ str(np.round(np.nanpercentile(x1['24104-2.0'],75),2)) +"]", str(np.round(x3['24104-2.0'].median(),2)) + " IQR[" + str(np.round(np.nanpercentile(x3['24104-2.0'],25),2)) +" "+ str(np.round(np.nanpercentile(x3['24104-2.0'],75),2)) +"]", (rank_compare_2indep(x1['24104-2.0'], x3['24104-2.0'])).pvalue
  471. temp.append(LV_cardiac_output); temp_index.append('LV cardiac output')
  472. if '22424-2.0' in x1.columns:
  473. Cardiac_output = str(np.round(x1['22424-2.0'].median(),2)) + " IQR[" + str(np.round(np.nanpercentile(x1['22424-2.0'],25),2)) +" "+ str(np.round(np.nanpercentile(x1['22424-2.0'],75),2)) +"]", str(np.round(x3['22424-2.0'].median(),2)) + " IQR[" + str(np.round(np.nanpercentile(x3['22424-2.0'],25),2)) +" "+ str(np.round(np.nanpercentile(x3['22424-2.0'],75),2)) +"]", (rank_compare_2indep(x1['22424-2.0'], x3['22424-2.0'])).pvalue
  474. temp.append(Cardiac_output); temp_index.append('Cardiac output')
  475. if '12336-2.0' in x1.columns:
  476. Ventricular_rate = str(np.round(x1['12336-2.0'].median(),2)) + " IQR[" + str(np.round(np.nanpercentile(x1['12336-2.0'],25),2)) +" "+ str(np.round(np.nanpercentile(x1['12336-2.0'],75),2)) +"]", str(np.round(x3['12336-2.0'].median(),2)) + " IQR[" + str(np.round(np.nanpercentile(x3['12336-2.0'],25),2)) +" "+ str(np.round(np.nanpercentile(x3['12336-2.0'],75),2)) +"]", (rank_compare_2indep(x1['12336-2.0'], x3['12336-2.0'])).pvalue
  477. temp.append(Ventricular_rate); temp_index.append('Ventricular rate')
  478. if '12677-2.0' in x1.columns:
  479. Central_systolic_blood_pressure_during_PWA = str(np.round(x1['12677-2.0'].median(),2)) + " IQR[" + str(np.round(np.nanpercentile(x1['12677-2.0'],25),2)) +" "+ str(np.round(np.nanpercentile(x1['12677-2.0'],75),2)) +"]", str(np.round(x3['12677-2.0'].median(),2)) + " IQR[" + str(np.round(np.nanpercentile(x3['12677-2.0'],25),2)) +" "+ str(np.round(np.nanpercentile(x3['12677-2.0'],75),2)) +"]", (rank_compare_2indep(x1['12677-2.0'], x3['12677-2.0'])).pvalue
  480. temp.append(Central_systolic_blood_pressure_during_PWA); temp_index.append('Central systolic blood pressure during PWA')
  481. T = pd.DataFrame(temp, columns=['Case','Control','P-value'], index=temp_index)
  482. return(T)
  483. def calcComorbidPercentage(df_idf_toE, cate, instance):
  484. D = df_idf_toE.filter(regex=("^41270-"))
  485. D2 = df_idf_toE.filter(regex=("^41271-"))
  486. D3 = df_idf_toE.filter(regex=("^41200-"))
  487. D4 = df_idf_toE.filter(regex=("^41202-"))
  488. D5 = df_idf_toE.filter(regex=("^41203-")) # 41204 does not have time
  489. D6 = df_idf_toE.filter(regex=("^41272-"))
  490. D7 = df_idf_toE.filter(regex=("^41256-"))
  491. # days
  492. Da = df_idf_toE.filter(regex=("^41280-"))
  493. Da2 = df_idf_toE.filter(regex=("^41281-"))
  494. Da3 = df_idf_toE.filter(regex=("^41260-"))
  495. Da4 = df_idf_toE.filter(regex=("^41262-"))
  496. Da5 = df_idf_toE.filter(regex=("^41263-"))
  497. Da6 = df_idf_toE.filter(regex=("^41282-"))
  498. Da7 = df_idf_toE.filter(regex=("^41257-"))
  499. T = pd.DataFrame([],index=df_idf_toE.index, columns=list(cate.keys()))
  500. if instance=='All':
  501. for disease, l in cate.items():
  502. temp = D.apply(lambda x: x.isin(l).sum(),axis=1)
  503. T[disease] = temp
  504. else:
  505. dataDate2 = df_idf_toE['53'+instance].astype('datetime64[ns]')
  506. I = Da.apply(lambda x: (dataDate2 - x.astype('datetime64[ns]')).dt.days >=0,axis=0)
  507. I.columns = D.columns
  508. D.sub = D[I]
  509. for disease, l in cate.items():
  510. temp = D.sub.apply(lambda x: x.isin(l).sum(),axis=1)
  511. T[disease] = temp
  512. co = (T >0).sum(axis=0)
  513. res = co.astype(str) + " [" + (np.round(co / T.shape[0]*100,1)).astype(str) + "%]"
  514. return(res)
  515. def calcPvalueComorbids(res, x1count, x3count):
  516. x1 = pd.DataFrame(0, index=range(x1count), columns=res.index)
  517. x3 = pd.DataFrame(0, index=range(x3count), columns=res.index)
  518. P = pd.DataFrame(pd.NA,index=res.index,columns=['P-value'])
  519. for i in range(res.shape[0]):
  520. n = int(re.sub("^(\d+) .+$","\\1",res.iloc[i,0]))
  521. x1.iloc[0:n,i] = 1
  522. n = int(re.sub("^(\d+) .+$","\\1",res.iloc[i,1]))
  523. x3.iloc[0:n,i] = 1
  524. P.iloc[i,0] = rank_compare_2indep(x1.iloc[:,i], x3.iloc[:,i]).pvalue
  525. P = pd.concat([res,P],axis=1)
  526. return(P)
  527. def value_count_of_ICDs(df_idf_toE, instance):
  528. icd10table = pd.read_csv("UKBB_ICD10_table.csv",sep="\t",index_col=0)
  529. icd10table = icd10table[['Meaning','Selectable']]
  530. icd9table = pd.read_csv("UKBB_ICD9_table.csv",sep="\t",index_col=0)
  531. icd9table = icd9table[['Meaning','Selectable']]
  532. D = df_idf_toE.filter(regex=("^41270-"))
  533. D2 = df_idf_toE.filter(regex=("^41271-"))
  534. Da = df_idf_toE.filter(regex=("^41280-"))
  535. Da2 = df_idf_toE.filter(regex=("^41281-"))
  536. if instance=='All':
  537. icd10 = pd.DataFrame(D[I].apply(pd.Series.value_counts).sum(axis=1).astype(int).sort_values(ascending=False),columns=['Count'])
  538. icd10['Percent'] = icd10 / df_idf_toE.shape[0] * 100
  539. icd10 = pd.merge(icd10, icd10table, left_index=True, right_index=True, how='left')
  540. icd9 = pd.DataFrame(D2[I].apply(pd.Series.value_counts).sum(axis=1).astype(int).sort_values(ascending=False),columns=['Count'])
  541. icd9['Percent'] = icd9 / df_idf_toE.shape[0] * 100
  542. icd9 = pd.merge(icd9, icd9table, left_index=True, right_index=True, how='left')
  543. icd9 = icd9.sort_values(by=['Count'], ascending=False)
  544. return icd10, icd9
  545. else:
  546. dataDate2 = df_idf_toE['53'+instance].astype('datetime64[ns]')
  547. # ICD10
  548. I = Da.apply(lambda x: (dataDate2 - x.astype('datetime64[ns]')).dt.days >=0,axis=0)
  549. I.columns = D.columns
  550. icd10 = pd.DataFrame(D[I].apply(pd.Series.value_counts).sum(axis=1).astype(int).sort_values(ascending=False),columns=['Count'])
  551. icd10['Percent'] = icd10 / df_idf_toE.shape[0] * 100
  552. icd10 = pd.merge(icd10, icd10table, left_index=True, right_index=True, how='left')
  553. # ICD9
  554. I = Da2.apply(lambda x: (dataDate2 - x.astype('datetime64[ns]')).dt.days >=0,axis=0)
  555. I.columns = D2.columns
  556. D2 = D2.astype(str)
  557. D2 = D2.apply(lambda x: x.str.replace("^(.+)\.0","\\1",regex=True), axis=0)
  558. icd9 = pd.DataFrame(D2[I].apply(pd.Series.value_counts).sum(axis=1).astype(int).sort_values(ascending=False),columns=['Count'])
  559. icd9['Percent'] = icd9 / df_idf_toE.shape[0] * 100
  560. icd9 = pd.merge(icd9, icd9table, left_index=True, right_index=True, how='left')
  561. icd9 = icd9.sort_values(by=['Count'], ascending=False)
  562. return icd10, icd9
  563. def snsPlotEachDF_multipage(X2, dv, yvar, xvar, yname, xname, pdf, ylabfontsize, xlabfontsize, ytickfontsize, xtickfontsize, titlefontsize):
  564. bp = sns.boxplot(y=yvar,x=xvar,data=X2, order=[1,0])
  565. plt.xlabel(xname,fontsize=xlabfontsize)
  566. plt.ylabel(yname,fontsize=ylabfontsize)
  567. plt.xticks(fontsize=xtickfontsize)
  568. plt.yticks(fontsize=ytickfontsize)
  569. plt.title(dv, fontsize=titlefontsize)
  570. #bp.axhline(y=0, linewidth=2, color='black', ls=':')
  571. fig = bp.get_figure()
  572. pdf.savefig(fig)
  573. fig.clf()
  574. def missingValueImputeKNN(Before_imputation, cov):
  575. imputer = KNNImputer(n_neighbors=2)
  576. After_imputation = imputer.fit_transform(Before_imputation[cov])
  577. After_imputation = pd.DataFrame(After_imputation,index=Before_imputation.index,columns=cov)
  578. Before_imputation[cov] = After_imputation
  579. return(Before_imputation)
  580. def runBatchRegression_caseControl(df_idf_1, df_idf_3, maps, covariates, caseCol='Case',suffix='suffix',comorbidM=None, booleanizeComorbid=True, removeKinship=True, onlyWhiteBritish=True, instance=None, cohortStats=False, DL=None, focusedDFs=None, output_dir='.', outlierStdv=None, normalizeByTIV=None, DFtype=None, paraEst=None, postfix=None, imputeMissingValues=None):
  581. print("paraEst: "+str(paraEst))
  582. df_idf_1 = filterData(df_idf_1, kinship=removeKinship, onlyWhiteBritish=onlyWhiteBritish)
  583. df_idf_3 = filterData(df_idf_3, kinship=removeKinship, onlyWhiteBritish=onlyWhiteBritish)
  584. if focusedDFs!=None:
  585. df_idf_1 = df_idf_1[(df_idf_1[focusedDFs].isna()).sum(axis=1)!=df_idf_1[focusedDFs].shape[1]]
  586. df_idf_3 = df_idf_3[(df_idf_3[focusedDFs].isna()).sum(axis=1)!=df_idf_3[focusedDFs].shape[1]]
  587. if covariates['UKBB'][0]=='None':
  588. pe_X = pd.DataFrame(1, index=df_idf_1.index, columns=[caseCol])
  589. ctrl_X = pd.DataFrame(0, index=df_idf_3.index, columns=[caseCol])
  590. elif normalizeByTIV:
  591. pe_X = df_idf_1[covariates['UKBB']+['26521-2.0']]
  592. ctrl_X = df_idf_3[covariates['UKBB']+['26521-2.0']]
  593. pe_X.loc[:,caseCol] = 1
  594. ctrl_X.loc[:,caseCol] = 0
  595. else:
  596. pe_X = df_idf_1[covariates['UKBB']]
  597. ctrl_X = df_idf_3[covariates['UKBB']]
  598. pe_X.loc[:,caseCol] = 1
  599. ctrl_X.loc[:,caseCol] = 0
  600. display(pe_X)
  601. display(ctrl_X)
  602. #
  603. X = pd.concat([pe_X, ctrl_X], axis=0)
  604. ##############################
  605. if 'UKBB' in covariates:
  606. if '6138-0.0' in covariates['UKBB']:
  607. X = booleanizeEducation(X)
  608. if '21000-0.0' in covariates['UKBB']:
  609. X = booleanizeEthnicity(X)
  610. if onlyWhiteBritish:
  611. X = X[X['21000-0.0']==0]; X = X.drop(['21000-0.0'],axis=1)
  612. if '738-0.0' in covariates['UKBB']:
  613. mea = X.loc[X['738-0.0'] >= 0,'738-0.0'].mean()
  614. X.loc[X['738-0.0'] < 0,'738-0.0'] = mea
  615. X.loc[X['738-0.0'].isna(),'738-0.0'] = mea
  616. if '20002-0.0' in covariates['UKBB']:
  617. X = booleanizeSelfReportedDF20002(X, [1220, 1222, 1223],'Self_diabeticCondition'); X = X.drop(['20002-0.0'],axis=1)
  618. if '20160-0.0' in covariates['UKBB']:
  619. X['20160-0.0'].fillna(0, inplace=True) # all missing values as 0 for smoking
  620. if '23104-0.0' in covariates['UKBB']:
  621. X['23104-0.0'].fillna(X['23104-0.0'].mean(), inplace=True) # BMI imputation by mean
  622. if '30760-0.0' in covariates['UKBB']:
  623. X['30760-0.0'].fillna(X['30760-0.0'].mean(), inplace=True) # HDL cholesterol imputation
  624. if '30780-0.0' in covariates['UKBB']:
  625. X['30780-0.0'].fillna(X['30780-0.0'].mean(), inplace=True) # LDL direct imputation
  626. ##############################
  627. X.rename({'31-0.0':'Sex', '6138-0.0':'Education', '21000-0.0':'Ethnicity', '23104-0.0':'BMI', '21022-0.0':'Age', '20160-0.0':'Ever_smoked', '30760-0.0':'HDL_cholesterol','30780-0.0':'LDL_direct','738-0.0':'Income','26521-2.0':'TIV'}, axis=1, inplace=True)
  628. X = X.rename(columns=lambda x: re.sub('22009-0.','PC',x))
  629. outfile_suffix = ''
  630. if comorbidM is not None:
  631. if 'comorbid' in covariates:
  632. if booleanizeComorbid:
  633. comorbidM = (comorbidM >0).astype(int)
  634. X = pd.merge(X, comorbidM[covariates['comorbid']], how='inner', right_index=True, left_index=True)
  635. if imputeMissingValues:
  636. X = missingValueImputeKNN(X, X.columns.tolist())
  637. X = X.dropna()
  638. toExport = ['24486-2.0','24485-2.0','25781-2.0','27230-2.0','27199-2.0','27195-2.0','27188-2.0','27268-2.0','26557-2.0','26556-2.0','26528-2.0','26587-2.0','25895-2.0','25909-2.0','25893-2.0','25903-2.0','25897-2.0','25906-2.0','25900-2.0','25912-2.0','25915-2.0','25918-2.0','25786-2.0','24104-2.0','22424-2.0','12677-2.0','1707-0.0','12336-2.0'] # white matter, left cerebellum, SFG
  639. if set(toExport).issubset(set(df_idf_1.columns)):
  640. df_idf = pd.concat([df_idf_1, df_idf_3],axis=0)
  641. g = pd.merge(X,df_idf[toExport],how='inner',left_index=True,right_index=True)
  642. g.to_csv('DFs_WMH_white_LCerebellumSFG_'+suffix+'.csv',sep=",",quoting=2,index=True,header=True)
  643. else:
  644. g = X.copy()
  645. toExport = ['Left-Cerebellum-Cortex__ctx-lh-superiorfrontal-2.0','ctx-lh-superiorfrontal__ctx-lh-superiorparietal-2.0'] # white matter, left cerebellum, SFG
  646. if set(toExport).issubset(set(df_idf_1.columns)):
  647. df_idf = pd.concat([df_idf_1, df_idf_3],axis=0)
  648. g = pd.merge(X,df_idf[toExport],how='inner',left_index=True,right_index=True)
  649. g.to_csv('DFs_eAUC_LCerebellumSFG_'+suffix+'.csv',sep=",",quoting=2,index=True,header=True)
  650. else:
  651. g = X.copy()
  652. display(g)
  653. T = exportStats(g)
  654. if DL!=None: #
  655. res = pd.concat([calcComorbidPercentage(df_idf_1, DL, instance), calcComorbidPercentage(df_idf_3, DL, instance)], axis=1)
  656. res = calcPvalueComorbids(res, df_idf_1.shape[0], df_idf_3.shape[0])
  657. res.columns = T.columns
  658. T = pd.concat([T, res])
  659. suffix2 = re.sub("^(.+_rfMRI_.+)_(abs|neg|pos).+?$","\\1",suffix)
  660. T.to_csv(output_dir+'/sigStats_DFs-Case_LR'+outfile_suffix+'__'+DFtype+"_"+suffix2+'.csv',sep="\t",header=True,index=True)
  661. icd10,icd9 = value_count_of_ICDs(df_idf_1, instance)
  662. icd10.to_csv(output_dir+'/sigICD10_DFs-Case_LR'+outfile_suffix+'__'+DFtype+"_"+suffix2+'.csv',sep="\t",header=False,index=True)
  663. icd9.to_csv(output_dir+'/sigICD9_DFs-Case_LR'+outfile_suffix+'__'+DFtype+"_"+suffix2+'.csv',sep="\t",header=False,index=True)
  664. icd10,icd9 = value_count_of_ICDs(df_idf_3, instance)
  665. icd10.to_csv(output_dir+'/sigICD10_DFs-Case_LR'+outfile_suffix+'__'+DFtype+"_"+'control'+'.csv',sep="\t",header=False,index=True)
  666. icd9.to_csv(output_dir+'/sigICD9_DFs-Case_LR'+outfile_suffix+'__'+DFtype+"_"+'control'+'.csv',sep="\t",header=False,index=True)
  667. U = calcPHBreakdoown(X[X['Case']==1], 2)
  668. U.to_csv(output_dir+'/sigStats_DFs-Case_LR_PHbreakdown'+outfile_suffix+'__'+DFtype+"_"+suffix2+'.csv',sep="\t",header=True,index=True)
  669. #
  670. df_idf = pd.concat([df_idf_1, df_idf_3],axis=0)
  671. df_idf = df_idf.loc[X.index,:]
  672. pd.DataFrame(df_idf_1.index).to_csv(output_dir+'/eid_df_idf_1'+outfile_suffix+'__'+DFtype+"_"+suffix2+'.csv',sep=",",header=True,index=False,quoting=1)
  673. pd.DataFrame(df_idf_3.index).to_csv(output_dir+'/eid_df_idf_3'+outfile_suffix+'__'+DFtype+"_"+suffix2+'.csv',sep=",",header=True,index=False,quoting=1)
  674. #
  675. if not df_idf.index.identical(X.index):
  676. print('index different between df_idf and X'); exit
  677. L = maps['data_type'].unique()
  678. tested = []
  679. for l in L:
  680. print(l)
  681. Ys = maps.loc[maps['data_type']==l,'DF']
  682. LR = pd.DataFrame()
  683. sub_tested = []
  684. LRtype='DFs-Case_LR'
  685. outpdf = output_dir+"/sigBox_"+LRtype+outfile_suffix+'__'+l+"_"+suffix+postfix+'.pdf'
  686. pdf = matplotlib.backends.backend_pdf.PdfPages(outpdf)
  687. for dv in Ys:
  688. LoR = False
  689. dvmax = str(dv)+instance
  690. if not dvmax in df_idf_1.columns:
  691. print(dvmax," does not exist")
  692. else:
  693. print(dvmax)
  694. # remove -1.0 and -3.0 ("do not know", "prefer not to answer" )
  695. df_idf_1.loc[(df_idf_1[dvmax]==-1) | (df_idf_1[dvmax]==-3),dvmax] = float('NaN')
  696. df_idf_3.loc[(df_idf_3[dvmax]==-1) | (df_idf_3[dvmax]==-3),dvmax] = float('NaN')
  697. df_idf.loc[(df_idf[dvmax]==-1) | (df_idf[dvmax]==-3),dvmax] = float('NaN')
  698. if (len(df_idf_1[dvmax].unique())==1):
  699. print(dvmax," is constant")
  700. elif (len(df_idf[dvmax].unique()) < 4) and (len(df_idf[dvmax].unique()) > 2):
  701. print(dvmax," has less than 4 unique values")
  702. elif (pd.isna(df_idf[dvmax].unique()).sum() >0) and (len(df_idf[dvmax].unique())==2):
  703. print(dvmax," has nan and one values")
  704. elif (isinstance(df_idf[dvmax].unique()[1],str)):
  705. print(dvmax," has non-numeric value")
  706. elif (df_idf[dvmax].dtype=='O'):
  707. print(dvmax," has object value")
  708. else:
  709. sub_tested.append(dv)
  710. df_idf[caseCol] = X[caseCol]
  711. snsPlotEachDF_multipage(df_idf, dv=dvmax, yvar=dvmax, xvar=caseCol, yname='Measurement value', xname='Case', pdf=pdf, ylabfontsize=12, xlabfontsize=12, ytickfontsize=12, xtickfontsize=12, titlefontsize=18)
  712. if (len(df_idf[dvmax].unique())==2) and (np.sum(np.sort(df_idf[dvmax].unique())==np.sort(np.array([0,1])))==2):
  713. LoR = True
  714. print(dvmax," logistic regression applied")
  715. else:
  716. print(dvmax, " has two or more non-binary variables" )
  717. tempX = X
  718. if (normalizeByTIV) & (not l in ['Brain_MRI','aparc+aseg']): # exclude Abdominal, heart, DEXA
  719. tempX = X.drop(['TIV'],axis=1)
  720. formula = 'IDF' + " ~ " + ' + '.join([re.sub("^.+\s(.+)$","\\1",s) for s in tempX.columns.tolist()])
  721. X2 = pd.concat([df_idf[dvmax],X],axis=1)
  722. X2.rename({dvmax:'IDF'}, axis=1, inplace=True)
  723. X2.columns = [re.sub("^.+\s(.+)$","\\1",s) for s in X2.columns.tolist()]
  724. X2 = X2.dropna()
  725. if outlierStdv!=100: ## outlier removal
  726. high = df_idf[dvmax].mean() + outlierStdv * df_idf[dvmax].std()
  727. low = df_idf[dvmax].mean() - outlierStdv * df_idf[dvmax].std()
  728. I = (df_idf[dvmax] <= high) & (df_idf[dvmax] >= low)
  729. if LoR: # logistic
  730. resT = runLogit_caseControl_formula(X2[I], formula, dvmax, printResult=False, l1=False)
  731. if resT.empty:
  732. continue
  733. resT.rename({'P>|z|':'P>|t|'},axis=1,inplace=True)
  734. if paraEst=='permutation':
  735. LR = pd.concat([LR,permutationLoRegression_ntrials(X2[I], formula, dvmax, resT, caseCol, pcol='P>|t|', pvalMethod='count-based', ntrials=10000)], axis=1)
  736. elif paraEst=='bootstrapping':
  737. LR = pd.concat([LR,bootstrapLoRegression(X2[I], formula, dvmax, resT, caseCol, pcol='P>|t|', pvalMethod='count-based', ntrials=10000)], axis=1)
  738. elif paraEst=='meanDiffClassPermutation':
  739. LR = pd.concat([LR, permutationGroupMeanLoRegression(X2[I], formula, dvmax, resT, caseCol, pcol='P>|t|', pvalMethod='count-based', ntrials=10000)], axis=1)
  740. else:
  741. LR = pd.concat([LR, resT], axis=1)
  742. else: # OLS
  743. resT = runOLS_formula(X2[I], formula, dvmax, printResult=True)
  744. if paraEst=='permutation': # permutation
  745. LR = pd.concat([LR,permutationOLSregression(X2[I], formula, dvmax, resT, caseCol, pcol='P>|t|', pvalMethod='count-based', ntrials=10000)], axis=1)
  746. elif paraEst=='bootstrapping':
  747. LR = pd.concat([LR,bootstrapOLSregression(X2[I], formula, dvmax, resT, caseCol, pcol='P>|t|', pvalMethod='count-based', ntrials=10000)], axis=1)
  748. elif paraEst=='meanDiffClassPermutation':
  749. LR = pd.concat([LR, permutationGroupMeanOLSregression(X2[I], formula, dvmax, resT, caseCol, pcol='P>|t|', pvalMethod='count-based', ntrials=10000)], axis=1)
  750. else:
  751. LR = pd.concat([LR,resT], axis=1)
  752. else: ## No outlier removal
  753. if LoR: # logistic regression
  754. resT = runLogit_caseControl_formula(X2, formula, dvmax, printResult=False, l1=False)
  755. if resT.empty:
  756. continue
  757. resT.rename({'P>|z|':'P>|t|'},axis=1,inplace=True)
  758. if paraEst=='permutation':
  759. LR = pd.concat([LR, permutationLoRegression_ntrials(X2, formula, dvmax, resT, caseCol, pcol='P>|t|', pvalMethod='count-based', ntrials=10000)], axis=1)
  760. elif paraEst=='bootstrapping':
  761. LR = pd.concat([LR, bootstrapLoRegression(X2, formula, dvmax, resT, caseCol, pcol='P>|t|', pvalMethod='count-based', ntrials=10000)], axis=1)
  762. elif paraEst=='meanDiffClassPermutation':
  763. LR = pd.concat([LR, permutationGroupMeanLoRegression(X2, formula, dvmax, resT, caseCol, pcol='P>|t|', pvalMethod='count-based', ntrials=10000)], axis=1)
  764. else:
  765. LR = pd.concat([LR, resT], axis=1)
  766. else: # OLS
  767. resT = runOLS_formula(X2, formula, dvmax, printResult=True)
  768. if paraEst=='permutation': # permutation
  769. LR = pd.concat([LR, permutationOLSregression(X2, formula, dvmax, resT, caseCol, pcol='P>|t|', pvalMethod='count-based', ntrials=10000)], axis=1)
  770. elif paraEst=='bootstrapping':
  771. LR = pd.concat([LR, bootstrapOLSregression(X2, formula, dvmax, resT, caseCol, pcol='P>|t|', pvalMethod='count-based', ntrials=10000)], axis=1)
  772. elif paraEst=='meanDiffClassPermutation':
  773. LR = pd.concat([LR, permutationGroupMeanOLSregression(X2, formula, dvmax, resT, caseCol, pcol='P>|t|', pvalMethod='count-based', ntrials=10000)], axis=1)
  774. else:
  775. LR = pd.concat([LR,resT], axis=1)
  776. pdf.close()
  777. tested.append(sub_tested)
  778. if paraEst in ['bootstrapping','permutation']:
  779. paraEst = "_"+paraEst
  780. else:
  781. paraEst=""
  782. if LR.empty:
  783. print(l, " has no usable variable")
  784. continue
  785. I = np.where(LR.loc[caseCol,'P>|t|'] <= 1.0)[0]
  786. if(len(I)==0):
  787. print(l, " has no significant result")
  788. temp = pd.DataFrame(np.nan, index=maps['DF'], columns=['DF','Coefficient','P-value','Padj','CI_025','CI_975','Sample_Count','Sample_Count_Case'])
  789. temp['DF'] = temp.index
  790. temp.to_csv(output_dir+'/sig2_DFs-Case_LR'+outfile_suffix+'__'+l+"_"+suffix+paraEst+postfix+'.csv',sep=",",header=True,index=False)
  791. continue
  792. lr = LR.iloc[:,np.sort(np.concatenate([I*5,I*5+1,I*5+2,I*5+3,I*5+4]))]
  793. lr.to_csv(output_dir+'/sig_DFs-Case_LR'+outfile_suffix+'__'+l+"_"+suffix+paraEst+postfix+'.csv',sep=",",header=True,index=True)
  794. padj = (ss.multitest.fdrcorrection(LR.loc[caseCol,'P>|t|']))[1]
  795. padjBonf = (ss.multitest.multipletests(LR.loc[caseCol,'P>|t|'], method='bonferroni'))[1]
  796. target_I = int(np.where(LR.index==caseCol)[0])
  797. b = pd.DataFrame([LR.iloc[0,np.sort(np.concatenate([I*5]))].values, LR.iloc[target_I,np.sort(np.concatenate([I*5]))].values, LR.iloc[target_I,np.sort(np.concatenate([I*5+2]))].values, padj[I], padjBonf[I], LR.iloc[target_I,np.sort(np.concatenate([I*5+3]))].values, LR.iloc[target_I,np.sort(np.concatenate([I*5+4]))].values, LR.iloc[1,np.sort(np.concatenate([I*5]))].values, LR.iloc[2,np.sort(np.concatenate([I*5]))].values]).T
  798. b.columns = ['DF','Coefficient','P-value','Padj','Padj_Bonf','CI_025','CI_975','Sample_Count','Sample_Count_Case']
  799. b['DF'+instance] = b['DF'].copy()
  800. b['DF'] = [re.sub("^(.+)-.+$","\\1",i) for i in b['DF'] ]
  801. if b['DF'][0].isnumeric():
  802. b['DF'] = b['DF'].astype('int')
  803. sub1 = df_idf_1.loc[:,df_idf_1.columns.isin(b['DF'+instance])]
  804. sub3 = df_idf_3.loc[:,df_idf_3.columns.isin(b['DF'+instance])]
  805. mean1 = sub1.mean(axis=0); std1=sub1.std(axis=0); min1=sub1.min(axis=0); q5_1=sub1.quantile(0.05, axis=0); q25_1=sub1.quantile(0.25, axis=0); med1=sub1.quantile(0.5, axis=0); q75_1=sub1.quantile(0.75, axis=0); q95_1=sub1.quantile(0.95, axis=0); max1=sub1.max(axis=0)
  806. mean3 = sub3.mean(axis=0); std3=sub3.std(axis=0); min3=sub3.min(axis=0); q5_3=sub3.quantile(0.05, axis=0); q25_3=sub3.quantile(0.25, axis=0); med3=sub3.quantile(0.5, axis=0); q75_3=sub3.quantile(0.75, axis=0); q95_3=sub3.quantile(0.95, axis=0); max3=sub3.max(axis=0)
  807. delta = mean1 - mean3
  808. delta_percent = delta / mean3 *100
  809. ms1 = pd.DataFrame(np.round(mean1,2).astype(str) + " \xb1 " + np.round(std1,2).astype(str), columns=['Case_mean[std]'])
  810. ms3 = pd.DataFrame(np.round(mean3,2).astype(str) + " \xb1 " + np.round(std3,2).astype(str), columns=['Control_mean[std]'])
  811. de = pd.DataFrame(delta, columns=['Case-Control']).astype(str)
  812. de_percent = pd.DataFrame(delta_percent, columns=['Percent_Case-Control']).astype(str)
  813. sss = pd.DataFrame([min1,q5_1,q25_1,med1,q75_1,q95_1,max1,min3,q5_3,q25_3,med3,q75_3,q95_3,max3],index=['Case_min','Case_q5','Case_q25','Case_q50','Case_q75','Case_q95','Case_max','Control_min','Control_q5','Control_q25','Control_q50','Control_q75','Control_q95','Control_max']).astype(str).T
  814. b = pd.merge(b,ms1,how='left',left_on='DF'+instance,right_index=True)
  815. b = pd.merge(b,ms3,how='left',left_on='DF'+instance,right_index=True)
  816. b = pd.merge(b,de,how='left',left_on='DF'+instance,right_index=True)
  817. b = pd.merge(b,de_percent,how='left',left_on='DF'+instance,right_index=True)
  818. b = pd.merge(b,sss,how='left',left_on='DF'+instance,right_index=True)
  819. temp = pd.merge(maps[['DF','description','data_type','Image_type','Sub_classification']], b, left_on='DF',right_on='DF', how='inner')
  820. temp = temp.sort_values('P-value')
  821. temp.to_csv(output_dir+'/sig2_DFs-Case_LR'+outfile_suffix+'__'+l+"_"+suffix+paraEst+postfix+'.csv',sep=",",header=True,index=False)
  822. if l=="Brain_MRI":
  823. temp['Padj_global'] = temp['Padj'].copy()
  824. temp['Padj'] = np.float('NaN')
  825. atlases = temp['Sub_classification'].unique()
  826. for atla in atlases:
  827. I = temp['Sub_classification']==atla
  828. temp.loc[I,'Padj'] = ss.multitest.fdrcorrection(temp[I]['P-value'])[1]
  829. temp = temp.sort_values('P-value')
  830. temp.to_csv(output_dir+'/sig2_DFs-Case_LR'+outfile_suffix+'__'+l+"_"+suffix+paraEst+postfix+'.csv',sep=",",header=True,index=False)
  831. temp = temp[temp['Padj'] <= 0.05]
  832. temp = temp[temp['Sub_classification'].isin(['Freesurfer_a2009s','Freesurfer_ASEG','Freesurfer_BA_exvivo','Freesurfer_DKT','Freesurfer_subsegmentation','Regional_grey_matter_volumes_(FAST)','Subcortical_volumes_(FIRST)'])]
  833. temp = temp.sort_values(['description','Sub_classification'], ascending=[False, True])
  834. temp.to_csv(output_dir+'/significant_sig2_DFs-Case_LR'+outfile_suffix+'__'+l+"_"+suffix+paraEst+postfix+'.csv',sep=",",header=True,index=False)
  835. def runBatchRegression_SNPvsPhenotype_withoutControl(df_idf_1, maps, covariates, caseCol='Case', suffix='suffix', comorbidM=None, booleanizeComorbid=True, removeKinship=False, onlyWhiteBritish=True, instance=None, cohortStats=True, DL=None, focusedDFs=None, normalizeByTIV=None, paraEst=None, output_dir='.', snps=None, postfix=None, gtypes=None, setname=None, snpmodel=None):
  836. print("paraEst: "+str(paraEst))
  837. df_idf_1 = filterData(df_idf_1, kinship=removeKinship, onlyWhiteBritish=onlyWhiteBritish)
  838. if focusedDFs!=None:
  839. df_idf_1 = df_idf_1[(df_idf_1[focusedDFs].isna()).sum(axis=1)!=df_idf_1[focusedDFs].shape[1]]
  840. if covariates['UKBB'][0]=='None':
  841. pass
  842. elif normalizeByTIV:
  843. pe_X = df_idf_1[covariates['UKBB']+['26521-2.0']]
  844. else:
  845. pe_X = df_idf_1[covariates['UKBB']]
  846. display(pe_X)
  847. X = pe_X
  848. ##############################
  849. if 'UKBB' in covariates:
  850. if '6138-0.0' in covariates['UKBB']:
  851. X = booleanizeEducation(X)
  852. if '21000-0.0' in covariates['UKBB']:
  853. X = booleanizeEthnicity(X)
  854. if onlyWhiteBritish:
  855. X = X[X['21000-0.0']==0]; X = X.drop(['21000-0.0'],axis=1)
  856. if '738-0.0' in covariates['UKBB']:
  857. mea = X.loc[X['738-0.0'] >= 0,'738-0.0'].mean()
  858. X.loc[X['738-0.0'] < 0,'738-0.0'] = mea
  859. X.loc[X['738-0.0'].isna(),'738-0.0'] = mea
  860. if '20002-0.0' in covariates['UKBB']:
  861. X = booleanizeSelfReportedDF20002(X, [1220, 1222, 1223],'Self_diabeticCondition'); X = X.drop(['20002-0.0'],axis=1)
  862. if '20160-0.0' in covariates['UKBB']:
  863. X['20160-0.0'].fillna(0, inplace=True) # all missing values as 0 for smoking
  864. if '23104-0.0' in covariates['UKBB']:
  865. X['23104-0.0'].fillna(X['23104-0.0'].mean(), inplace=True) # BMI imputation by mean
  866. if '30760-0.0' in covariates['UKBB']:
  867. X['30760-0.0'].fillna(X['30760-0.0'].mean(), inplace=True) # HDL cholesterol imputation
  868. if '30780-0.0' in covariates['UKBB']:
  869. X['30780-0.0'].fillna(X['30780-0.0'].mean(), inplace=True) # LDL direct imputation
  870. ##############################
  871. X.rename({'31-0.0':'Sex', '6138-0.0':'Education', '21000-0.0':'Ethnicity', '23104-0.0':'BMI', '21022-0.0':'Age', '20160-0.0':'Ever_smoked', '30760-0.0':'HDL_cholesterol','30780-0.0':'LDL_direct','738-0.0':'Income','26521-2.0':'TIV'}, axis=1, inplace=True)
  872. X = X.rename(columns=lambda x: re.sub('22009-0.','PC',x))
  873. outfile_suffix = ''
  874. if comorbidM is not None:
  875. if 'comorbid' in covariates:
  876. if booleanizeComorbid:
  877. comorbidM = (comorbidM >0).astype(int)
  878. X = pd.merge(X, comorbidM[covariates['comorbid']], how='inner', right_index=True, left_index=True)
  879. X = X.dropna()
  880. display(X)
  881. suffix2 = re.sub("^(.+_rfMRI_.+)_(abs|neg|pos).+?$","\\1",suffix)
  882. df_idf = df_idf_1.copy()
  883. df_idf = df_idf.loc[X.index,:]
  884. df_idf_1.to_csv(output_dir+'/df_idf_1.csv',sep=",",header=True,index=True,quoting=1)
  885. if not df_idf.index.identical(X.index):
  886. print('index different between df_idf and X'); exit
  887. L = maps['data_type'].unique()
  888. tested = []
  889. for l in L:
  890. print(l)
  891. Ys = maps.loc[maps['data_type']==l,'DF']
  892. sub_tested = []
  893. for dv in Ys:
  894. LoR = False
  895. dvmax = str(dv)+instance
  896. print(dvmax)
  897. pcol = 'P>|z|'
  898. LR0 = pd.DataFrame()
  899. if not dvmax in df_idf_1.columns:
  900. print(dvmax," does not exist")
  901. else:
  902. # remove -1.0 and -3.0 ("do not know", "prefer not to answer" )
  903. df_idf_1.loc[(df_idf_1[dvmax]==-1) | (df_idf_1[dvmax]==-3),dvmax] = float('NaN')
  904. df_idf.loc[(df_idf[dvmax]==-1) | (df_idf[dvmax]==-3),dvmax] = float('NaN')
  905. if (len(df_idf_1[dvmax].unique())==1):
  906. print(dvmax," is constant")
  907. elif (pd.isna(df_idf[dvmax].unique()).sum() >0) and (len(df_idf[dvmax].unique())==2):
  908. print(dvmax," has nan and one values")
  909. elif (isinstance(df_idf[dvmax].unique()[1],str)):
  910. print(dvmax," has non-numeric value")
  911. elif (df_idf[dvmax].dtype=='O'):
  912. print(dvmax," has object value")
  913. else:
  914. sub_tested.append(dvmax)
  915. if (len(df_idf[dvmax].unique())==2) and (np.sum(np.sort(df_idf[dvmax].unique())==np.sort(np.array([0,1])))==2):
  916. print(dvmax," logistic regression applied")
  917. elif (len(df_idf[dvmax].unique()) < 2):
  918. print(outcome," has < 1 unique outcome variable")
  919. continue
  920. else:
  921. print(dvmax, " has two or more non-binary variables" )
  922. for eachSNP in gtypes: # regression one by one
  923. print(eachSNP)
  924. if not isinstance(snps, pd.DataFrame):
  925. sys.exit('input snps not defined')
  926. snps2 = snps[eachSNP]
  927. X15 = pd.merge(X,snps2,left_index=True,right_index=True,how='inner')
  928. X15 = X15[~X15[eachSNP].isna()]
  929. X15[eachSNP] = X15[eachSNP].astype(int)
  930. y = df_idf.loc[:,~df_idf.columns.isin(X15.columns)]
  931. y = y[y.index.isin(X15.index)]
  932. y2 = y[dvmax]
  933. y2 = y2[~y2.isna()]
  934. pcol = 'P>|z|'
  935. if snpmodel=='dominant':
  936. X15.loc[X15[eachSNP]==2,eachSNP] = 1
  937. diff_X2 = pd.merge(y2, X15, right_index=True, left_index=True, how='inner')
  938. toExport = ['rs11154337_G']
  939. if set(toExport).issubset(set(diff_X2.columns)):
  940. if snpmodel=='additive':
  941. diff_X2.to_csv('DFs_regre4_SNPs_vs_'+str(dv)+"_"+suffix+'.csv',sep=",",quoting=2,index=True,header=True)
  942. diff_X2.rename({dvmax:'IDF'},axis=1,inplace=True)
  943. diff_X2 = diff_X2.dropna()
  944. diff_X2.columns = [re.sub("^.+\s(.+)$","\\1",s) for s in diff_X2.columns.tolist()]
  945. formula = 'IDF ~ '+' + '.join(diff_X2.columns.tolist())
  946. formula = re.sub("( IDF \+| Case \+)","",formula)
  947. if not normalizeByTIV: # exclude Abdominal, heart, DEXA
  948. formula = formula.replace(" + TIV","")
  949. minimumSample = len(formula.split(' + ')) + 1
  950. if diff_X2.shape[0] < minimumSample:
  951. print("diff_X2.shape[0] < minimumSample")
  952. continue
  953. if (len(diff_X2['IDF'].unique()) < 2):
  954. print(dvmax," has < 1 unique outcome variable")
  955. continue
  956. if LoR: # logistic regression
  957. fitmodel,resT = runGLMLogit_severity_formula(diff_X2, formula, dvmax, printResult=False, l1=False)
  958. else: # OLS
  959. fitmodel,resT = runGLMOLS_severity_formula(diff_X2, formula, dvmax, printResult=False, l1=False)
  960. if resT.empty:
  961. continue
  962. if paraEst=='bootstrapping':
  963. pass
  964. elif paraEst=='meanDiffClassBootstrapping':
  965. pass
  966. else:
  967. pass
  968. effectAlleleNums = np.sum(diff_X2[eachSNP] >0)
  969. totalAlele = diff_X2.shape[0]*2
  970. effectAlleleCount = np.sum(diff_X2[eachSNP])
  971. eaf = pd.DataFrame({'Coef.':[effectAlleleNums, effectAlleleCount / totalAlele, effectAlleleCount, totalAlele], 'Std.Err.':["","","",""], 'P>|z|':["","","",""], '[0.025':["","","",""], '0.975]':["","","",""], 'Coef.sx':["","","",""], 'Coef_sxsy':["","","",""]},index=['eaSampleCountCase','eaf','eacount','totalacount'])
  972. resT = pd.concat([resT[0:3], eaf, resT[3:resT.shape[0]] ], axis=0)
  973. m = pd.DataFrame(pd.concat([resT.loc[['Dep_Variable:'],'Coef.'], maps.loc[maps['DF'].isin([dv]),'description'], resT.loc[eachSNP], resT.loc[['Sample_Count','Sample_Count_Case','eaSampleCountCase','eaf','eacount','totalacount'],'Coef.']], axis=0)).T
  974. m.columns.values[0:2] = ['DF','description']
  975. m.index = [eachSNP]
  976. LR0 = pd.concat([LR0,m], axis=0)
  977. if paraEst in ['bootstrapping','meanDiffClassBootstrapping']:
  978. paraEst2 = "_"+paraEst
  979. else:
  980. paraEst2 = ""
  981. if LR0.empty:
  982. print(l, " has no usable variable")
  983. continue
  984. I = np.where(LR0[pcol] <= 1.0)[0]
  985. if(len(I)==0):
  986. print(setname, " has no significant result")
  987. padj = (ss.multitest.fdrcorrection(LR0[pcol]))[1]
  988. padjBonf = (ss.multitest.multipletests(LR0[pcol], method='bonferroni'))[1]
  989. LR0.insert(5,'Padj',padj)
  990. LR0.insert(6,'padjBonf',padj)
  991. LR0 = LR0.sort_values(pcol)
  992. LR0.index.name='SNP'
  993. LR0.to_csv(output_dir+'/sig2_SNPvsPhenotype'+outfile_suffix+'__'+suffix+paraEst2+postfix+"_"+setname+'_'+snpmodel+"__"+dvmax+'.csv',sep=",",header=True,index=True)
  994. def runBatchSeverityRegression_inputBothOutcomeAndExposureVectors(df_idf_1, maps, covariates, caseCol='Predictor',suffix='suffix',comorbidM=None, booleanizeComorbid=True, removeKinship=True, onlyWhiteBritish=True, instance=None, LRtype=None, cohortStats=False, DL=None, focusedDFs=None, outcomeDescriptions=None, output_dir='.', outlierStdv=None, normalizeByTIV=False, DFtype=None, paraEst=None, postfix=None, timeOffset=False, ntrials=None):
  995. print("paraEst: "+str(paraEst))
  996. df_idf_1 = filterData(df_idf_1, kinship=removeKinship, onlyWhiteBritish=onlyWhiteBritish)
  997. if focusedDFs!=None:
  998. df_idf_1 = df_idf_1[(df_idf_1[focusedDFs].isna()).sum(axis=1)!=df_idf_1[focusedDFs].shape[1]]
  999. if timeOffset:
  1000. if not 'TimeOffset' in covariates['UKBB']:
  1001. covariates['UKBB'] = covariates['UKBB']+['TimeOffset']
  1002. if covariates['UKBB'][0]=='None':
  1003. pe_X = pd.DataFrame(1, index=df_idf_1.index, columns=[caseCol])
  1004. pass
  1005. elif normalizeByTIV:
  1006. pe_X = df_idf_1[covariates['UKBB']+['26521-2.0']]
  1007. else:
  1008. pe_X = df_idf_1[covariates['UKBB']]
  1009. display(pe_X)
  1010. X = pe_X
  1011. #
  1012. ##############################
  1013. if 'UKBB' in covariates:
  1014. if '6138-0.0' in covariates['UKBB']:
  1015. X = booleanizeEducation(X)
  1016. if '21000-0.0' in covariates['UKBB']:
  1017. X = booleanizeEthnicity(X)
  1018. if onlyWhiteBritish:
  1019. X = X[X['21000-0.0']==0]; X = X.drop(['21000-0.0'],axis=1)
  1020. if '738-0.0' in covariates['UKBB']:
  1021. mea = X.loc[X['738-0.0'] >= 0,'738-0.0'].mean()
  1022. X.loc[X['738-0.0'] < 0,'738-0.0'] = mea
  1023. X.loc[X['738-0.0'].isna(),'738-0.0'] = mea
  1024. if '20002-0.0' in covariates['UKBB']:
  1025. X = booleanizeSelfReportedDF20002(X, [1220, 1222, 1223],'Self_diabeticCondition'); X = X.drop(['20002-0.0'],axis=1)
  1026. if '20160-0.0' in covariates['UKBB']:
  1027. X['20160-0.0'].fillna(0, inplace=True) # all missing values as 0 for smoking
  1028. if '23104-0.0' in covariates['UKBB']:
  1029. X['23104-0.0'].fillna(X['23104-0.0'].mean(), inplace=True) # BMI imputation by mean
  1030. if '30760-0.0' in covariates['UKBB']:
  1031. X['30760-0.0'].fillna(X['30760-0.0'].mean(), inplace=True) # HDL cholesterol imputation
  1032. if '30780-0.0' in covariates['UKBB']:
  1033. X['30780-0.0'].fillna(X['30780-0.0'].mean(), inplace=True) # LDL direct imputation
  1034. ##############################
  1035. X.rename({'31-0.0':'Sex', '6138-0.0':'Education', '21000-0.0':'Ethnicity', '23104-0.0':'BMI', '21022-0.0':'Age', '20160-0.0':'Ever_smoked', '30760-0.0':'HDL_cholesterol','30780-0.0':'LDL_direct','738-0.0':'Income','26521-2.0':'TIV'}, axis=1, inplace=True)
  1036. X = X.rename(columns=lambda x: re.sub('22009-0.','PC',x))
  1037. outfile_suffix = ''
  1038. if comorbidM is not None:
  1039. if 'comorbid' in covariates:
  1040. if booleanizeComorbid:
  1041. comorbidM = (comorbidM >0).astype(int)
  1042. X = pd.merge(X, comorbidM[covariates['comorbid']], how='inner', right_index=True, left_index=True)
  1043. X = X.dropna()
  1044. toExport = ['30870-0.0','30860-0.0','30840-0.0','30820-0.0','30810-0.0','30800-0.0','30790-0.0','30780-0.0','30760-0.0','30740-0.0','30730-0.0','30660-0.0','30690-0.0','30680-0.0','30650-0.0','30640-0.0','30630-0.0','30610-0.0','30620-0.0','30890-0.0','30670-0.0','30700-0.0','30720-0.0','30880-0.0','30750-0.0','30770-0.0','30600-0.0','30830-0.0','30850-0.0','30710-0.0','27230-2.0','27199-2.0','26557-2.0','26556-2.0','26521-2.0'] # white matter, left cerebellum, SFG, TIV
  1045. if set(toExport).issubset(set(df_idf_1.columns)):
  1046. g = pd.merge(X,df_idf_1[toExport],how='inner',left_index=True,right_index=True)
  1047. g.to_csv('DFs_Blood_biochemistry_LCerebellumSFG_'+suffix+'.csv',sep=",",quoting=2,index=True,header=True)
  1048. toExport = ['Max_wsumed_cardsupdays','Summed_episode_length','Summed_wsumed_cardsupdays','Summed_All_supdays','Max_wsumed_card_res_supdays','Summed_wsumed_card_res_supdays','Max_All_supdays','Max_orgsupmax','Summed_wsumed_ressupdays','Count_gisupcares','Max_wsumed_ressupdays','LCerebellum__LSFG_z0.675_lower','L_Cerebellum_WM_and_LCerebellum__LSFG_AND_L_SFG_Th_and_LCerebellum__LSFG_z0.675_lower'] # white matter, left cerebellum, SFG
  1049. toExport = [s+instance for s in toExport]
  1050. if set(toExport).issubset(set(df_idf_1.columns)):
  1051. g = pd.merge(X,df_idf_1[toExport],how='inner',left_index=True,right_index=True)
  1052. g.to_csv('DFs_regre13_ClinicalOutcomesvsMRI_RI_LCerebellumWMSFG_'+suffix+'.csv',sep=",",quoting=2,index=True,header=True)
  1053. display(X)
  1054. suffix2 = re.sub("^(.+_rfMRI_.+)_(abs|neg|pos).+?$","\\1",suffix)
  1055. df_idf = df_idf_1.copy()
  1056. df_idf = df_idf.loc[X.index,:]
  1057. pd.DataFrame(df_idf_1.index).to_csv(output_dir+'/eid_df_idf_1'+outfile_suffix+'__'+DFtype+"_"+suffix2+'.csv',sep=",",header=True,index=False,quoting=1)
  1058. if not df_idf.index.identical(X.index):
  1059. print('index different between df_idf and X'); exit
  1060. L = maps['data_type'].unique()
  1061. tested = []
  1062. for outcome in focusedDFs: # export output file for each outcome
  1063. print(outcome)
  1064. for l in L:
  1065. print(l)
  1066. Ys = maps.loc[maps['data_type']==l,'DF']
  1067. LR = pd.DataFrame()
  1068. sub_tested = []
  1069. outpdf = output_dir+"/regressExog_"+LRtype+outfile_suffix+'__'+l+"_"+suffix+postfix+'.pdf'
  1070. for dv in Ys:
  1071. LoR = False
  1072. if instance=='NA':
  1073. dvmax = str(dv)
  1074. else:
  1075. dvmax = str(dv)+instance
  1076. if dvmax==outcome:
  1077. continue
  1078. if not dvmax in df_idf_1.columns:
  1079. print(dvmax," does not exist")
  1080. else:
  1081. print(dvmax)
  1082. # remove -1.0 and -3.0 ("do not know", "prefer not to answer" )
  1083. df_idf_1.loc[(df_idf_1[dvmax]==-1) | (df_idf_1[dvmax]==-3),dvmax] = float('NaN')
  1084. df_idf.loc[(df_idf[dvmax]==-1) | (df_idf[dvmax]==-3),dvmax] = float('NaN')
  1085. if (len(df_idf_1[dvmax].unique())==1):
  1086. print(dvmax," is constant")
  1087. elif (pd.isna(df_idf[dvmax].unique()).sum() >0) and (len(df_idf[dvmax].unique())==2):
  1088. print(dvmax," has nan and one values")
  1089. elif (isinstance(df_idf[dvmax].unique()[1],str)):
  1090. print(dvmax," has non-numeric value")
  1091. elif (df_idf[dvmax].dtype=='O'):
  1092. print(dvmax," has object value")
  1093. else:
  1094. sub_tested.append(dv)
  1095. X[caseCol] = df_idf[dvmax]
  1096. if (len(df_idf[outcome].unique())==2) and (np.sum(np.sort(df_idf[outcome].unique())==np.sort(np.array([0,1])))==2):
  1097. LoR = True
  1098. print(outcome," logistic regression applied")
  1099. elif (len(df_idf[outcome].unique()) < 2):
  1100. print(outcome," has < 1 unique outcome variable")
  1101. continue
  1102. else:
  1103. print(outcome, " has two or more non-binary variables" )
  1104. X2 = X.copy()
  1105. X2.columns = [re.sub("^.+\s(.+)$","\\1",s) for s in X2.columns.tolist()]
  1106. X2['IDF'] = df_idf[outcome]
  1107. X2 = X2.dropna()
  1108. if X2.shape[0] <10:
  1109. print('too few input')
  1110. continue
  1111. if timeOffset:
  1112. ax = X2['TimeOffset'].hist() # s is an instance of Series
  1113. print(shapiro(X2['TimeOffset']))
  1114. X2['TimeOffset'] = stats.zscore(X2['TimeOffset'])
  1115. X2['Predictor'] = stats.zscore(X2['Predictor'])
  1116. if normalizeByTIV:
  1117. X2['TIV'] = stats.zscore(X2['TIV'])
  1118. formula = 'IDF' + " ~ " + ' + '.join([re.sub("^.+\s(.+)$","\\1",s) for s in X.drop(['TimeOffset'],axis=1).columns.tolist()]) + " - 1"
  1119. X3 = X2.copy()
  1120. X3['Predictor_over_TimeOffset'] = X2['Predictor'] / X2['TimeOffset']
  1121. X3['Predictor_minus_TimeOffset'] = X2['Predictor'] - X2['TimeOffset']
  1122. else:
  1123. formula = 'IDF' + " ~ " + ' + '.join([re.sub("^.+\s(.+)$","\\1",s) for s in X.columns.tolist()])
  1124. if not normalizeByTIV: # exclude Abdominal, heart, DEXA
  1125. formula = formula.replace(" + TIV","")
  1126. if outlierStdv!=100: ## outlier removal
  1127. high = df_idf[dvmax].mean() + outlierStdv * df_idf[dvmax].std()
  1128. low = df_idf[dvmax].mean() - outlierStdv * df_idf[dvmax].std()
  1129. I = (df_idf[dvmax] <= high) & (df_idf[dvmax] >= low)
  1130. X2 = X2[I]
  1131. if LoR: # logistic regression
  1132. if timeOffset:
  1133. fitmodel,resT = runGLMLogit_severity_formula(X2, formula, dvmax, offset=X2['TimeOffset'], printResult=False, l1=False)
  1134. else:
  1135. fitmodel,resT = runGLMLogit_severity_formula(X2, formula, dvmax, printResult=False, l1=False)
  1136. if resT.empty:
  1137. continue
  1138. if paraEst=='permutation':
  1139. if timeOffset:
  1140. LR = pd.concat([LR, permutationGLMLogitregression(X2, formula, dvmax, resT, caseCol, pcol='P>|z|', pvalMethod='count-based', ntrials=ntrials, timeOffset=timeOffset)], axis=1)
  1141. else:
  1142. LR = pd.concat([LR, permutationGLMLogitregression(X2, formula, dvmax, resT, caseCol, pcol='P>|z|', pvalMethod='count-based', ntrials=ntrials, timeOffset=False)], axis=1)
  1143. elif paraEst=='bootstrapping':
  1144. if timeOffset:
  1145. LR = pd.concat([LR, bootstrapGLMLogitregression(X2, formula, dvmax, resT, caseCol,pcol='P>|z|', pvalMethod='count-based', ntrials=ntrials, timeOffset=timeOffset)], axis=1)
  1146. else:
  1147. LR = pd.concat([LR, bootstrapGLMLogitregression(X2, formula, dvmax, resT, caseCol,pcol='P>|z|', pvalMethod='count-based', ntrials=ntrials, timeOffset=False)], axis=1)
  1148. else:
  1149. LR = pd.concat([LR, resT], axis=1)
  1150. else: # OLS
  1151. if timeOffset:
  1152. fitmodel,resT = runGLMOLS_severity_formula(X2, formula, dvmax, offset=X2['TimeOffset'], printResult=False, l1=False)
  1153. else:
  1154. fitmodel,resT = runGLMOLS_severity_formula(X2, formula, dvmax, printResult=False, l1=False)
  1155. if paraEst=='permutation':
  1156. if timeOffset:
  1157. LR = pd.concat([LR, permutationGLMOLSregression(X2, formula, dvmax, resT, caseCol, pcol='P>|z|', pvalMethod='count-based', ntrials=ntrials, timeOffset=timeOffset)], axis=1)
  1158. else:
  1159. LR = pd.concat([LR, permutationGLMOLSregression(X2, formula, dvmax, resT, caseCol, pcol='P>|z|', pvalMethod='count-based', ntrials=ntrials, timeOffset=False)], axis=1)
  1160. elif paraEst=='bootstrapping':
  1161. if timeOffset:
  1162. LR = pd.concat([LR, bootstrapGLMOLSregression(X2, formula, dvmax, resT, caseCol, pcol='P>|z|', pvalMethod='count-based', ntrials=ntrials, timeOffset=timeOffset)], axis=1)
  1163. else:
  1164. LR = pd.concat([LR, bootstrapGLMOLSregression(X2, formula, dvmax, resT, caseCol, pcol='P>|z|', pvalMethod='count-based', ntrials=ntrials, timeOffset=False)], axis=1)
  1165. else:
  1166. LR = pd.concat([LR,resT], axis=1)
  1167. tested.append(sub_tested)
  1168. if paraEst in ['bootstrapping','permutation']:
  1169. paraEst2 = "_"+paraEst
  1170. else:
  1171. paraEst2 = ""
  1172. if LR.empty:
  1173. print(l, " has no usable variable")
  1174. continue
  1175. I = np.where(LR.loc[caseCol,'P>|z|'] <= 1.0)[0]
  1176. if(len(I)==0):
  1177. print(l, " has no significant result")
  1178. continue
  1179. lr = LR.iloc[:,np.sort(np.concatenate([I*7,I*7+1,I*7+2,I*7+3,I*7+4,I*7+5,I*7+6]))]
  1180. padj = (ss.multitest.fdrcorrection(LR.loc[caseCol,'P>|z|']))[1]
  1181. padjBonf = (ss.multitest.multipletests(LR.loc[caseCol,'P>|z|'], method='bonferroni'))[1]
  1182. target_I = int(np.where(LR.index==caseCol)[0])
  1183. b = pd.DataFrame([LR.iloc[0,np.sort(np.concatenate([I*7]))].values, LR.iloc[target_I,np.sort(np.concatenate([I*7]))].values, LR.iloc[target_I,np.sort(np.concatenate([I*7+2]))].values, padj[I], padjBonf[I], LR.iloc[target_I,np.sort(np.concatenate([I*7+3]))].values, LR.iloc[target_I,np.sort(np.concatenate([I*7+4]))].values, LR.iloc[target_I,np.sort(np.concatenate([I*7+5]))].values, LR.iloc[target_I,np.sort(np.concatenate([I*7+6]))].values, LR.iloc[1,np.sort(np.concatenate([I*7]))].values, LR.iloc[2,np.sort(np.concatenate([I*7]))].values]).T
  1184. b.columns = ['DF','Coefficient','P-value','Padj','Padj_Bonf','CI_025','CI_975','Coef_sx','Coef_sxsy','Sample_Count','Sample_Count_Case']
  1185. b['DF'+instance] = b['DF'].copy()
  1186. b['DF'] = [re.sub("^(.+)-\d+\.\d+$","\\1",i) for i in b['DF'] ]
  1187. b['DF'] = [re.sub("^(.+)-All$","\\1",i) for i in b['DF'] ]
  1188. if b['DF'].str.isnumeric().sum()==b.shape[0]:
  1189. b['DF'] = b['DF'].astype('int')
  1190. else:
  1191. b['DF'] = b['DF'].astype(str)
  1192. maps['DF'] = maps['DF'].astype(str)
  1193. sub1 = df_idf_1.loc[:,df_idf_1.columns.isin(b['DF'+instance])]
  1194. mean1 = sub1.mean(axis=0); std1=sub1.std(axis=0); min1=sub1.min(axis=0); q5_1=sub1.quantile(0.05, axis=0); q25_1=sub1.quantile(0.25, axis=0); med1=sub1.quantile(0.5, axis=0); q75_1=sub1.quantile(0.75, axis=0); q95_1=sub1.quantile(0.95, axis=0); max1=sub1.max(axis=0)
  1195. ms1 = pd.DataFrame(np.round(mean1,2).astype(str) + " \xb1 " + np.round(std1,2).astype(str), columns=['Case_mean[std]'])
  1196. sss = pd.DataFrame([min1,q5_1,q25_1,med1,q75_1,q95_1,max1],index=['Case_min','Case_q5','Case_q25','Case_q50','Case_q75','Case_q95','Case_max']).astype(str).T
  1197. b = pd.merge(b,ms1,how='left',left_on='DF'+instance,right_index=True)
  1198. b = pd.merge(b,sss,how='left',left_on='DF'+instance,right_index=True)
  1199. temp = pd.merge(maps[['DF','description','data_type','Image_type','Sub_classification']], b, left_on='DF',right_on='DF', how='inner')
  1200. temp = temp.sort_values('P-value')
  1201. if isinstance(outcomeDescriptions, pd.DataFrame):
  1202. temp.insert(0,'Outcome_description',outcomeDescriptions[outcomeDescriptions['DF']==outcome]['description'].tolist()[0])
  1203. else:
  1204. temp.insert(0,'Outcome_description','')
  1205. temp.insert(0,'Outcome',outcome)
  1206. temp.to_csv(output_dir+'/sig2_'+LRtype+outfile_suffix+'__'+l+"_"+suffix+paraEst2+postfix+"__"+outcome+"_"+instance+'_.csv',sep=",",header=True,index=False)

function_module.py at commit 3ae4b25, no license · at the source

Overview

Authors: Satoshi Okawa1,2,3, Yinan Shi1, Somanshu Banerjee4, Yi Yin Tai1, Jamal Nabhanizadeh5, Stefan Guenther6, Anisha N. Shah1, Siyi Jiang1,7, Timothy Kim8, Yassmin Al Aaraj1, Caroline Pidro9, Metin Aytekin1, Omolara Fatukasi10, Nishita Kalepalli1, Joseph Mettenburg11, Timothy D. Girard9, James T. Becker10, Kathiravan Kaliyappan12,13, Shanshan Song12,13, Sandra Breuils-Bonnet14
and 10 other authorsSteeve Provencher14, Sébastien Bonnet5,14, Theodore Huppert15, Lloyd D. Harvey1, Seyed Mehdi Nouraie16, Rajkumar Savai5,6,14, Dandan Sun12,13, Soban Umar4, Soni S. Pullamsetti5,6,14, Stephen Y. Chan1,8
16 affiliations
  1. Center for Pulmonary Vascular Biology and Medicine, Pittsburgh Heart, Lung, and Blood Vascular Medicine Institute, Division of Cardiology, Department of Medicine
  2. Department of Computational and Systems Biology; and
  3. McGowan Institute for Regenerative Medicine, University of Pittsburgh School of Medicine, Pittsburgh, Pennsylvania, USA
  4. Department of Anesthesiology and Perioperative Medicine, Division of Molecular Medicine, University of California, Los Angeles, Los Angeles, California, USA
  5. Institute for Lung Health, Department of Internal Medicine, German Center for Lung Research (DZL), Cardio-pulmonary Institute (CPI), Justus Liebig University, Giessen, Germany
  6. Max Planck Institute for Heart and Lung Research, DZL, CPI, Bad Nauheim, Germany
  7. Cellular and Molecular Pathology Graduate Program, University of Pittsburgh, Pittsburgh, Pennsylvania, USA
  8. Heart and Vascular Institute, University of Pittsburgh Medical Center (UPMC), Pittsburgh, Pennsylvania, USA
  9. Department of Critical Care Medicine
  10. Department of Psychiatry
  11. Department of Radiology, and
  12. Department of Neurology, University of Pittsburgh School of Medicine, Pittsburgh, Pennsylvania, USA
  13. Pittsburgh Veteran’s Affairs Research Center, Pittsburgh, Pennsylvania, USA
  14. PAH Research Group, Institut Universitaire de Cardiologie et Pneumologie de Québec Research Center, Department of Medicine, Université Laval, Quebec City, Québec, Canada
  15. Department of Electrical and Computer Engineering, Swanson School of Engineering, University of Pittsburgh, Pittsburgh, Pennsylvania, USA
  16. Division of Pulmonary, Allergy, and Critical Care Medicine, Department of Medicine, University of Pittsburgh School of Medicine, Pittsburgh, Pennsylvania, USA
Journal: The Journal of clinical investigation, volume 136, issue 21, article e195110
Dates: received 9 May 2025; accepted 3 September 2026; published online 2 November 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1172/jci195110 · PMID 42969225 · PMCID PMC13722401 · OpenAlex W7225064535
Open access: gold, a free copy (OpenAlex)
Status: code verified (how the code is found and verified)
Categories: genetics / omics (modality), human (organism), mouse (organism), other condition (population)
Methods: Spectral & time-frequency, Statistics
Keywords: Inflammation, Neuroscience, Pulmonology, Genetic risk factors, Neuroimaging, Transcriptomics
MeSH: Cerebellum*, Frontal Lobe*, Hypertension, Pulmonary*, Lung*, Aged, Animals, Female, Humans, Male, Mice, Mice, Knockout, Middle Aged, White Matter (* major topic)
Topic: Pulmonary Hypertension Research and Treatments (Pulmonary and Respiratory Medicine, Medicine), according to OpenAlex
Funding: WoodNext Foundation (Research Grant); Veterans Administration Medical Center (IK6 BX005647-01,I01BX006894-01); National Institutes of Health (R01HL161038, R35GM164224); American Heart Association (24CDA1274310, 26SFRNPVHD1609644, 24SFRNCCN1276089,24SFRNPCN1280228,25ISFRNCP1501443); National Aeronautics and Space Administration (80NSSC26K0720); Deutsche Forschungsgemeinschaft (SA 1923/7-1, Collaborative Research Center 1213 (A01/A05/A10N) (268555672)); European Research Council (866051)
Citations: not cited yet (Europe PMC); 82 references in the paper

Abstract

Connections between vascular and neurocognitive diseases are emerging but remain poorly defined. Cognitive impairment is increasingly recognized in pulmonary hypertension (PH), a disease traditionally viewed as limited to the heart and lungs. Given that inflammation is shared by PH and neurodegenerative diseases, we investigated its role in driving brain and cognitive deficits in PH. Using structural and functional MRI data from UK Biobank (N = 248 PH) and a prospective validation cohort, we identified reduced cerebellar white matter volume, thinner frontal gyri, and weakened cerebellar-frontal connectivity in patients with PH but not in other heart or lung diseases. These changes were accompanied by worsened executive function and processing speed. Olink proteomics and targeted genomics linked inflammatory plasma proteins and a PH-associated nuclear receptor coactivator 7 (NCOA7) single nucleotide polymorphism, rs11154337, to these deficits. PH cerebellum showed increased microglial activation and white matter derangement. In PH mice, Ncoa7 deficiency worsened cerebellar inflammation and atrophy. Microglial functional assays, cerebellar single-nucleus RNA sequencing, and spatial transcriptomic analyses further implicated Ncoa7-dependent lysosomal, inflammatory, and cell-specific mechanisms of cerebellar pathobiology. These findings identify NCOA7-linked inflammatory dysfunction in the cerebellar-frontal axis in PH, redefining this disease with neurologic consequences and thus offering neural targets for diagnostic, prognostic, and therapeutic development.

Reproduced under the paper's license (CC BY), from the paper cited above.

Repository

Its files are read in the Code ↔ Paper reader above, with 2 matches between paragraphs and lines of code.

PittVMIOSB/Okawa_et_al

License: none: the authors keep all their rights
State: the link answers, verified on 3 November 2026
Evidence: files inventoried
Commit: 3ae4b2540f1491eca8a5292851ea8d5ac437de4a, 22 April 2025
Languages: Python (4)
Size: 14 files, 4 scripts
Software Heritage: not archived
Found in: “Data availability.”
Holds: README
Not found: license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: NumPy (4 files), pandas (4 files), statsmodels (4 files), Matplotlib (1 file), scikit-learn (1 file), SciPy (1 file), seaborn (1 file)
Availability: 1 check, the latest on 3 November 2026: the link answers
  • 3 November 2026: the link answers
5 files

The paper's code and data availability statement is in the Data section.

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 4 scripts, each with its path and the digest of its content;
  • 2 matches between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

Datasets cited

Data availability

All materials and data from this study are available to researchers upon reasonable request and after issuance of relevant institutional data sharing agreements by contacting the corresponding authors. Human data with identifiers are restricted owing to patient confidentiality. The UKBB data can be accessed through the UKBB Research Analysis Portal (https://www.ukbiobank.ac.uk/enable-your-research). Raw and processed snRNA-seq and spatial transcriptomics data have been deposited in Gene Expression Omnibus under accession numbers GSE334773 and GSE334959, respectively. Analysis code is available with open access at the following GitHub repository: https://github.com/PittVMIOSB/Okawa_et_al (commit ID 3ae4b25). Any additional information required to reanalyze the data reported in this paper is available from the corresponding authors upon request. All raw data values are included in the Supporting Data Values file.

Reproduced under the paper's license (CC BY), from the paper cited above.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 1, 3 November 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 30 authors, 6 keywords, 13 MeSH terms, 7 funders, 82 references.

Cite

This paper

Okawa, S., Shi, Y., Banerjee, S., Tai, Y. Y., Nabhanizadeh, J., Guenther, S., Shah, A. N., Jiang, S., Kim, T., Al Aaraj, Y., Pidro, C., Aytekin, M., Fatukasi, O., Kalepalli, N., Mettenburg, J., Girard, T. D., Becker, J. T., Kaliyappan, K., Song, S., . . . Chan, S. Y. (2026). Cerebellar and frontal lobe alterations in pulmonary hypertension implicate an inflammatory lung vascular/brain axis. The Journal of clinical investigation, 136(21), e195110. https://doi.org/10.1172/jci195110

BibTeX

@article{okawa2026cerebellar,
author = {Okawa, Satoshi and Shi, Yinan and Banerjee, Somanshu and Tai, Yi Yin and Nabhanizadeh, Jamal and Guenther, Stefan and Shah, Anisha N. and Jiang, Siyi and Kim, Timothy and Al Aaraj, Yassmin and Pidro, Caroline and Aytekin, Metin and Fatukasi, Omolara and Kalepalli, Nishita and Mettenburg, Joseph and Girard, Timothy D. and Becker, James T. and Kaliyappan, Kathiravan and Song, Shanshan and Breuils-Bonnet, Sandra and Provencher, Steeve and Bonnet, Sébastien and Huppert, Theodore and Harvey, Lloyd D. and Nouraie, Seyed Mehdi and Savai, Rajkumar and Sun, Dandan and Umar, Soban and Pullamsetti, Soni S. and Chan, Stephen Y.},
title = {{Cerebellar and frontal lobe alterations in pulmonary hypertension implicate an inflammatory lung vascular/brain axis}},
journal = {The Journal of clinical investigation},
year = {2026},
month = nov,
volume = {136},
number = {21},
pages = {e195110},
publisher = {American Society for Clinical Investigation},
issn = {0021-9738},
doi = {10.1172/jci195110},
url = {https://doi.org/10.1172/jci195110},
pmid = {42969225},
pmcid = {PMC13722401}
}

RIS

TY - JOUR
AU - Okawa, Satoshi
AU - Shi, Yinan
AU - Banerjee, Somanshu
AU - Tai, Yi Yin
AU - Nabhanizadeh, Jamal
AU - Guenther, Stefan
AU - Shah, Anisha N.
AU - Jiang, Siyi
AU - Kim, Timothy
AU - Al Aaraj, Yassmin
AU - Pidro, Caroline
AU - Aytekin, Metin
AU - Fatukasi, Omolara
AU - Kalepalli, Nishita
AU - Mettenburg, Joseph
AU - Girard, Timothy D.
AU - Becker, James T.
AU - Kaliyappan, Kathiravan
AU - Song, Shanshan
AU - Breuils-Bonnet, Sandra
AU - Provencher, Steeve
AU - Bonnet, Sébastien
AU - Huppert, Theodore
AU - Harvey, Lloyd D.
AU - Nouraie, Seyed Mehdi
AU - Savai, Rajkumar
AU - Sun, Dandan
AU - Umar, Soban
AU - Pullamsetti, Soni S.
AU - Chan, Stephen Y.
TI - Cerebellar and frontal lobe alterations in pulmonary hypertension implicate an inflammatory lung vascular/brain axis
T2 - The Journal of clinical investigation
J2 - J Clin Invest
PY - 2026
DA - 2026/11/02
VL - 136
IS - 21
SP - e195110
SN - 0021-9738
PB - American Society for Clinical Investigation
DO - 10.1172/jci195110
UR - https://doi.org/10.1172/jci195110
LA - en
ER -

CSL-JSON

{
"id": "10.1172/jci195110",
"type": "article-journal",
"title": "Cerebellar and frontal lobe alterations in pulmonary hypertension implicate an inflammatory lung vascular/brain axis",
"container-title": "The Journal of clinical investigation",
"author": [
{
"family": "Okawa",
"given": "Satoshi"
},
{
"family": "Shi",
"given": "Yinan"
},
{
"family": "Banerjee",
"given": "Somanshu"
},
{
"family": "Tai",
"given": "Yi Yin"
},
{
"family": "Nabhanizadeh",
"given": "Jamal"
},
{
"family": "Guenther",
"given": "Stefan"
},
{
"family": "Shah",
"given": "Anisha N."
},
{
"family": "Jiang",
"given": "Siyi"
},
{
"family": "Kim",
"given": "Timothy"
},
{
"family": "Al Aaraj",
"given": "Yassmin"
},
{
"family": "Pidro",
"given": "Caroline"
},
{
"family": "Aytekin",
"given": "Metin"
},
{
"family": "Fatukasi",
"given": "Omolara"
},
{
"family": "Kalepalli",
"given": "Nishita"
},
{
"family": "Mettenburg",
"given": "Joseph"
},
{
"family": "Girard",
"given": "Timothy D."
},
{
"family": "Becker",
"given": "James T."
},
{
"family": "Kaliyappan",
"given": "Kathiravan"
},
{
"family": "Song",
"given": "Shanshan"
},
{
"family": "Breuils-Bonnet",
"given": "Sandra"
},
{
"family": "Provencher",
"given": "Steeve"
},
{
"family": "Bonnet",
"given": "Sébastien"
},
{
"family": "Huppert",
"given": "Theodore"
},
{
"family": "Harvey",
"given": "Lloyd D."
},
{
"family": "Nouraie",
"given": "Seyed Mehdi"
},
{
"family": "Savai",
"given": "Rajkumar"
},
{
"family": "Sun",
"given": "Dandan"
},
{
"family": "Umar",
"given": "Soban"
},
{
"family": "Pullamsetti",
"given": "Soni S."
},
{
"family": "Chan",
"given": "Stephen Y."
}
],
"container-title-short": "J Clin Invest",
"volume": "136",
"issue": "21",
"page": "e195110",
"DOI": "10.1172/jci195110",
"PMID": "42969225",
"PMCID": "PMC13722401",
"ISSN": "0021-9738",
"publisher": "American Society for Clinical Investigation",
"URL": "https://doi.org/10.1172/jci195110",
"language": "en",
"issued": {
"date-parts": [
[
2026,
11,
2
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.1038/s41591-024-03426-4 [code]
Plasma proteomic evidence for increased β-amyloid pathology after SARS-CoV-2 infection.
Journal: Nature medicine
In common: statsmodels, seaborn, scikit-learn, 4 other tools, ukbiobank.ac.uk/enable-your-research, genetics / omics, other condition
[2] doi:10.1002/hbm.26267 [code]
Optic radiations representing different eccentricities age differently.
Journal: Human brain mapping
In common: statsmodels, seaborn, pandas, 3 other tools, ukbiobank.ac.uk/enable-your-research
[3] doi:10.1038/s41586-026-10345-6 [code]
Population-scale repeat expansions elucidate disease risk and brain atrophy.
Journal: Nature
In common: statsmodels, pandas, SciPy, 2 other tools, ukbiobank.ac.uk/enable-your-research, genetics / omics, other condition
[4] doi:10.1038/s41467-026-72875-x [code]
Lifespan normative modeling of brain microstructure.
Journal: Nature communications
In common: seaborn, scikit-learn, pandas, 3 other tools, ukbiobank.ac.uk/enable-your-research
[5] doi:10.1038/s41398-025-03290-x [code]
Neurofind: using deep learning to make individualised inferences in brain-based disorders.
Journal: Translational psychiatry
In common: seaborn, scikit-learn, pandas, 3 other tools, ukbiobank.ac.uk/enable-your-research
[6] doi:10.1038/s43856-024-00496-w [code]
Convolutional neural network-based classification of glaucoma using optic radiation tissue properties.
Journal: Communications medicine
In common: statsmodels, scikit-learn, pandas, 2 other tools, ukbiobank.ac.uk/enable-your-research, other condition
[7] doi:10.1016/j.celrep.2025.116624 [code]
Spatial and single-cell transcriptomics reveal the reorganization of cerebellar microglia with aging.
Journal: Cell reports
In common: statsmodels, seaborn, scikit-learn, 4 other tools, genetics / omics, mouse, 2 references
[8] doi:10.1038/s41467-025-67578-8 [code]
Genetic Insights into Head-to-Body Ratios Via Deep Learning-Based Image Segmentation and Implications for Common Diseases.
Journal: Nature communications
In common: seaborn, scikit-learn, pandas, 2 other tools, ukbiobank.ac.uk/enable-your-research, genetics / omics
[9] doi:10.1038/s41514-026-00456-9 [code]
Exploring the link between body physiology and cognition: the role of the brain and aging.
Journal: npj aging
In common: statsmodels, seaborn, scikit-learn, 4 other tools, 2 references
[10] doi:10.3389/fnimg.2022.1031253 [code]
Automatic measure and normalization of spinal cord cross-sectional area using the pontomedullary junction.
Journal: Frontiers in neuroimaging
In common: seaborn, pandas, SciPy, 2 other tools, ukbiobank.ac.uk/enable-your-research

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Add the badge to the code's README

OSCR: the badge of this paper

If you are an author or a maintainer of this paper's code, you can add this badge. It says what OSCR knows of the paper (its code, its validated tracing map) and links the code to this page. Paste one of these snippets under the README's title. Keep the two marks around it, so that the badge can be replaced in place and is never added twice. OSCR changes nothing in your repository.

Markdown
<!-- oscr-badge:start -->
[![OSCR](https://openscicode.org/badge/doi/10.1172/jci195110.svg)](https://openscicode.org/badge/doi/10.1172/jci195110)
<!-- oscr-badge:end -->
reStructuredText
.. oscr-badge:start

.. image:: https://openscicode.org/badge/doi/10.1172/jci195110.svg
   :target: https://openscicode.org/badge/doi/10.1172/jci195110
   :alt: OSCR

.. oscr-badge:end
HTML
<!-- oscr-badge:start -->
<a href="https://openscicode.org/badge/doi/10.1172/jci195110"><img src="https://openscicode.org/badge/doi/10.1172/jci195110.svg" alt="OSCR"></a>
<!-- oscr-badge:end -->

On GitHub, open the README, choose Edit (the pencil), paste the snippet under the title, then "Commit changes".

If you choose to, you can have the badge kept up to date for you, with oscr badge --write from the command line or with the GitHub Action in your repository's workflows. Every other form and option (a card, AsciiDoc, LaTeX, shields.io) is on the badge page.

Request its removal

To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).

Discussion, reproductions, activity

Discussion: code errors and mismatches between the code and the paper about this paper and its code, from readers and its authors, beside the paper and its tracing map.

Report a mismatch between the code and the paper · Report a code error (signed in)

Reproductions: reports from readers who ran the authors' code and did not get the paper's result, what they ran, with which environment, commit and data.

Report a reproduction failure (signed in)

Versions of its code: the releases of its code tied to a version of this paper (the preprint, the accepted manuscript, the version of record…), each with the tracing map versioned with it.

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.