Skip to content
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

enhance(apps/analytics): add computation logic for activity progress #4392

Merged
merged 4 commits into from
Dec 6, 2024
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
1 change: 1 addition & 0 deletions apps/analytics/src/modules/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
from .aggregated_course_analytics import *
from .participant_performance import *
from .instance_activity_performance import *
from .activity_progress import *
sjschlapbach marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 4 additions & 0 deletions apps/analytics/src/modules/activity_progress/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .get_course_progress_activities import get_course_progress_activities
from .compute_progress_counts import compute_progress_counts
from .save_practice_quiz_progress import save_practice_quiz_progress
from .save_microlearning_progress import save_microlearning_progress
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import pandas as pd


def compute_progress_counts(activity):
started_count = 0
completed_count = 0
repeated_count = 0

sjschlapbach marked this conversation as resolved.
Show resolved Hide resolved
if len(activity["responses"]) != 0:
# count number of elements in activity stacks
num_elements = 0
for stack in activity["stacks"]:
num_elements += len(stack["elements"])

# group the activity responses by participant and count them
df_responses = pd.DataFrame(activity["responses"])
df_statistics = (
df_responses[["id", "trialsCount", "participantId"]]
.groupby("participantId")
.agg({"id": "count", "trialsCount": "min"})
.rename(columns={"id": "count", "trialsCount": "min_trials"})
)
sjschlapbach marked this conversation as resolved.
Show resolved Hide resolved

# compute number of participants that have started the activity
started_count = len(df_statistics[df_statistics["count"] <= num_elements])

# compute number of participants that have completed the activity
completed_count = len(df_statistics[df_statistics["count"] == num_elements])

# count the number of participants that have repeated the activity (completed and min_trials >= 2)
repeated_count = len(
df_statistics[
(df_statistics["count"] == num_elements)
& (df_statistics["min_trials"] >= 2)
]
)

else:
print("No responses found for activity", activity["id"])

return started_count, completed_count, repeated_count
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
def get_course_progress_activities(db, course_id):
pqs = db.practicequiz.find_many(
where={"courseId": course_id},
include={"stacks": {"include": {"elements": True}}, "responses": True},
)
pqs = list(map(lambda x: x.dict(), pqs))
sjschlapbach marked this conversation as resolved.
Show resolved Hide resolved

mls = db.microlearning.find_many(
where={"courseId": course_id},
include={"stacks": {"include": {"elements": True}}, "responses": True},
)
mls = list(map(lambda x: x.dict(), mls))

return pqs, mls
sjschlapbach marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
def save_microlearning_progress(
db,
course_participants,
started_count,
completed_count,
course_id,
ml_id,
):
sjschlapbach marked this conversation as resolved.
Show resolved Hide resolved
values = {
"totalCourseParticipants": course_participants,
"startedCount": started_count,
"completedCount": completed_count,
}
creation_values = values.copy()
creation_values["course"] = {"connect": {"id": course_id}}
creation_values["microLearning"] = {"connect": {"id": ml_id}}

db.activityprogress.upsert(
where={"microLearningId": ml_id},
data={"create": creation_values, "update": values},
)
sjschlapbach marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
def save_practice_quiz_progress(
db,
course_participants,
started_count,
completed_count,
repeated_count,
course_id,
quiz_id,
):
values = {
"totalCourseParticipants": course_participants,
"startedCount": started_count,
"completedCount": completed_count,
"repeatedCount": repeated_count,
}
creation_values = values.copy()
creation_values["course"] = {"connect": {"id": course_id}}
creation_values["practiceQuiz"] = {"connect": {"id": quiz_id}}

