change_effects_summary.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. from cProfile import label
  2. import numpy as np
  3. import pandas as pd
  4. from scipy.stats import entropy
  5. from sklearn.linear_model import LinearRegression
  6. from matplotlib import pyplot as plt
  7. import matplotlib
  8. matplotlib.use("pgf")
  9. matplotlib.rcParams.update(
  10. {
  11. "pgf.texsystem": "xelatex",
  12. "font.family": "serif",
  13. "font.serif": "Times New Roman",
  14. "text.usetex": True,
  15. "pgf.rcfonts": False,
  16. }
  17. )
  18. plt.rcParams["text.latex.preamble"].join([
  19. r"\usepackage{amsmath}",
  20. r"\setmainfont{amssymb}",
  21. ])
  22. import argparse
  23. from os.path import join as opj, exists
  24. import pickle
  25. parser = argparse.ArgumentParser()
  26. parser.add_argument("--input")
  27. args = parser.parse_args()
  28. topics = pd.read_csv(opj(args.input, "topics.csv"))
  29. junk = topics["label"].str.contains("Junk")
  30. topics = topics[~junk]["label"].tolist()
  31. n_topics = len(topics)
  32. labels = [
  33. "Intellectual capital (diversity)",
  34. "Social capital (diversity)",
  35. "Social capital (power)",
  36. "Stable affiliation",
  37. "Academic age"
  38. ]
  39. labels = [f"\\textbf{{{label}}}" for label in labels]
  40. labels += topics
  41. n_vars = len(labels)
  42. label_position = {label: i for i, label in enumerate(labels)}
  43. names = [
  44. "beta_int_div", "beta_soc_div", "beta_soc_cap", "beta_stable", "beta_age"
  45. ]
  46. nice_names = {
  47. "change": "Change score ($c_a$)",
  48. "disruption": "Disruption score ($d_a$)",
  49. "entered": "Entered a new research area",
  50. "exited": "Exited a research area"
  51. }
  52. def get_effects(metric, diversity, power):
  53. filename = opj(args.input, f"samples_{metric}_{diversity}_{power}.npz")
  54. if not exists(filename):
  55. print(f"samples not found: {filename}")
  56. return pd.DataFrame([])
  57. samples = np.load(filename)
  58. mu = np.array([samples[name].mean() for name in names] + [(samples["beta_x"][:,i]*samples["tau"]).mean() for i in range(n_topics)])
  59. low = np.array([np.quantile(samples[name], q=0.05/2) for name in names] + [np.quantile(samples["beta_x"][:,i]*samples["tau"], q=0.05/2) for i in range(n_topics)])
  60. up = np.array([np.quantile(samples[name], q=1-0.05/2) for name in names] + [np.quantile(samples["beta_x"][:,i]*samples["tau"], q=1-0.05/2) for i in range(n_topics)])
  61. sig = up*low>0
  62. sign = mu>0
  63. prob = np.array([(samples[name]*np.sign(samples[name].mean())<0).mean() for name in names] + [((samples["beta_x"][:,i]*np.sign(samples["beta_x"][:,i].mean()))<0).mean() for i in range(n_topics)])
  64. vars = []
  65. model = None
  66. if diversity == "entropy":
  67. model = "Reference" if power=="magnitude" else "$P=\\text{Brokerage}$"
  68. else:
  69. model = "$D=\\text{Stirling}$"
  70. for i in range(n_vars):
  71. plus = up[i]-mu[i]
  72. minus = mu[i]-low[i]
  73. sign_char = "+" if sign[i] else ""
  74. s = (f"{mu[i]:.2g}").replace("-", "")
  75. if len(s)<5 and "e" not in s:
  76. if sig[i]:
  77. string = f"$\\bm{{{sign_char}{mu[i]:.2g}}}\\substack{{+{plus:.2g} \\\\ -{minus:.2g}}}$"
  78. else:
  79. string = f"${sign_char}{mu[i]:.2g}\\substack{{+{plus:.2g} \\\\ -{minus:.2g}}}$"
  80. else:
  81. if sig[i]:
  82. string = f"$\\bm{{{sign_char}{mu[i]:.1g}}}\\substack{{+{plus:.1g} \\\\ -{minus:.1g}}}$"
  83. else:
  84. string = f"${sign_char}{mu[i]:.1g}\\substack{{+{plus:.1g} \\\\ -{minus:.1g}}}$"
  85. vars.append({
  86. "Dep. variable": nice_names[metric],
  87. "Model": model,
  88. "mu": mu[i],
  89. "low": low[i],
  90. "up": up[i],
  91. "sig": sig[i]>0,
  92. "Predictor": labels[i],
  93. "string": string,
  94. })
  95. print(metric, model)
  96. return pd.DataFrame(vars)
  97. vars = []
  98. metrics = ["change", "disruption"]
  99. for metric in metrics:
  100. vars.append(get_effects(metric, "entropy", "magnitude"))
  101. vars.append(get_effects(metric, "stirling", "magnitude"))
  102. vars.append(get_effects(metric, "entropy", "brokerage"))
  103. vars = pd.concat(vars)
  104. print(vars)
  105. vars = vars.pivot(columns=["Dep. variable", "Model"], index="Predictor", values="string")
  106. vars.sort_index(key=lambda x: x.map(label_position), inplace=True)
  107. latex = vars.to_latex(
  108. escape=False,
  109. multicolumn_format="c",
  110. caption="Effect of each variable on (a) the change score and (b) the disruption score for each model. The reference model uses entropy as the diversity measure $D$ and the magnitude of intellectual capital as a measure of power $P$. Values indicate the mean posterior effect size and the 95\\% credible interval. Significant effects are shown in bold.",
  111. label="table:summary_change_disruption",
  112. position="H"
  113. )
  114. latex = latex.replace("\\\nHadrons", "\\\n\\hline Hadrons")
  115. latex = latex.replace("\\begin{tabular}", "\\renewcommand{\\arraystretch}{2}\\fontsize{6}{7}\\selectfont\\begin{tabular}")
  116. latex = latex.replace("\\end{tabular}", "\\end{tabular}\\normalsize\\renewcommand{\\arraystretch}{1}")
  117. with open(opj(args.input, f"summary_change_disruption.tex"), "w+") as fp:
  118. fp.write(latex)
  119. vars = []
  120. metrics = ["entered", "exited"]
  121. for metric in metrics:
  122. vars.append(get_effects(metric, "entropy", "magnitude"))
  123. vars.append(get_effects(metric, "stirling", "magnitude"))
  124. vars.append(get_effects(metric, "entropy", "brokerage"))
  125. vars = pd.concat(vars)
  126. print(vars)
  127. vars = vars.pivot(columns=["Dep. variable", "Model"], index="Predictor", values="string")
  128. vars.sort_index(key=lambda x: x.map(label_position), inplace=True)
  129. latex = vars.to_latex(
  130. escape=False,
  131. multicolumn_format="c",
  132. caption="Effect of each variable on (a) the probability of having entered a new research area and (b) the probability of having exited a research area, for each model. The reference model uses entropy as the diversity measure $D$ and the magnitude of intellectual capital as a measure of power $P$. Values indicate the mean posterior effect size and the 95\\% credible interval. Significant effects are shown in bold.",
  133. label="table:summary_entered_exited",
  134. position="H"
  135. )
  136. latex = latex.replace("\\\nHadrons", "\\\n\\hline Hadrons")
  137. latex = latex.replace("\\begin{tabular}", "\\renewcommand{\\arraystretch}{2}\\fontsize{6}{7}\\selectfont\\begin{tabular}")
  138. latex = latex.replace("\\end{tabular}", "\\end{tabular}\\normalsize\\renewcommand{\\arraystretch}{1}")
  139. with open(opj(args.input, f"summary_entered_exited.tex"), "w+") as fp:
  140. fp.write(latex)