<jupyter_start><jupyter_text>Parameter Estimation using ASSISTments Skill Builder Dataset<jupyter_code>import pandas as pd
import json

import autograd.numpy as np
import autograd.scipy as ascipy
from autograd import value_and_grad
from autograd import grad
from scipy.optimize import minimize

pd.options.display.max_columns = 100
pd.options.display.max_rows = 1000
# ASSISTment Data
df = pd.DataFrame()
data = pd.read_csv('../skill_builder_data.csv')
# prerequistes
f = open('prereq.json')
prereqs = json.load(f)

# getting student 78178
per_student = data.loc[data['user_id'] == 78178]
per_student = per_student[pd.notnull(per_student['skill_name'])]
per_student_frame = per_student.sort_values(by=['order_id'])
# per_student_frame = per_student_frame[(per_student_frame['skill_name'] == 'Addition and Subtraction Fractions') 
#                                       | (per_student_frame['skill_name'] == 'Order of Operations All')]
per_student_frame = per_student_frame.sort_values(by=['order_id'])

n_skills = len(per_student_frame['skill_name'].unique())
def initialize(n):
    # initialize weight vector
    weight_vector = np.random.rand(n+1)

    # alpha (probability) vector
    alpha_vector = np.zeros(n+1)
    
    # initialize takeaway dictionary
    f_s = {}
    counter_f_s = {}
    counter = 0
    for each in per_student_frame['skill_name'].unique():
        f_s[each] = 0.0
        counter_f_s[each] = counter
        counter += 1
    return alpha_vector, f_s, counter_f_s
'''
Sigmoid function
1/(1+e^{-w'x})
'''
def sigmoid_function(weight, x):
    return 1/(1 + np.exp(-np.dot(weight, x)))

'''
Update Rule for Takeaway Fraction
F_s(T_i, n) = F_s(T_i, n-1) + (1-F_s[T_i, n-1])*alpha(T_i, n)
'''
def update_f_s(f_s, skill_name, alpha):
    f_s[skill_name] = f_s[skill_name] + (1-f_s[skill_name])*alpha
    return f_s
def construct_feature_vector(n, f_s, counter_f_s, skill_name, prereqs):
    # initilalize feature vector
    feature_vector = np.zeros(n+1)
    feature_vector[n] = 1
    
    # add F_s(skill_name)
    feature_vector[counter_f_s[skill_name]] = f_s[skill_name]
    
    # add F_s for all prereqs
    for each_skill in prereqs[skill_name]:
        if(each_skill in f_s):
            feature_vector[counter_f_s[each_skill]] = f_s[each_skill]
    return feature_vector
'''
Student Updates.
'''
def update_student(weight_vector, alpha_vector, f_s, counter_f_s):
    step = 1
    for index, row in per_student_frame.iterrows():
        skill_name = row['skill_name']
        if(skill_name not in f_s): continue
        skill_index = counter_f_s[skill_name]

        feature_vector = construct_feature_vector(n_skills, f_s, counter_f_s, skill_name, prereqs)
        alpha_vector[skill_index] = sigmoid_function(weight_vector, feature_vector)
        
        f_s = update_f_s(f_s, skill_name, alpha_vector[skill_index])

#         feature_vector[skill_index] = f_s[skill_name]
        step += 1
    return f_s

'''
Log Likelihood.
'''
def log_likelihood(weight_vector, sign=1.0):
    alpha_vector, f_s, counter_f_s = initialize(n_skills)
    all_f_s = update_student(weight_vector, alpha_vector, f_s, counter_f_s)
    s = 1
    for each in all_f_s.values():
        s = s + each
    return np.log(s)

def all_students_likelihood(weight_vector, sign=1.0):
    ids = data['user_id'].unique()
    
w0 = np.zeros(n_skills+1)

# alphas = log_likelihood(w0, alpha_vector, f_s, counter_f_s, alphas)
opt = minimize(log_likelihood, w0, method='CG', options={'disp':True})
opt.x
feature_vector = np.zeros(n_skills+1)
feature_vector[n_skills] = 1.
w = opt.x
alpha_vector, f_s, counter_f_s = initialize(n_skills)
a = opt.x
a
for k,v in counter_f_s.items():
    print(k, a[v])<jupyter_output>('Write Linear Equation from Graph', -0.012126386282034218)
('Percent Of', 0.0)
('Proportion', 0.0)
('Finding Percents', -3.1378003768622875e-05)
('Multiplication and Division Integers', 0.0)
('Algebraic Solving', -0.021225631353445351)
('Solving Inequalities', -0.00012676866026595235)
('Percents', -0.82459233759436756)
('Ordering Fractions', -3.1378003768622875e-05)
('Exponents', -0.001146187714766711)
('Addition and Subtraction Fractions', -0.19393399357795715)
('Absolute Value', -0.021225631353445351)
('Number Line', -0.00012676866026595235)
('Percent Discount', -0.19393399357795715)
('Equation Solving Two or Fewer Steps', -0.0024461087596137077)
('Conversion of Fraction Decimals Percents', -0.00019114260794594884)
('Solving for a variable', -0.0011449409066699445)
('Order of Operations +,-,/,* () positive reals', -0.24241811537649482)
('Ordering Positive Decimals', -0.20605534315109253)
('Order of Operations All', -0.00010879390174522996)
('Subtraction Whole Numbers', -0.2424181153[...]
{'fraction_non_alphanumeric': 0.12754668930390492, 'fraction_numerical': 0.08297962648556877, 'mean_word_length': 4.518735362997658, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '370198', 'license': 'MIT', 'n_tokens_mistral': 2003, 'n_tokens_neox': 1789, 'n_words': 356, 'path': 'skill_builder/Skill Builder Dataset.ipynb', 'repo_name': 'rishabhranawat/CrowdPlatform', 'size': '4712'}