OSCR

Subthalamic beta activity and neuroimaging concordance in deep brain stimulation: electrode placement and clinical outcomes.

Code ↔ Paper

The paper beside its authors' code: matches between them have not been computed for this paper yet.

Paper

Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

Jupyter notebook · 543 lines · 21 KB · no license

  1. # %% [markdown]
  2. # # 4. Motor improvements (UPDRS III & IV analysis)
  3. # %% [markdown]
  4. # This is the fourth Notebook that has to be runned. In this one we will study the motor improvements in the UPDRS scale
  5. # %%
  6. # Load libraries
  7. import numpy as np
  8. import pandas as pd
  9. import matplotlib.pyplot as plt
  10. import seaborn as sns
  11. import scipy.stats as stats
  12. import scipy.stats
  13. from scipy.stats import chi2_contingency, f_oneway, kruskal, shapiro, anderson, ttest_rel, f_oneway, ttest_ind, kstest
  14. from statsmodels.stats.multicomp import pairwise_tukeyhsd
  15. import statsmodels.api as sm
  16. from statsmodels.formula.api import ols
  17. from statsmodels.stats.anova import anova_lm
  18. # %%
  19. df = pd.read_csv('/home/razkinm/projects/6articulodbs/raw/data.csv', sep=';')
  20. df_e = pd.read_csv('/home/razkinm/projects/6articulodbs/derivates/df_preprocessed.csv', sep=',')
  21. df_exploracion = df[['CIC', 'SEXO', 'DD', 'EDAD', 'UPDRS III Off - PREQX', 'UPDRS III On - PREQX', 'UPDRS IV - PRE', 'UPDRS III Off- POSTQX', 'UPDRS III On- POSTQX', 'UPDRS IV - POSTQX', 'LEAD IZQ', 'LEAD DER']]
  22. df_exploracion = df_exploracion.dropna()
  23. df_exploracion['COCANAL IZQ'] = None
  24. df_exploracion['COCANAL DER'] = None
  25. # Iterate over df_exploracion and df_e to compare values
  26. for index_exploracion, row_exploracion in df_exploracion.iterrows():
  27. for index_e, row_e in df_e.iterrows():
  28. if row_exploracion['CIC'] == row_e['ID']:
  29. if row_e['HEMISFERIO'] == 1:
  30. df_exploracion.at[index_exploracion, 'COCANAL DER'] = row_e['COCANAL']
  31. if row_e['HEMISFERIO'] == 0:
  32. df_exploracion.at[index_exploracion, 'COCANAL IZQ'] = row_e['COCANAL']
  33. df_exploracion['COCANAL DER'] = df_exploracion['COCANAL DER'].fillna(0)
  34. df_exploracion['COCANAL_GENERAL'] = np.where(
  35. (df_exploracion['COCANAL IZQ'] == 0) & (df_exploracion['COCANAL DER'] == 0), 0,
  36. np.where((df_exploracion['COCANAL IZQ'] == 1) & (df_exploracion['COCANAL DER'] == 1), 2, 1)
  37. )
  38. # create a new variable called 'COINCIDE IMAGEN' to check if LEAD IZQ and LEAD DER have the same value
  39. df_exploracion['BOTH OPTIMO'] = np.where((df_exploracion['LEAD IZQ'] == 'optimo') & (df_exploracion['LEAD DER'] == 'optimo'), 1, 0)
  40. conditions = [
  41. # 'optimo' paired with either 'optimo' or 'suboptimo' except when paired with 'fuera'
  42. ((df_exploracion['LEAD IZQ'] == 'optimo') & (df_exploracion['LEAD DER'].isin(['optimo', 'suboptimo']))) |
  43. ((df_exploracion['LEAD DER'] == 'optimo') & (df_exploracion['LEAD IZQ'].isin(['optimo', 'suboptimo']))),
  44. # All other cases get 0
  45. True # Acts as a catch-all for any cases not covered above
  46. ]
  47. # Define corresponding actions for each condition
  48. choices = [
  49. 1, # Cases where 'optimo' is paired as specified
  50. 0 # All other combinations
  51. ]
  52. # Create the new column based on these conditions
  53. df_exploracion['OPTIMO_vs_no'] = np.select(conditions, choices)
  54. # %% [markdown]
  55. # ## 4.1 UPDRS General Analysis
  56. # %%
  57. # UPDRS III Off - PREQX
  58. mean_UPDRSIIIOffPREQX = df_exploracion['UPDRS III Off - PREQX'].mean()
  59. std_UPDRSIIIOffPREQX = df_exploracion['UPDRS III Off - PREQX'].std()
  60. # UPDRS III On - PREQX
  61. mean_UPDRSIIIOnPREQX = df_exploracion['UPDRS III On - PREQX'].mean()
  62. std_UPDRSIIIOnPREQX = df_exploracion['UPDRS III On - PREQX'].std()
  63. # UPDRS IV - PRE
  64. mean_UPDRSIVPRE = df_exploracion['UPDRS IV - PRE'].mean()
  65. std_UPDRSIVPRE = df_exploracion['UPDRS IV - PRE'].std()
  66. # UPDRS III Off - POSTQX
  67. mean_UPDRSIIIOffPOSTQX = df_exploracion['UPDRS III Off- POSTQX'].mean()
  68. std_UPDRSIIIOffPOSTQX = df_exploracion['UPDRS III Off- POSTQX'].std()
  69. # UPDRS III Off - POSTQX
  70. mean_UPDRSIIIOnPOSTQX = df_exploracion['UPDRS III On- POSTQX'].mean()
  71. std_UPDRSIIIOnPOSTQX = df_exploracion['UPDRS III On- POSTQX'].std()
  72. # UPDRS IV - POSTQX
  73. mean_UPDRSIVPOST = df_exploracion['UPDRS IV - POSTQX'].mean()
  74. std_UPDRSIVPOST = df_exploracion['UPDRS IV - POSTQX'].std()
  75. # UPDRS III Off - PREQX
  76. female_mean_UPDRSIIIOffPREQX = df_exploracion[df_exploracion['SEXO'] == 1]['UPDRS III Off - PREQX'].mean()
  77. female_std_UPDRSIIIOffPREQX = df_exploracion[df_exploracion['SEXO'] == 1]['UPDRS III Off - PREQX'].std()
  78. # UPDRS III On - PREQX
  79. female_mean_UPDRSIIIOnPREQX = df_exploracion[df_exploracion['SEXO'] == 1]['UPDRS III On - PREQX'].mean()
  80. female_std_UPDRSIIIOnPREQX = df_exploracion[df_exploracion['SEXO'] == 1]['UPDRS III On - PREQX'].std()
  81. # UPDRS IV - PRE
  82. female_mean_UPDRSIVPRE = df_exploracion[df_exploracion['SEXO'] == 1]['UPDRS IV - PRE'].mean()
  83. female_std_UPDRSIVPRE = df_exploracion[df_exploracion['SEXO'] == 1]['UPDRS IV - PRE'].std()
  84. # UPDRS III Off - POSTQX
  85. female_mean_UPDRSIIIOffPOSTQX = df_exploracion[df_exploracion['SEXO'] == 1]['UPDRS III Off- POSTQX'].mean()
  86. female_std_UPDRSIIIOffPOSTQX = df_exploracion[df_exploracion['SEXO'] == 1]['UPDRS III Off- POSTQX'].std()
  87. # UPDRS III Off - POSTQX
  88. female_mean_UPDRSIIIOnPOSTQX = df_exploracion[df_exploracion['SEXO'] == 1]['UPDRS III On- POSTQX'].mean()
  89. female_std_UPDRSIIIOnPOSTQX = df_exploracion[df_exploracion['SEXO'] == 1]['UPDRS III On- POSTQX'].std()
  90. # UPDRS IV - POSTQX
  91. female_mean_UPDRSIVPOST = df_exploracion[df_exploracion['SEXO'] == 1]['UPDRS IV - POSTQX'].mean()
  92. female_std_UPDRSIVPOST = df_exploracion[df_exploracion['SEXO'] == 1]['UPDRS IV - POSTQX'].std()
  93. # UPDRS III Off - PREQX
  94. male_mean_UPDRSIIIOffPREQX = df_exploracion[df_exploracion['SEXO'] == 2]['UPDRS III Off - PREQX'].mean()
  95. male_std_UPDRSIIIOffPREQX = df_exploracion[df_exploracion['SEXO'] == 2]['UPDRS III Off - PREQX'].std()
  96. # UPDRS III On - PREQX
  97. male_mean_UPDRSIIIOnPREQX = df_exploracion[df_exploracion['SEXO'] == 2]['UPDRS III On - PREQX'].mean()
  98. male_std_UPDRSIIIOnPREQX = df_exploracion[df_exploracion['SEXO'] == 2]['UPDRS III On - PREQX'].std()
  99. # UPDRS IV - PRE
  100. male_mean_UPDRSIVPRE = df_exploracion[df_exploracion['SEXO'] == 2]['UPDRS IV - PRE'].mean()
  101. male_std_UPDRSIVPRE = df_exploracion[df_exploracion['SEXO'] == 2]['UPDRS IV - PRE'].std()
  102. # UPDRS III Off - POSTQX
  103. male_mean_UPDRSIIIOffPOSTQX = df_exploracion[df_exploracion['SEXO'] == 2]['UPDRS III Off- POSTQX'].mean()
  104. male_std_UPDRSIIIOffPOSTQX = df_exploracion[df_exploracion['SEXO'] == 2]['UPDRS III Off- POSTQX'].std()
  105. # UPDRS III Off - POSTQX
  106. male_mean_UPDRSIIIOnPOSTQX = df_exploracion[df_exploracion['SEXO'] == 2]['UPDRS III On- POSTQX'].mean()
  107. male_std_UPDRSIIIOnPOSTQX = df_exploracion[df_exploracion['SEXO'] == 2]['UPDRS III On- POSTQX'].std()
  108. # UPDRS IV - POSTQX
  109. male_mean_UPDRSIVPOST = df_exploracion[df_exploracion['SEXO'] == 2]['UPDRS IV - POSTQX'].mean()
  110. male_std_UPDRSIVPOST = df_exploracion[df_exploracion['SEXO'] == 2]['UPDRS IV - POSTQX'].std()
  111. # print all results
  112. print('UPDRS III Off - PREQX')
  113. print('Mean:', mean_UPDRSIIIOffPREQX)
  114. print('Standard Deviation:', std_UPDRSIIIOffPREQX)
  115. print('UPDRS III On - PREQX')
  116. print('Mean:', mean_UPDRSIIIOnPREQX)
  117. print('Standard Deviation:', std_UPDRSIIIOnPREQX)
  118. print('UPDRS IV - PRE')
  119. print('Mean:', mean_UPDRSIVPRE)
  120. print('Standard Deviation:', std_UPDRSIVPRE)
  121. print('UPDRS III Off - POSTQX')
  122. print('Mean:', mean_UPDRSIIIOffPOSTQX)
  123. print('Standard Deviation:', std_UPDRSIIIOffPOSTQX)
  124. print('UPDRS III On - POSTQX')
  125. print('Mean:', mean_UPDRSIIIOnPOSTQX)
  126. print('Standard Deviation:', std_UPDRSIIIOnPOSTQX)
  127. print('UPDRS IV - POSTQX')
  128. print('Mean:', mean_UPDRSIVPOST)
  129. print('Standard Deviation:', std_UPDRSIVPOST)
  130. print('UPDRS FEMALE')
  131. print('UPDRS III Off - PREQX')
  132. print('Mean:', female_mean_UPDRSIIIOffPREQX)
  133. print('Standard Deviation:', female_std_UPDRSIIIOffPREQX)
  134. print('UPDRS III On - PREQX')
  135. print('Mean:', female_mean_UPDRSIIIOnPREQX)
  136. print('Standard Deviation:', female_std_UPDRSIIIOnPREQX)
  137. print('UPDRS IV - PRE')
  138. print('Mean:', female_mean_UPDRSIVPRE)
  139. print('Standard Deviation:', female_std_UPDRSIVPRE)
  140. print('UPDRS III Off - POSTQX')
  141. print('Mean:', female_mean_UPDRSIIIOffPOSTQX)
  142. print('Standard Deviation:', female_std_UPDRSIIIOffPOSTQX)
  143. print('UPDRS III On - POSTQX')
  144. print('Mean:', female_mean_UPDRSIIIOnPOSTQX)
  145. print('Standard Deviation:', female_std_UPDRSIIIOnPOSTQX)
  146. print('UPDRS IV - POSTQX')
  147. print('Mean:', female_mean_UPDRSIVPOST)
  148. print('Standard Deviation:', female_std_UPDRSIVPOST)
  149. print('UPDRS MALE')
  150. print('UPDRS III Off - PREQX')
  151. print('Mean:', male_mean_UPDRSIIIOffPREQX)
  152. print('Standard Deviation:', male_std_UPDRSIIIOffPREQX)
  153. print('UPDRS III On - PREQX')
  154. print('Mean:', male_mean_UPDRSIIIOnPREQX)
  155. print('Standard Deviation:', male_std_UPDRSIIIOnPREQX)
  156. print('UPDRS IV - PRE')
  157. print('Mean:', male_mean_UPDRSIVPRE)
  158. print('Standard Deviation:', male_std_UPDRSIVPRE)
  159. print('UPDRS III Off - POSTQX')
  160. print('Mean:', male_mean_UPDRSIIIOffPOSTQX)
  161. print('Standard Deviation:', male_std_UPDRSIIIOffPOSTQX)
  162. print('UPDRS III On - POSTQX')
  163. print('Mean:', male_mean_UPDRSIIIOnPOSTQX)
  164. print('Standard Deviation:', male_std_UPDRSIIIOnPOSTQX)
  165. print('UPDRS IV - POSTQX')
  166. print('Mean:', male_mean_UPDRSIVPOST)
  167. print('Standard Deviation:', male_std_UPDRSIVPOST)
  168. # %% [markdown]
  169. # ## 4.2 Is there a stadistically difference between people that have optimo/suboptimo or suboptimo/fuera?
  170. # %% [markdown]
  171. # #### For UPDRS III Off
  172. # %%
  173. # Assuming 'UPDRS III Off - PREQX' and 'UPDRS III Off - POSTQX' are your columns
  174. df_exploracion['DIFF UPDRS III Off'] = df_exploracion['UPDRS III Off- POSTQX'] - df_exploracion['UPDRS III Off - PREQX']
  175. from scipy.stats import shapiro, levene, ttest_ind, mannwhitneyu, kstest
  176. # Split the data into two groups
  177. group1 = df_exploracion[df_exploracion['OPTIMO_vs_no'] == 1]['DIFF UPDRS III Off'].dropna()
  178. group2 = df_exploracion[df_exploracion['OPTIMO_vs_no'] == 0]['DIFF UPDRS III Off'].dropna()
  179. # Test for normality
  180. print("Normality Test (Shapiro-Wilk):")
  181. norm1 = scipy.stats.kstest(group1)
  182. norm2 = scipy.stats.kstest(group2)
  183. print("Group 1:", norm1)
  184. print("Group 2:", norm2)
  185. # Test for equality of variances
  186. print("Equality of Variances Test (Levene’s Test):")
  187. lev_test = levene(group1, group2)
  188. print(lev_test)
  189. # Choose the test based on the assumptions
  190. print("\nIndependent Samples Test:")
  191. if norm1.pvalue > 0.05 and norm2.pvalue > 0.05 and lev_test.pvalue > 0.05:
  192. # If both distributions are normal and variances are equal, use t-test
  193. t_stat, p_val = ttest_ind(group1, group2)
  194. print(f"Independent t-test: t={t_stat}, p={p_val}")
  195. else:
  196. # If assumptions are not met, use Mann-Whitney U test
  197. u_stat, p_val = mannwhitneyu(group1, group2)
  198. print(f"Mann-Whitney U test: U={u_stat}, p={p_val}")
  199. # Interpret the p-value
  200. if p_val < 0.05:
  201. print("There is a statistically significant difference between the groups.")
  202. else:
  203. print("There is no statistically significant difference between the groups.")
  204. # %% [markdown]
  205. # #### For UPDRS III On
  206. # %%
  207. # Assuming 'UPDRS III Off - PREQX' and 'UPDRS III Off - POSTQX' are your columns
  208. df_exploracion['DIFF UPDRS III On'] = df_exploracion['UPDRS III On- POSTQX'] - df_exploracion['UPDRS III On - PREQX']
  209. from scipy.stats import shapiro, levene, ttest_ind, mannwhitneyu, norm
  210. # Split the data into two groups
  211. group1 = df_exploracion[df_exploracion['OPTIMO_vs_no'] == 1]['DIFF UPDRS III On'].dropna()
  212. group2 = df_exploracion[df_exploracion['OPTIMO_vs_no'] == 0]['DIFF UPDRS III On'].dropna()
  213. data = group1
  214. mean, std = norm.fit(data) # Fit a normal distribution to get mean and std
  215. stat, p = kstest(data, 'norm', args=(mean, std))
  216. print("Statistic:", stat, "P-value:", p)
  217. data = group2
  218. mean, std = norm.fit(data) # Fit a normal distribution to get mean and std
  219. stat, p = kstest(data, 'norm', args=(mean, std))
  220. print("Statistic:", stat, "P-value:", p)
  221. if p > 0.05:
  222. print("Data is normally distributed (fail to reject H0).")
  223. else:
  224. print("Data is not normally distributed (reject H0).")
  225. if p > 0.05:
  226. print("Data is normally distributed (fail to reject H0).")
  227. else:
  228. print("Data is not normally distributed (reject H0).")
  229. # Test for normality
  230. print("Normality Test (Shapiro-Wilk):")
  231. norm1 = shapiro(group1)
  232. norm2 = shapiro(group2)
  233. print("Group 1:", norm1)
  234. print("Group 2:", norm2)
  235. # Test for equality of variances
  236. print("Equality of Variances Test (Levene’s Test):")
  237. lev_test = levene(group1, group2)
  238. print(lev_test)
  239. # Choose the test based on the assumptions
  240. print("\nIndependent Samples Test:")
  241. if norm1.pvalue > 0.05 and norm2.pvalue > 0.05 and lev_test.pvalue > 0.05:
  242. # If both distributions are normal and variances are equal, use t-test
  243. t_stat, p_val = ttest_ind(group1, group2)
  244. print(f"Independent t-test: t={t_stat}, p={p_val}")
  245. else:
  246. # If assumptions are not met, use Mann-Whitney U test
  247. u_stat, p_val = mannwhitneyu(group1, group2)
  248. print(f"Mann-Whitney U test: U={u_stat}, p={p_val}")
  249. # Interpret the p-value
  250. if p_val < 0.05:
  251. print("There is a statistically significant difference between the groups.")
  252. else:
  253. print("There is no statistically significant difference between the groups.")
  254. # %% [markdown]
  255. # #### For UPDRS IV
  256. # %%
  257. # Assuming 'UPDRS III Off - PREQX' and 'UPDRS III Off - POSTQX' are your columns
  258. df_exploracion['DIFF UPDRS IV'] = df_exploracion['UPDRS IV - POSTQX'] - df_exploracion['UPDRS IV - PRE']
  259. from scipy.stats import shapiro, levene, ttest_ind, mannwhitneyu
  260. # Split the data into two groups
  261. group1 = df_exploracion[df_exploracion['OPTIMO_vs_no'] == 1]['DIFF UPDRS IV'].dropna()
  262. group2 = df_exploracion[df_exploracion['OPTIMO_vs_no'] == 0]['DIFF UPDRS IV'].dropna()
  263. # Test for normality
  264. print("Normality Test (Shapiro-Wilk):")
  265. norm1 = shapiro(group1)
  266. norm2 = shapiro(group2)
  267. print("Group 1:", norm1)
  268. print("Group 2:", norm2)
  269. # Test for equality of variances
  270. print("Equality of Variances Test (Levene’s Test):")
  271. lev_test = levene(group1, group2)
  272. print(lev_test)
  273. # Choose the test based on the assumptions
  274. print("\nIndependent Samples Test:")
  275. if norm1.pvalue > 0.05 and norm2.pvalue > 0.05 and lev_test.pvalue > 0.05:
  276. # If both distributions are normal and variances are equal, use t-test
  277. t_stat, p_val = ttest_ind(group1, group2)
  278. print(f"Independent t-test: t={t_stat}, p={p_val}")
  279. else:
  280. # If assumptions are not met, use Mann-Whitney U test
  281. u_stat, p_val = mannwhitneyu(group1, group2)
  282. print(f"Mann-Whitney U test: U={u_stat}, p={p_val}")
  283. # Interpret the p-value
  284. if p_val < 0.05:
  285. print("There is a statistically significant difference between the groups.")
  286. else:
  287. print("There is no statistically significant difference between the groups.")
  288. # %% [markdown]
  289. # ## 4.3 Analysis for differences related to sex, age or disease duration
  290. # %% [markdown]
  291. # ## Any difference related to age?
  292. # %%
  293. df = df_exploracion.rename(columns={
  294. 'UPDRS III Off - PREQX': 'UPDRS_III_Off_PREQX',
  295. 'UPDRS III Off- POSTQX': 'UPDRS_III_Off_POSTQX',
  296. 'UPDRS III On - PREQX': 'UPDRS_III_On_PREQX',
  297. 'UPDRS III On- POSTQX': 'UPDRS_III_On_POSTQX',
  298. 'UPDRS IV - PRE': 'UPDRS_IV_PRE',
  299. 'UPDRS IV - POSTQX': 'UPDRS_IV_POSTQX',
  300. 'EDAD': 'EDAD'
  301. })
  302. df['UPDRS_III_Off_Diff'] = df['UPDRS_III_Off_POSTQX'] - df['UPDRS_III_Off_PREQX']
  303. df['UPDRS_III_On_Diff'] = df['UPDRS_III_On_POSTQX'] - df['UPDRS_III_On_PREQX']
  304. df['UPDRS_IV_Diff'] = df['UPDRS_IV_POSTQX'] - df['UPDRS_IV_PRE']
  305. # Análisis de regresión para verificar el efecto de la edad
  306. def regress_age_effect(df, dependent_var):
  307. X = sm.add_constant(df['EDAD'])
  308. model = sm.OLS(df[dependent_var], X).fit()
  309. print(f"Regression analysis for {dependent_var} on AGE")
  310. print(model.summary())
  311. regress_age_effect(df, 'UPDRS_III_Off_Diff')
  312. regress_age_effect(df, 'UPDRS_III_On_Diff')
  313. regress_age_effect(df, 'UPDRS_IV_Diff')
  314. # %% [markdown]
  315. # No hay evidencia significativa de que la edad tenga un efecto en las diferencias en las puntuaciones UPDRS_III_Off (p-valor = 0.794).
  316. # No hay evidencia significativa de que la edad tenga un efecto en las diferencias en las puntuaciones UPDRS_III_On (p-valor = 0.653).
  317. # No hay evidencia significativa de que la edad tenga un efecto en las diferencias en las puntuaciones UPDRS_IV_Diff (p-valor = 0.412).
  318. # %% [markdown]
  319. # ## Any difference related to sex?
  320. # %% [markdown]
  321. # ### Linear Regression Analysis
  322. # %%
  323. df = df_exploracion.rename(columns={
  324. 'UPDRS III Off - PREQX': 'UPDRS_III_Off_PREQX',
  325. 'UPDRS III Off- POSTQX': 'UPDRS_III_Off_POSTQX',
  326. 'UPDRS III On - PREQX': 'UPDRS_III_On_PREQX',
  327. 'UPDRS III On- POSTQX': 'UPDRS_III_On_POSTQX',
  328. 'UPDRS IV - PRE': 'UPDRS_IV_PRE',
  329. 'UPDRS IV - POSTQX': 'UPDRS_IV_POSTQX',
  330. 'SEXO': 'SEXO'
  331. })
  332. # Calcular las diferencias en las puntuaciones
  333. df['UPDRS_III_Off_Diff'] = df['UPDRS_III_Off_POSTQX'] - df['UPDRS_III_Off_PREQX']
  334. df['UPDRS_III_On_Diff'] = df['UPDRS_III_On_POSTQX'] - df['UPDRS_III_On_PREQX']
  335. df['UPDRS_IV_Diff'] = df['UPDRS_IV_POSTQX'] - df['UPDRS_IV_PRE']
  336. # Análisis de regresión para verificar el efecto del sexo
  337. def regress_sex_effect(df, dependent_var):
  338. X = sm.add_constant(df['SEXO'])
  339. model = sm.OLS(df[dependent_var], X).fit()
  340. print(f"Regression analysis for {dependent_var} on SEX")
  341. print(model.summary())
  342. # Verificar el efecto del sexo en las diferencias UPDRS
  343. regress_sex_effect(df, 'UPDRS_III_Off_Diff')
  344. regress_sex_effect(df, 'UPDRS_III_On_Diff')
  345. regress_sex_effect(df, 'UPDRS_IV_Diff')
  346. # %%
  347. # Filtrar los datos según LEAD y SEXO
  348. df_filtered_optimosub_male = df_exploracion[(df_exploracion['OPTIMO_vs_no'] == 1) & (df_exploracion['SEXO'] == 2)]
  349. df_filtered_optimosub_female = df_exploracion[(df_exploracion['OPTIMO_vs_no'] == 1) & (df_exploracion['SEXO'] == 1)]
  350. df_filtered_subfuera_male = df_exploracion[(df_exploracion['OPTIMO_vs_no'] == 0) & (df_exploracion['SEXO'] == 2)]
  351. df_filtered_subfuera_female = df_exploracion[(df_exploracion['OPTIMO_vs_no'] == 0) & (df_exploracion['SEXO'] == 1)]
  352. # Diccionario para almacenar los resultados
  353. results = {
  354. 'Group': [],
  355. 'UPDRS III Off': [],
  356. 'UPDRS III On': [],
  357. 'UPDRS IV': []
  358. }
  359. def paired_t_tests(df, group_name):
  360. # Calcular el tamaño de la muestra
  361. n = len(df)
  362. # Prueba t pareada para UPDRS III Off
  363. ttest_off = ttest_rel(df['UPDRS III Off - PREQX'], df['UPDRS III Off- POSTQX'])
  364. print(f"Paired t-test {group_name} UPDRS III Off (N={n}): t={ttest_off.statistic}, p={ttest_off.pvalue:.3f}")
  365. # Prueba t pareada para UPDRS III On
  366. ttest_on = ttest_rel(df['UPDRS III On - PREQX'], df['UPDRS III On- POSTQX'])
  367. print(f"Paired t-test {group_name} UPDRS III On (N={n}): t={ttest_on.statistic}, p={ttest_on.pvalue:.3f}")
  368. # Prueba t pareada para UPDRS IV
  369. ttest_iv = ttest_rel(df['UPDRS IV - PRE'], df['UPDRS IV - POSTQX'])
  370. print(f"Paired t-test {group_name} UPDRS IV (N={n}): t={ttest_iv.statistic}, p={ttest_iv.pvalue:.3f}")
  371. # Guardar los resultados en el diccionario
  372. results['Group'].append(group_name)
  373. results['UPDRS III Off'].append(round(ttest_off.pvalue, 3))
  374. results['UPDRS III On'].append(round(ttest_on.pvalue, 3))
  375. results['UPDRS IV'].append(round(ttest_iv.pvalue, 3))
  376. # Realizar las pruebas para cada grupo y sexo
  377. print('OPTIMOSUB - Male')
  378. paired_t_tests(df_filtered_optimosub_male, 'OPTIMO - Male')
  379. print('OPTIMOSUB - Female')
  380. paired_t_tests(df_filtered_optimosub_female, 'OPTIMO - Female')
  381. # Crear la tabla comparativa
  382. results_df = pd.DataFrame(results)
  383. print("\nResultados Comparativos de p-valores")
  384. print(results_df)
  385. # %%
  386. # df_sex = df_exploracion but just the rows that have OPTIMO_vs_no == 1
  387. df_sex = df_exploracion[df_exploracion['OPTIMO_vs_no'] == 1]
  388. df = df_sex.rename(columns={
  389. 'UPDRS III Off - PREQX': 'UPDRS_III_Off_PREQX',
  390. 'UPDRS III Off- POSTQX': 'UPDRS_III_Off_POSTQX',
  391. 'UPDRS III On - PREQX': 'UPDRS_III_On_PREQX',
  392. 'UPDRS III On- POSTQX': 'UPDRS_III_On_POSTQX',
  393. 'UPDRS IV - PRE': 'UPDRS_IV_PRE',
  394. 'UPDRS IV - POSTQX': 'UPDRS_IV_POSTQX',
  395. 'SEXO': 'SEXO'
  396. })
  397. # Calcular las diferencias en las puntuaciones
  398. df['UPDRS_III_Off_Diff'] = df['UPDRS_III_Off_POSTQX'] - df['UPDRS_III_Off_PREQX']
  399. df['UPDRS_III_On_Diff'] = df['UPDRS_III_On_POSTQX'] - df['UPDRS_III_On_PREQX']
  400. df['UPDRS_IV_Diff'] = df['UPDRS_IV_POSTQX'] - df['UPDRS_IV_PRE']
  401. # Análisis de regresión para verificar el efecto del sexo
  402. def regress_sex_effect(df, dependent_var):
  403. X = sm.add_constant(df['SEXO'])
  404. model = sm.OLS(df[dependent_var], X).fit()
  405. print(f"Regression analysis for {dependent_var} on SEX")
  406. print(model.summary())
  407. # Verificar el efecto del sexo en las diferencias UPDRS
  408. regress_sex_effect(df, 'UPDRS_III_Off_Diff')
  409. regress_sex_effect(df, 'UPDRS_III_On_Diff')
  410. regress_sex_effect(df, 'UPDRS_IV_Diff')
  411. # %% [markdown]
  412. # ## Any difference related to disease duration?
  413. # %% [markdown]
  414. # #### Linear Regression
  415. # %%
  416. df = df_exploracion.rename(columns={
  417. 'UPDRS III Off - PREQX': 'UPDRS_III_Off_PREQX',
  418. 'UPDRS III Off- POSTQX': 'UPDRS_III_Off_POSTQX',
  419. 'UPDRS III On - PREQX': 'UPDRS_III_On_PREQX',
  420. 'UPDRS III On- POSTQX': 'UPDRS_III_On_POSTQX',
  421. 'UPDRS IV - PRE': 'UPDRS_IV_PRE',
  422. 'UPDRS IV - POSTQX': 'UPDRS_IV_POSTQX',
  423. 'DD': 'DURATION'
  424. })
  425. # Calcular las diferencias en las puntuaciones
  426. df['UPDRS_III_Off_Diff'] = df['UPDRS_III_Off_POSTQX'] - df['UPDRS_III_Off_PREQX']
  427. df['UPDRS_III_On_Diff'] = df['UPDRS_III_On_POSTQX'] - df['UPDRS_III_On_PREQX']
  428. df['UPDRS_IV_Diff'] = df['UPDRS_IV_POSTQX'] - df['UPDRS_IV_PRE']
  429. # Análisis de regresión para verificar el efecto del sexo
  430. def regress_sex_effect(df, dependent_var):
  431. X = sm.add_constant(df['DURATION'])
  432. model = sm.OLS(df[dependent_var], X).fit()
  433. print(f"Regression analysis for {dependent_var} on DURATION")
  434. print(model.summary())
  435. # Verificar el efecto del sexo en las diferencias UPDRS
  436. regress_sex_effect(df, 'UPDRS_III_Off_Diff')
  437. regress_sex_effect(df, 'UPDRS_III_On_Diff')
  438. regress_sex_effect(df, 'UPDRS_IV_Diff')

