Badge Calculations#

Important

This page is generated with code and calculations, you can view them for more precise implementations of what the english sentences mean.

Hide code cell source
import os
from datetime import date,timedelta
import calendar
import pandas as pd
import numpy as np
import seaborn as sns

from myst_nb import glue
import plotly.express as px
# learning complexities
weights_mrw = {'experience' :2,'review': 3,'practice': 6,'explore': 9,'build' :36}
# base grade influence cutoffs
thresh_mrw = {'D ':23*weights_mrw['experience'], 'C ':23*weights_mrw['experience']+18*weights_mrw['review'],
          'B ':23*weights_mrw['experience']+18*weights_mrw['practice'],
          'A ': 23*weights_mrw['experience']+18*weights_mrw['practice'] + 6*weights_mrw['explore']}

examples_mrw = [[24,0,0,0,0],[24,18,0,0,0],[24,24,0,0,0],[24,18,6,0,0],
                [24,18,0,0,1],[24,0,18,0,0],[24,12,12,0,0],[24,0,24,0,0],
                [24,0,18,6,0],[24,0,18,4,0],[24,0,18,0,1],
                [24,18,0,0,3],[24,6,12,4,1],[24,12,6,2,2],[24,0,24,2,0]]

ex_df_mrw = pd.DataFrame(data=examples_mrw,columns = weights_mrw.keys())
w_df_mrw = pd.DataFrame(data=[(ex_df_mrw[col]*weights_mrw[col]) for col in weights_mrw]).T.rename(columns=lambda col:col + '_weight')
w_df_mrw['total'] = w_df_mrw.sum(axis=1)
# [ex_df[col]*weights[col] for col in weights]
# columns = [col + '_weight' for col in weights ]
badge_thresh_df_mrw = pd.concat([ex_df_mrw,w_df_mrw],axis=1).reset_index()


delta = thresh_mrw['C ']-thresh_mrw['D ']
minus_thresh = {k.strip()+'-':int(v-delta/3) for k,v in thresh_mrw.items()}
minus_thresh

plus_thresh = {k.strip()+'+':int(v+delta/3) for k,v in thresh_mrw.items()}

# calculate the final thresholds for all leter grades
thresh_mrw.update(minus_thresh)
thresh_mrw.update(plus_thresh)
thresh_mrw.pop('A+');

ind_badges_mrw = [[exid,bt,bw,bc,1] for i,ex in enumerate(examples_mrw) for bc,(bt,bw) in zip(ex,weights_mrw.items()) 
                                      for exid in bc*[i]]
per_badge_df_mrw = pd.DataFrame(ind_badges_mrw,columns=['example','badge','complexity','count','weight'])

# weight community badges, 
community_weights = {'plus': 3*weights_mrw['practice']/10,'experience_makeup':weights_mrw['experience']/3,
                    'review_makeup':weights_mrw['review']/4,
                     'review_upgrade': (weights_mrw['practice']-weights_mrw['review'])/3,
                    'practice_makeup':weights_mrw['practice']/7}

learning_df = pd.Series(weights_mrw,name ='complexity').reset_index()
learning_df['badge_type'] = 'learning'
comm_df  = pd.Series(community_weights,name='weight').reset_index()
comm_df['badge_type'] = 'community'
# nans are for learning badges which all ahve weight 1
influence_df = pd.concat([learning_df,comm_df]).fillna(1).rename(columns={'index':'badge'})
# final df
influence_df['influence'] = influence_df['complexity']*influence_df['weight']

Grade cutorrs are:

Hide code cell source
th_list = [[k,v] for k,v in thresh_mrw.items()]
pd.DataFrame(th_list, columns = ['letter','threshold']).sort_values(by='threshold').set_index('letter')
threshold
letter
D- 28
D 46
D+ 64
C- 82
C 100
C+ 118
B- 136
B 154
B+ 172
A- 190
A 208

