clep_scaling.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import matplotlib.pyplot as plt
  2. import numpy as np
  3. import pandas as pd
  4. import xlsxwriter
  5. cuts_all = {
  6. 'Spanish': {'2026': {'C': [49, 50], 'B': [73, 63], 'T': [99, 80], 'L': [0, 20], 'U': [100, 80]}},
  7. 'French': {'2010': {'C': [40, 50], 'B': [68, 59], 'T': [99, 80], 'L': [0, 20], 'U': [100, 80]}},
  8. 'German': {'2010': {'C': [34, 50], 'B': [56, 60], 'T': [86, 80], 'L': [0, 20], 'U': [87, 80]}}
  9. }
  10. col_dict = {
  11. 'raw': 'Raw Score',
  12. 'ss_lin':'SS Linear',
  13. 'ss_elb':'SS Segments',
  14. 'ss_lin_ur':'SS Linear (unrounded)',
  15. 'ss_elb_ur':'SS Segments (unrounded)',
  16. }
  17. def ab(top, bot, cuts):
  18. _a = (cuts[top][1] - cuts[bot][1]) / (cuts[top][0] - cuts[bot][0])
  19. _b = cuts[top][1] - _a * cuts[top][0]
  20. return _a, _b
  21. def round_clip(a, low, high):
  22. return np.clip(np.round(a, 0), low, high)
  23. def conversion(cuts):
  24. a, b = ab('T', 'C', cuts)
  25. a1, b1 = ab('B', 'C', cuts)
  26. a2, b2 = ab('T', 'B', cuts)
  27. raw = np.arange(cuts['L'][0], cuts['U'][0]+1)
  28. raw1 = np.arange(cuts['L'][0], cuts['B'][0])
  29. raw2 = np.arange(cuts['B'][0], cuts['U'][0]+1)
  30. ss_lin_ur = raw * a + b
  31. ss_elb_ur = np.append(raw1 * a1 + b1, raw2 * a2 + b2)
  32. data = pd.DataFrame({
  33. 'raw': raw,
  34. 'ss_lin': round_clip(ss_lin_ur, cuts['L'][1], cuts['U'][1]),
  35. 'ss_elb': round_clip(ss_elb_ur, cuts['L'][1], cuts['U'][1]),
  36. 'ss_lin_ur': ss_lin_ur,
  37. 'ss_elb_ur': ss_elb_ur
  38. })
  39. data = data.sort_values(by="raw", ascending=False)
  40. return data
  41. def plot(data, subject, year, cuts):
  42. fig, ax = plt.subplots()
  43. ax.plot(data.raw, data.ss_lin_ur, label='Linear')
  44. ax.plot(data.raw, data.ss_elb_ur, color='magenta', label='Segments')
  45. ax.plot([cuts['L'][0], cuts['U'][0]], [cuts['C'][1], cuts['C'][1]], color='green', linewidth=0.5)
  46. ax.plot([cuts['L'][0], cuts['U'][0]], [cuts['B'][1], cuts['B'][1]], color='orange', linewidth=0.5)
  47. ax.set_xlabel('Raw Score')
  48. ax.set_ylabel('Scale Score')
  49. ax.set_title(f'Conversions: CLEP {subject} ({year})')
  50. ax.legend()
  51. plt.tight_layout()
  52. plt.savefig(f'output/CLEP_{subject}_conversion_{year}.pdf')
  53. def save_excel(data, subject, year, cuts):
  54. workbook = xlsxwriter.Workbook(f'output/CLEP_{subject}_conversion_{year}.xlsx')
  55. worksheet = workbook.add_worksheet('conversion')
  56. bold = workbook.add_format({'bold': True})
  57. cut_red0 = workbook.add_format({'bold': True, 'font_color': 'red'})
  58. cut_red2 = workbook.add_format({'bold': True, 'font_color': 'red', 'num_format': '#.00'})
  59. dec0 = workbook.add_format({'num_format': '#0'})
  60. dec2 = workbook.add_format({'num_format': '#.0'})
  61. i, j = 0, 0
  62. for col in data.columns:
  63. for row in data[col]:
  64. fmt = dec0
  65. val = data[col].iloc[j]
  66. raw = data.raw.iloc[j]
  67. if j == 0: # column header
  68. worksheet.write(j, i, col_dict[col], bold)
  69. if (raw == cuts['C'][0] or raw == cuts['B'][0]):
  70. if i<3:
  71. fmt = cut_red0
  72. else:
  73. fmt = cut_red2
  74. else:
  75. if i>2:
  76. fmt = dec2
  77. worksheet.write(j+1, i, val, fmt)
  78. j += 1
  79. i += 1
  80. j = 0
  81. workbook.close()
  82. def main(subject, year):
  83. cuts = cuts_all[subject][year]
  84. data = conversion(cuts)
  85. plot(data, subject, year, cuts)
  86. save_excel(data, subject, year, cuts)
  87. if __name__ == "__main__":
  88. main('Spanish', '2026')