-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathstudent_streak.py
More file actions
73 lines (58 loc) · 2.68 KB
/
Copy pathstudent_streak.py
File metadata and controls
73 lines (58 loc) · 2.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import os
import polars as pl # Using polars instead of pandas for speed. >9 million lines in 784k csv files.
# Calculate student_streak and student_ben_score
# student_streak is a measurement correct or incorrect answers in a row.
# Positive values represent correct answers in a row while negative values
# represent wrong answers in a row; for example, if a student correctly
# answers 3 questions in a row, their student_streak gets incremented by 3.
# Then, if they miss a question, their streak gets reset to 0 and then
# decremented by one, leaving a student_streak of -1.
def calculate_streak(df):
"""Calculate student streak using Polars vectorized operations for memory efficiency"""
print("Sorting data by student_id and timestamp...")
df = df.sort(['student_id', 'timestamp'])
print("Detecting student changes...")
# Detect when student ID changes or correctness changes
df = df.with_columns(
pl.when(pl.col('student_id') != pl.col('student_id').shift(1))
.then(1)
.when(pl.col('correct') != pl.col('correct').shift(1))
.then(1)
.otherwise(0)
.alias('streak_changed')
)
print("Creating groups for streaks...")
# Create groups for each streak (same student, same correctness)
df = df.with_columns(
pl.col('streak_changed').cum_sum().alias('streak_group_id')
)
print("Computing streaks...")
# Calculate streak within each group
df = df.with_columns(
pl.when(pl.col('correct') == 1)
.then(pl.col('correct').cum_sum().over('streak_group_id'))
.otherwise(-pl.arange(1, pl.len() + 1).over('streak_group_id'))
.alias('student_streak')
)
print("Cleaning up temporary columns...")
# Drop temporary columns
df = df.drop(['streak_changed', 'streak_group_id'])
return df
# UNCOMMENT STUFF AS NEEDED, MY COMPUTER DIDN'T HAVE ENOUGH RAM TO DO BOTH AT THE SAME TIME
# We split our data into 2 separate sets in the prep_data file
# print("Loading training data...")
# train_df = pl.read_parquet(rf".\Data\train_data.parquet")
print("Loading validation data...")
val_df = pl.read_parquet(rf".\Data\val_data.parquet")
# print("\nCalculating streak for training data...")
# train_df = calculate_streak(train_df)
print("\nCalculating streak for validation data...")
val_df = calculate_streak(val_df)
print("\nTraining data sample:")
print(val_df.head())
# print("\nSaving training data...")
# train_df.write_parquet(rf".\Data\final_train_data.parquet")
# train_df.write_csv(rf".\Data\final_train_data.csv")
print("Saving validation data...")
val_df.write_parquet(rf".\Data\final_val_data.parquet")
val_df.write_csv(rf".\Data\final_val_data.csv")