The total influence of each badge is as follows:

Hide code cell source
# display
influence_df[['badge_type','badge','complexity','weight','influence']]
badge_type badge complexity weight influence
0 learning experience 2.0 1.000000 2.000000
1 learning review 3.0 1.000000 3.000000
2 learning practice 6.0 1.000000 6.000000
3 learning explore 9.0 1.000000 9.000000
4 learning build 36.0 1.000000 36.000000
0 community plus 1.0 1.800000 1.800000
1 community experience_makeup 1.0 0.666667 0.666667
2 community review_makeup 1.0 0.750000 0.750000
3 community review_upgrade 1.0 1.000000 1.000000
4 community practice_makeup 1.0 0.857143 0.857143
Hide code cell source
# example calculation helper functions
def commumunity_example(badges,exid,cw_type):
    case_weights = weights_mrw.copy()
    case_weights['community'] = community_weights[cw_type]
    return [[exid,bt,bw,bc] for bc,(bt,bw) in zip(badges,case_weights.items()) 
                                      for i in range(bc)]

def commumunity_example(badges,exid,cw_type):
    case_weights = weights_mrw.copy()
    if type(cw_type)==list:
        for cw in cw_type:
            case_weights['community_'+cw] = community_weights[cw]
    else:
        case_weights['community'] = community_weights[cw_type]
#     print(badge)
    return [[exid,bt,bt.split('_')[0],bw,bc] for bc,(bt,bw) in zip(badges,case_weights.items()) 
                                      for i in range(bc)]
# 


def get_row(exid,badge_detail,badge_category,badge_mult,badge_count):
    if 'community' in badge_detail:
        badge_complexity = 1
        badge_weight = badge_mult
    else: 
        badge_complexity = badge_mult
        badge_weight = 1
    
    badge_row = [exid,badge_detail,badge_category,
                 badge_complexity, badge_weight,badge_count]
    return badge_row

def commumunity_example_comp_w(badges,exid,cw_type):
    case_weights = weights_mrw.copy()
    if type(cw_type)==list:
        for cw in cw_type:
            case_weights['community_'+cw] = community_weights[cw]
    else:
        case_weights['community'] = community_weights[cw_type]
#     print(badge)
    return [get_row(exid,bt,bt.split('_')[0],bw,bc) for bc,(bt,bw) in zip(badges,case_weights.items()) 
                                      for i in range(bc)]
# make more examples
ind_badges_mrw_c = [get_row(str(exid),bt,bt,bw,bc) for i,ex in enumerate(examples_mrw) for bc,(bt,bw) in zip(ex,weights_mrw.items()) 
                                      for exid in bc*[i]]

examples_mrw_cplus = [[24,0,0,0,0,10],[24,18,0,0,0,10],[24,0,18,0,0,10],[24,12,12,0,0,10],
                     [24,0,18,0,1,10],[24,12,12,2,0,10]]
ind_badges_mrw_c +=[r for i,ex in enumerate(examples_mrw_cplus) 
                    for r in commumunity_example_comp_w(ex,str(i)+'cp',['plus'])]
examples_mrw_em = [[22,0,0,0,0,6],[21,18,0,0,0,9],[23,0,18,0,0,13],[20,12,12,0,0,12],[20,12,12,0,0,12]]
ind_badges_mrw_c +=[r for i,ex in enumerate(examples_mrw_em) 
                    for r in commumunity_example_comp_w(ex,str(i)+'cem',['experience_makeup'])]
examples_mrw_rm = [[22,17,0,0,0,6,4],[24,10,12,0,0,0,8]]
ind_badges_mrw_c +=[r for i,ex in enumerate(examples_mrw_rm) for r in 
                    commumunity_example_comp_w(ex,str(i)+'cemrm',['experience_makeup','review_makeup'])]