UPDRS.ipynb at commit 451a9ca, no license · at the source

Overview

Authors: Malen Razkin1,2, Edurne Ruiz de Gopegui3, Beatriz Tijero4,5,6, Tamara Fernández del Valle4,5, Gaizka Bilbao3, Ainara Dolado7,8, Imanol Lambarri9, Juan Carlos Gómez-Estéban4,5,6,10, Asier Erramuzpe2,11, Marta Ruiz-Lopez4,5
  1. Biomedical Research Doctorate Program, University of the Basque Country, Leioa, Spain
  2. Computational Neuroimaging Lab, Biobizkaia Health Research Institute, Barakaldo, Spain
  3. Department of Neurosurgery, Cruces University Hospital, Barakaldo, Spain
  4. Neurodegenerative Diseases Group, Biobizkaia Bizkaia Health Research Institute, Barakaldo, Spain
  5. Department of Neurology, Cruces University Hospital, Barakaldo, Spain
  6. CIBERNED-CIBER, Institute Carlos III, Madrid, Spain
  7. Radiology Department, Cruces University Hospital, Barakaldo, Spain
  8. Department of Surgery and Radiology and Physical Medicine, University of the Basque Country UPV/EHU, Leioa, Spain
  9. Neurophysiology Department, Cruces University Hospital, Barakaldo, Spain
  10. Department of Neurosciences, University of the Basque Country UPV/EHU, Leioa, Spain
  11. Ikerbasque: The Basque Foundation for Science, Bilbao, Spain
