Skip to content

Grading Updates #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Apr 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion _toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ parts:
- file: syllabus/tools
- file: syllabus/grading
- file: syllabus/badges
- file: syllabus/badge_calc.md
- file: syllabus/badge_calc
- file: syllabus/schedule
- file: syllabus/uri_resources
- file: syllabus/uri_statements
Expand Down
225 changes: 225 additions & 0 deletions syllabus/badge_calc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
---
jupytext:
formats: ipynb,md:myst
text_representation:
extension: .md
format_name: myst
format_version: 0.13
jupytext_version: 1.14.1
kernelspec:
display_name: Python 3
language: python
name: python3
---

# 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.
```

```{code-cell} ipython3
:tags: ["hide-input"]
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 ':24*weights_mrw['experience'], 'C ':24*weights_mrw['experience']+18*weights_mrw['review'],
'B ':24*weights_mrw['experience']+18*weights_mrw['practice'],
'A ': 24*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']
```

The total influence of each badge is as follows:

```{code-cell} ipython3
:tags: ["hide-input"]
# display
influence_df[['badge_type','badge','complexity','weight','influence']]
```

```{code-cell} ipython3
:tags: ["hide-input"]

# 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,)
```

```{code-cell} ipython3
:tags: ["hide-input"]
# 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
```

```{code-cell} ipython3
# 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. What follows is close to equivalent, but changes some thresholds. This is a *proposed* alternative, that I will adopt
if it is more clear and students agree it is fair.
```

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)
24 changes: 8 additions & 16 deletions syllabus/badges.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,19 @@ weeks = int((last_day-first_day).days/7+1)
# create differences
mtg_delta = timedelta(meeting_days[1]-meeting_days[0])
week_delta = timedelta(7)
skips = [date(2023,2,28)]
weeks = int((last_day-first_day).days/7+1)

meeting_days =[1,3]
mtg_delta = timedelta(meeting_days[1]-meeting_days[0])
week_delta = timedelta(7)

# function to check if a date is during spring break
during_sb = lambda d: spring_break[0]<d<spring_break[1]

# generate the number of weeks worth of dates

possible = [(first_day+week_delta*w, first_day+mtg_delta+week_delta*w) for w in range(weeks)]
# rm spring break dates
weekly_meetings = [[c1,c2] for c1,c2 in possible if not(during_sb(c1))]
#unpack into single list
meetings = [m for w in weekly_meetings for m in w]
meetings = [m for w in weekly_meetings for m in w if not(m in skips)]


# build a table for the dates
Expand Down Expand Up @@ -450,14 +453,3 @@ style revision fill:#2cf
style earned fill:#2cf

```











34 changes: 21 additions & 13 deletions syllabus/grading.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,32 +132,32 @@ This is important information and it is also new in spring 2023. I would like a
````

To earn a D you must complete:
- 24 experience badges
- 23 experience badges

To earn a C you must complete:
- 24 experience badges
- 23 experience badges
- 18 review badges


To earn a B you must complete:
- 24 experience badges
- 23 experience badges
- your choice:
- 18 practice badges
- 12 review + 12 practice

For an A you must complete:
- 24 experience badges
- 23 experience badges
- your choice:
- 18 practice badges + 9 explore badges
- 18 practice badges + 6 explore badges
- 18 review badges + 3 build badges
- 6 review badges + 12 practice badges + 6 explore badges + 1 build badges
- 12 review badges + 6 practice badges+ 3 explore badges + 2 build badges
- 6 review badges + 12 practice badges + 4 explore badges + 1 build badges
- 12 review badges + 6 practice badges+ 2 explore badges + 2 build badges


You can also mix and match to get +/-. For example
(all examples assume 24 experience badges)
- A-: 18 practice + 6 explore
- A-: 6 review + 12 practice + 9 explore
(all examples assume 23 experience badges)
- A-: 18 practice + 4 explore
- B+: 6 review + 12 practice + 4 explore
- B-: 6 review + 12 practice
- B+: 24 practice
- C+: 12 review + 6 practice
Expand Down Expand Up @@ -294,10 +294,10 @@ Community badges can replace missed experience, review, and practice badges, upg

Community Badge values:
- 3 community = 1 experience badge
- 5 community = 1 review
- 4 community = 1 review
- 7 community = 1 practice.
- 5 community badges + 1 review = 1 practice.
- 10 community = + step to a D,C, or B, **note that this is more efficient.**
- 3 community badges + 1 review = 1 practice.
- 10 community = add a `+` to a D,C, or B, **note that this is more efficient.**


You can earn community badges by:
Expand Down Expand Up @@ -423,3 +423,11 @@ You may earn at most one build badge per month, with final grading in May. To ea
```{important}
this includes minor corrections relative to the readme in the template provided
``` -->

## Academic Honesty Violation Penalty

If you are found to submit prismia responses that do not reflect your own thinking or that of discussion with peers as directed, the experience badge for that class session will be ineligible.

If you are found to submit work that is not your own for a review or prepare badge, the review and prepare badges for that date will be ineligible and the penalty free zone terms will no longer apply to the first six badges.

If you are found to submit work that is not your own for an explore or build badge, that badge will not be awarded and your maximum badges at the level possible will drop to 2/3 of the maximum possible.