examples_mrw_ru = [[24,0,16,0,0,0,0,14],[23,1,16,0,0,3,3,7]]
ind_badges_mrw_c +=[r for i,ex in enumerate(examples_mrw_ru) for r in 
                    commumunity_example_comp_w(ex,str(i)+'cemrupm',['experience_makeup','review_upgrade','practice_makeup'])]
# ind_badges_mrw_c

per_badge_df_mrw_c = pd.DataFrame(ind_badges_mrw_c,columns=['example','badge_det','badge',
                                                            'complexity','weight','count'])
per_badge_df_mrw_c['influence'] = per_badge_df_mrw_c['complexity']*per_badge_df_mrw_c['weight']

# get example letter grades
grade_calc = lambda df: (np.floor((df.sum()-48)/(delta/3))*(delta/3)+48).astype(int)
ex_grade = per_badge_df_mrw_c.groupby(['example'])['influence'].apply(grade_calc).reset_index().rename(
                    columns = {'influence':'influence_total'})

thresh_mrw_rv = {v:k for k, v in thresh_mrw.items()}
ex_grade['letter'] = ex_grade['influence_total'].apply(lambda v: thresh_mrw_rv[v])

# ex_grade = ((per_badge_df_mrw_c.groupby(['example'])['influence'].sum()-48).floordiv((delta/3))*(delta/3)+48).astype(int).reset_index()


per_badge_df_mrw_cletter = pd.merge(per_badge_df_mrw_c,ex_grade[['example','letter','influence_total']],on='example')

# sort to improve visual display
badges_in_order = ['experience','community_experience_makeup', 'review',
                   'community_review_makeup','community_review_upgrade',
                  'practice','community_practice_makeup', 'explore', 'build','community_plus']
badge_order_num ={b:i for i,b in enumerate(badges_in_order)}
per_badge_df_mrw_cletter['badge_num'] = per_badge_df_mrw_cletter['badge_det'].apply(lambda bd:badge_order_num[bd])

# per_badge_df_mrw_c= per_badge_df_mrw_c.sort_values(by='example')
per_badge_df_mrw_cletter = per_badge_df_mrw_cletter.sort_values(by=['badge_num','influence_total'],ascending=True,)
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[4], line 72
     68 ex_grade = per_badge_df_mrw_c.groupby(['example'])['influence'].apply(grade_calc).reset_index().rename(
     69                     columns = {'influence':'influence_total'})
     71 thresh_mrw_rv = {v:k for k, v in thresh_mrw.items()}
---> 72 ex_grade['letter'] = ex_grade['influence_total'].apply(lambda v: thresh_mrw_rv[v])
     74 # ex_grade = ((per_badge_df_mrw_c.groupby(['example'])['influence'].sum()-48).floordiv((delta/3))*(delta/3)+48).astype(int).reset_index()
     77 per_badge_df_mrw_cletter = pd.merge(per_badge_df_mrw_c,ex_grade[['example','letter','influence_total']],on='example')

File /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages/pandas/core/series.py:4630, in Series.apply(self, func, convert_dtype, args, **kwargs)
   4520 def apply(
   4521     self,
   4522     func: AggFuncType,
   (...)
   4525     **kwargs,
   4526 ) -> DataFrame | Series:
   4527     """
   4528     Invoke function on values of Series.
   4529 
   (...)
   4628     dtype: float64
   4629     """
-> 4630     return SeriesApply(self, func, convert_dtype, args, kwargs).apply()

File /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages/pandas/core/apply.py:1025, in SeriesApply.apply(self)
   1022     return self.apply_str()
   1024 # self.f is Callable
-> 1025 return self.apply_standard()

File /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages/pandas/core/apply.py:1076, in SeriesApply.apply_standard(self)
   1074     else:
   1075         values = obj.astype(object)._values