Journal: Clinical neurophysiology practice, volume 11, pages 766-773
Dates: received 3 February 2026; accepted 23 August 2026; published online 27 August 2026
Type: Research article · Language: English
License: CC BY-NC-ND
Identifiers: DOI 10.1016/j.cnp.2026.08.008 · PMID 42733699 · PMCID PMC13571461 · OpenAlex W7204472157
Open access: gold, a free copy (OpenAlex)
Status: code verified
Methods: Statistics
Keywords: Deep brain stimulation, Subthalamic nucleus, Local field potentials, Neuroimaging, UPDRS
Topic: Neurological disorders and treatments (Neurology, Medicine), according to OpenAlex
Funding: Ikerbasque, Basque Foundation for Science; Ministerio de Ciencia e Innovación (RYC2021-032390-I, RYC2021); Instituto de Salud Carlos III (PI23/01270)
Citations: not cited yet (Europe PMC); 31 references in the paper

Abstract

The abstract is not reproduced here: the paper's license (CC BY-NC-ND) does not allow it. Read it in the paper, at the publisher or on Europe PMC.

Repository

Its files are read in the Code ↔ Paper reader above.

compneurobilbao/stn-beta-analysis

License: none: the authors keep all their rights
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: 451a9ca2349c7c74a04ec071a4e16f8d1f5fb343, 26 November 2025
Languages: Jupyter (4)
Size: 7 files, 4 scripts
Software Heritage: not archived
Found in: the text, “Statistics”
Holds: README, environment (requirements.txt), 4 notebooks
Not found: license file, CITATION.cff, tests, continuous integration, documentation
Tools: Matplotlib (4 files), NumPy (4 files), pandas (4 files), SciPy (4 files), seaborn (4 files), statsmodels (4 files)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
5 files

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;
  • no match between paragraphs and code yet;
  • 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