db.activityprogress.upsert(
where={"practiceQuizId": quiz_id},
data={"create": creation_values, "update": values},
)
sjschlapbach marked this conversation as resolved.
Show resolved Hide resolved
147 changes: 147 additions & 0 deletions apps/analytics/src/notebooks/activity_progress.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Preparation"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import json\n",
"from datetime import datetime\n",
"from prisma import Prisma\n",
"import pandas as pd\n",
"import sys\n",
"\n",
"# set the python path correctly for module imports to work\n",
"sys.path.append(\"../../\")\n",
"\n",
"from src.modules.participant_course_analytics.get_running_past_courses import (\n",
" get_running_past_courses,\n",
")\n",
"from src.modules.activity_progress.get_course_progress_activities import (\n",
" get_course_progress_activities,\n",
")\n",
"from src.modules.activity_progress.compute_progress_counts import (\n",
" compute_progress_counts,\n",
")\n",
"from src.modules.activity_progress.save_practice_quiz_progress import (\n",
" save_practice_quiz_progress,\n",
")\n",
"from src.modules.activity_progress.save_microlearning_progress import (\n",
" save_microlearning_progress,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"db = Prisma()\n",
"\n",
"# set the environment variable DATABASE_URL to the connection string of your database\n",
"os.environ[\"DATABASE_URL\"] = \"postgresql://klicker:klicker@localhost:5432/klicker-prod\"\n",
sjschlapbach marked this conversation as resolved.
Show resolved Hide resolved
Dismissed Show dismissed Hide dismissed
"\n",
"db.connect()\n",
"\n",
"# Script settings\n",
"verbose = False"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Compute Activity Progress"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Fetch all courses from the database\n",
"df_courses = get_running_past_courses(db)\n",
"\n",
"# Iterate over the course and fetch all question responses linked to it\n",
"for idx, course in df_courses.iterrows():\n",
" course_id = course[\"id\"]\n",
" print(f\"Processing course\", idx, \"of\", len(df_courses), \"with id\", course_id)\n",
"\n",
" # extract number of participants\n",
" course_participants = len(course[\"participations\"])\n",
"\n",
" # fetch all practice quizzes and microlearnings linked to the course\n",
" pqs, mls = get_course_progress_activities(db, course_id)\n",
sjschlapbach marked this conversation as resolved.
Show resolved Hide resolved
"\n",
" for quiz in pqs:\n",
" started_count, completed_count, repeated_count = compute_progress_counts(quiz)\n",
"\n",
" # store results in database table\n",
" save_practice_quiz_progress(\n",
" db,\n",
" course_participants,\n",
" started_count,\n",
" completed_count,\n",
" repeated_count,\n",
" course_id,\n",
" quiz[\"id\"],\n",
" )\n",
sjschlapbach marked this conversation as resolved.
Show resolved Hide resolved
"\n",
" for ml in mls:\n",
" started_count, completed_count, repeated_count = compute_progress_counts(ml)\n",
"\n",
" # store results in database table\n",
" save_microlearning_progress(\n",
" db,\n",
" course_participants,\n",
" started_count,\n",
" completed_count,\n",
" course_id,\n",
" ml[\"id\"],\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Disconnect from the database\n",
"db.disconnect()"
sjschlapbach marked this conversation as resolved.
Show resolved Hide resolved
]
}
],
"metadata": {
"kernelspec": {
"display_name": "analytics-fkWWeYLw-py3.12",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.5"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
32 changes: 24 additions & 8 deletions apps/analytics/src/notebooks/instance_activity_performance.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,21 @@
"from src.modules.participant_course_analytics.get_running_past_courses import (\n",
" get_running_past_courses,\n",
")\n",
"from src.modules.instance_activity_performance.get_course_activities import get_course_activities\n",
"from src.modules.instance_activity_performance.compute_instance_performance import compute_instance_performance\n",
"from src.modules.instance_activity_performance.agg_activity_performance import agg_activity_performance\n",
"from src.modules.instance_activity_performance.save_instance_performances import save_instance_performances\n",
"from src.modules.instance_activity_performance.save_activity_performance import save_activity_performance"
"from src.modules.instance_activity_performance.get_course_activities import (\n",
" get_course_activities,\n",
")\n",
"from src.modules.instance_activity_performance.compute_instance_performance import (\n",
" compute_instance_performance,\n",
")\n",
"from src.modules.instance_activity_performance.agg_activity_performance import (\n",
" agg_activity_performance,\n",
")\n",
"from src.modules.instance_activity_performance.save_instance_performances import (\n",
" save_instance_performances,\n",
")\n",
"from src.modules.instance_activity_performance.save_activity_performance import (\n",
" save_activity_performance,\n",
")"
]
},
{
Expand Down Expand Up @@ -89,7 +99,9 @@
" save_instance_performances(db, df_instance_performance, course_id)\n",
"\n",
" # save activity performance data\n",
" save_activity_performance(db, activity_performance, course_id, practice_quiz_id=quiz[\"id\"])\n",
" save_activity_performance(\n",
" db, activity_performance, course_id, practice_quiz_id=quiz[\"id\"]\n",
" )\n",
"\n",
" for ml in mls:\n",
" # compute instance performances\n",
Expand All @@ -103,10 +115,14 @@
" activity_performance = agg_activity_performance(df_instance_performance)\n",
"\n",
" # save instance performance data\n",
" save_instance_performances(db, df_instance_performance, course_id, total_only=True)\n",
" save_instance_performances(\n",
" db, df_instance_performance, course_id, total_only=True\n",
" )\n",
"\n",
" # save activity performance data\n",
" save_activity_performance(db, activity_performance, course_id, microlearning_id=ml[\"id\"])"
" save_activity_performance(\n",
" db, activity_performance, course_id, microlearning_id=ml[\"id\"]\n",
" )"
]
},
{
Expand Down
Loading