-> 1076         mapped = lib.map_infer(
   1077             values,
   1078             f,
   1079             convert=self.convert_dtype,
   1080         )
   1082 if len(mapped) and isinstance(mapped[0], ABCSeries):
   1083     # GH#43986 Need to do list(mapped) in order to get treated as nested
   1084     #  See also GH#25959 regarding EA support
   1085     return obj._constructor_expanddim(list(mapped), index=obj.index)

File /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages/pandas/_libs/lib.pyx:2834, in pandas._libs.lib.map_infer()

Cell In[4], line 72, in <lambda>(v)
     68 ex_grade = per_badge_df_mrw_c.groupby(['example'])['influence'].apply(grade_calc).reset_index().rename(
     69                     columns = {'influence':'influence_total'})
     71 thresh_mrw_rv = {v:k for k, v in thresh_mrw.items()}
---> 72 ex_grade['letter'] = ex_grade['influence_total'].apply(lambda v: thresh_mrw_rv[v])
     74 # ex_grade = ((per_badge_df_mrw_c.groupby(['example'])['influence'].sum()-48).floordiv((delta/3))*(delta/3)+48).astype(int).reset_index()
     77 per_badge_df_mrw_cletter = pd.merge(per_badge_df_mrw_c,ex_grade[['example','letter','influence_total']],on='example')

KeyError: 48
Hide code cell source
# make plot
fig_cur = px.bar(per_badge_df_mrw_cletter,x='example',y='influence',color='badge_det',
                 hover_data=['badge','count','letter'],height=700)
fig_cur.update_layout(yaxis = dict(tickmode='array',
                              tickvals = list(thresh_mrw.values()),
                              ticktext =list(thresh_mrw.keys()),
                                  title='grade'))
# fig.update_layout( xaxis={'categoryorder':'array','categoryarray':per_badge_df_mrw_cletter['influence_total'].unique()})
fig_cur
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[5], line 2
      1 # make plot
----> 2 fig_cur = px.bar(per_badge_df_mrw_cletter,x='example',y='influence',color='badge_det',
      3                  hover_data=['badge','count','letter'],height=700)
      4 fig_cur.update_layout(yaxis = dict(tickmode='array',
      5                               tickvals = list(thresh_mrw.values()),
      6                               ticktext =list(thresh_mrw.keys()),
      7                                   title='grade'))
      8 # fig.update_layout( xaxis={'categoryorder':'array','categoryarray':per_badge_df_mrw_cletter['influence_total'].unique()})

NameError: name 'per_badge_df_mrw_cletter' is not defined

Important

the labels on the horizontal axis are just example names, they do not have any meaning, I just have not figured out what I want to replace them with that might have meaning and need some sort of unique identifier there for the plot to work.

# fig_cur.to_html('influence.html',include_plotlyjs='cdn',
#                full_html=False,div_id='badge_grade_graph')

Warning

Officially what is on the Grading page is what applies if this page is in conflict with that.

The total influence of a badge on your grade is the product of the badge’s weight and its complexity. All learning badges have a weight of 1, but have varying complexity. All community badges have a complexity of 1, but the weight of a community badge can vary depending on what learning badges you earn.

There are also some hard thresholds on learning badges. You must have:

  • 24 experience badges to earn a D or above

  • at least 18 additional total across reivew and practice to earn above C or above

Only community badges can make exceptions to these thresholds. So if you are missing learning badges required to get to a threshold, your community badges will fill in for those. If you meet all of the thresholds, the community badges will be applied with more weight to give you a step up (eg C to C+ or B+ to A-).

Community badges have the most weight if you are on track for a grade between D and B+

If you are on track for an A, community badges can be used to fill in for learning badges, so for example, at the end of the semester, you might be able to skip some the low complexity learning badges (experience, review, practice) and focus on your high complexity ones to ensure you get an A.

More precisely the order of application for community badges:

  • to make up missing experience badges

  • to make up for missing review or practice badge to reach a total of 18 between these two types

  • to upgrade review to practice to meet a threshold

  • to give a step up (highest weight)