No dataset and no data link were found in the paper.

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 2, 28 September 2026

  • Funding: added Ikerbasque, Basque Foundation for Science; Ministerio de Ciencia e Innovación: RYC2021-032390-I, RYC2021; Instituto de Salud Carlos III: PI23/01270

Version 1, 27 September 2026: the first record

Recorded: type, language, journal, volume, pages, dates, 10 authors, 5 keywords, 31 references.

Cite

This paper

Razkin, M., de Gopegui, E. R., Tijero, B., del Valle, T. F., Bilbao, G., Dolado, A., Lambarri, I., Gómez-Estéban, J. C., Erramuzpe, A., & Ruiz-Lopez, M. (2026). Subthalamic beta activity and neuroimaging concordance in deep brain stimulation: electrode placement and clinical outcomes. Clinical neurophysiology practice, 11, 766-773. https://doi.org/10.1016/j.cnp.2026.08.008

BibTeX

@article{razkin2026subthalamic,
author = {Razkin, Malen and de Gopegui, Edurne Ruiz and Tijero, Beatriz and del Valle, Tamara Fernández and Bilbao, Gaizka and Dolado, Ainara and Lambarri, Imanol and Gómez-Estéban, Juan Carlos and Erramuzpe, Asier and Ruiz-Lopez, Marta},
title = {{Subthalamic beta activity and neuroimaging concordance in deep brain stimulation: electrode placement and clinical outcomes}},
journal = {Clinical neurophysiology practice},
year = {2026},
month = aug,
volume = {11},
pages = {766--773},
publisher = {Elsevier},
issn = {2467-981X},
doi = {10.1016/j.cnp.2026.08.008},
url = {https://doi.org/10.1016/j.cnp.2026.08.008},
pmid = {42733699},
pmcid = {PMC13571461}
}

RIS

TY - JOUR
AU - Razkin, Malen
AU - de Gopegui, Edurne Ruiz
AU - Tijero, Beatriz
AU - del Valle, Tamara Fernández
AU - Bilbao, Gaizka
AU - Dolado, Ainara
AU - Lambarri, Imanol
AU - Gómez-Estéban, Juan Carlos
AU - Erramuzpe, Asier
AU - Ruiz-Lopez, Marta
TI - Subthalamic beta activity and neuroimaging concordance in deep brain stimulation: electrode placement and clinical outcomes
T2 - Clinical neurophysiology practice
J2 - Clin Neurophysiol Pract
PY - 2026
DA - 2026/08/27
VL - 11
SP - 766
EP - 773
SN - 2467-981X
PB - Elsevier
DO - 10.1016/j.cnp.2026.08.008
UR - https://doi.org/10.1016/j.cnp.2026.08.008
LA - en
ER -

CSL-JSON

{
"id": "10.1016/j.cnp.2026.08.008",
"type": "article-journal",
"title": "Subthalamic beta activity and neuroimaging concordance in deep brain stimulation: electrode placement and clinical outcomes",
"container-title": "Clinical neurophysiology practice",
"author": [
{
"family": "Razkin",
"given": "Malen"
},
{
"family": "de Gopegui",
"given": "Edurne Ruiz"
},
{
"family": "Tijero",
"given": "Beatriz"
},
{
"family": "del Valle",
"given": "Tamara Fernández"
},
{
"family": "Bilbao",
"given": "Gaizka"
},
{
"family": "Dolado",
"given": "Ainara"
},
{
"family": "Lambarri",
"given": "Imanol"
},
{
"family": "Gómez-Estéban",
"given": "Juan Carlos"
},
{
"family": "Erramuzpe",
"given": "Asier"
},
{
"family": "Ruiz-Lopez",
"given": "Marta"
}
],
"container-title-short": "Clin Neurophysiol Pract",
"volume": "11",
"page": "766-773",
"DOI": "10.1016/j.cnp.2026.08.008",
"PMID": "42733699",
"PMCID": "PMC13571461",
"ISSN": "2467-981X",
"publisher": "Elsevier",
"URL": "https://doi.org/10.1016/j.cnp.2026.08.008",
"language": "en",
"issued": {
"date-parts": [
[
2026,
8,
27
]
]
}
}

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/s41531-026-01380-1 [code]
Identifying maximal beta power from directional subthalamic local field potentials in Parkinson's disease.
Journal: NPJ Parkinson's disease
In common: statsmodels, seaborn, pandas, 3 other tools, extracellular electrophysiology (units, LFP), clinical / translational, 6 references
[2] doi:10.1038/s41531-026-01531-4 [code]
Inconsistent subthalamic local field potential beta activity amid in- and antiphasic neuronal bursts.
Journal: NPJ Parkinson's disease
In common: pandas, SciPy, Matplotlib, 1 other tool, extracellular electrophysiology (units, LFP), clinical / translational, 4 references
[3] doi:10.1002/ana.78206 [code]
Multimodal Image Guidance in Subthalamic Deep Brain Stimulation for Parkinson's Disease.
Journal: Annals of neurology
In common: seaborn, pandas, SciPy, 2 other tools, clinical / translational, 3 references
[4] doi:10.1038/s41531-026-01354-3 [code]
Neuromodulation-induced normalization of cortical metastable dynamics signatures in Parkinson's disease.
Journal: NPJ Parkinson's disease
In common: statsmodels, seaborn, pandas, 3 other tools, 2 references
[5] doi:10.1038/s41467-026-75837-5 [code]
A hierarchical framework for cortical and subcortical gray-matter parcellation across rodents, primates, and humans.
Journal: Nature communications
In common: statsmodels, seaborn, pandas, 3 other tools, 2 references
[6] doi:10.1038/s41591-026-04432-4 [code]
Activity-dependent adaptive deep brain stimulation improves gait in Parkinson's disease.
Journal: Nature medicine
In common: SciPy, Matplotlib, NumPy, clinical / translational, 3 references
[7] doi:10.1162/imag.a.1264 [code]
Data-driven subtyping and staging of ALS: A multicenter, longitudinal, deformation-based morphometry study.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: statsmodels, seaborn, pandas, 3 other tools, clinical / translational, 1 reference
[8] doi:10.1038/s41591-026-04434-2 [code]
Adaptive deep brain stimulation for dynamic gait control in Parkinson's disease: a randomized feasibility trial.
Journal: Nature medicine
In common: pandas, SciPy, Matplotlib, 1 other tool, clinical / translational, 2 references
[9] doi:10.1162/imag.a.1262 [code]
Frame-wise multi-echo distortion correction for superior functional MRI.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: seaborn, pandas, SciPy, 2 other tools, 2 references
[10] doi:10.1162/imag.a.1362 [code]
Human fMRI at 11.7T: Assessing feasibility, stability, and reliability on the Iseult scanner.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: statsmodels, seaborn, pandas, 3 other tools, 1 reference

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.

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: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.

Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.

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