diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/person.html b/aleksis/apps/alsijil/templates/alsijil/class_register/person.html
index bc715d6794e65d000cc016d0ff3430e6e04054c9..a71e0c115a3586b16d9d02b3172fa8a7e382d19c 100644
--- a/aleksis/apps/alsijil/templates/alsijil/class_register/person.html
+++ b/aleksis/apps/alsijil/templates/alsijil/class_register/person.html
@@ -42,6 +42,47 @@
         </li>
       {% endfor %}
     </ul>
+    <h5>{% trans "Statistics on absences, tardinesses and remarks" %}</h5>
+    <ul class="collapsible">
+      {% for school_term, stat in stats %}
+        <li {% if forloop.first %}class="active"{% endif %}>
+          <div class="collapsible-header">
+            <i class="material-icons">date_range</i>{{ school_term }}</div>
+          <div class="collapsible-body">
+            <table>
+              <tr>
+                <th colspan="2">{% trans 'Absences' %}</th>
+                <td>{{ stat.absences_count }}</td>
+              </tr>
+              <tr>
+                <td rowspan="{{ excuse_types.count|add:2 }}" style="width: 16mm;"
+                    class="rotate small-print">{% trans "thereof" %}</td>
+                <th>{% trans 'Excused' %}</th>
+                <td>{{ stat.excused }}</td>
+              </tr>
+              {% for excuse_type in excuse_types %}
+                <th>{{ excuse_type.name }}</th>
+                <td>{{ stat|get_dict:excuse_type.count_label }}</td>
+              {% endfor %}
+              <tr>
+                <th>{% trans 'Unexcused' %}</th>
+                <td>{{ stat.unexcused }}</td>
+              </tr>
+              <tr>
+                <th colspan="2">{% trans 'Tardiness' %}</th>
+                <td>{{ stat.tardiness }}'</td>
+              </tr>
+              {% for extra_mark in extra_marks %}
+                <tr>
+                  <th colspan="2">{{ extra_mark.name }}</th>
+                  <td>{{ stat|get_dict:extra_mark.count_label }}</td>
+                </tr>
+              {% endfor %}
+            </table>
+          </div>
+        </li>
+      {% endfor %}
+    </ul>
   </div>
   <div class="col s12 m12 l6">
     <h5>{% trans "Relevant personal notes" %}</h5>
diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py
index 41c8d29612e9cec49914700c1b6463a7d4cfcf62..87b74da2592a779edf15fafb20cc0d3e6af0edd8 100644
--- a/aleksis/apps/alsijil/views.py
+++ b/aleksis/apps/alsijil/views.py
@@ -529,6 +529,55 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp
     )
     context["personal_notes"] = personal_notes
     context["excuse_types"] = ExcuseType.objects.all()
+
+    school_terms = SchoolTerm.objects.all().order_by("-date_start")
+    stats = []
+    for school_term in school_terms:
+        stat = {}
+        personal_notes = PersonalNote.objects.filter(
+            person=person, lesson_period__lesson__validity__school_term=school_term
+        )
+
+        if not personal_notes.exists():
+            continue
+
+        stat.update(
+            personal_notes.filter(absent=True).aggregate(absences_count=Count("absent"))
+        )
+        stat.update(
+            personal_notes.filter(
+                absent=True, excused=True, excuse_type__isnull=True
+            ).aggregate(excused=Count("absent"))
+        )
+        stat.update(
+            personal_notes.filter(absent=True, excused=False).aggregate(
+                unexcused=Count("absent")
+            )
+        )
+        stat.update(
+            personal_notes.filter(absent=True, excused=False).aggregate(
+                tardiness=Count("late")
+            )
+        )
+
+        for extra_mark in ExtraMark.objects.all():
+            stat.update(
+                personal_notes.filter(extra_marks=extra_mark).aggregate(
+                    **{extra_mark.count_label: Count("pk")}
+                )
+            )
+
+        for excuse_type in ExcuseType.objects.all():
+            stat.update(
+                personal_notes.filter(absent=True, excuse_type=excuse_type).aggregate(
+                    **{excuse_type.count_label: Count("absent")}
+                )
+            )
+
+        stats.append((school_term, stat))
+    context["stats"] = stats
+    context["excuse_types"] = ExcuseType.objects.all()
+    context["extra_marks"] = ExtraMark.objects.all()
     return render(request, "alsijil/class_register/person.html", context)