Improve statistics presentation
John Smith

John Smith commited on 2022-323 22:54:29
Showing 2 changed files, with 60 additions and 19 deletions.


* reorganise code
* fix bug encountered for small datasets
* allow user to filter for cards containing a given query
* show upcoming review quantities
... ...
@@ -136,7 +136,7 @@ local function showpctiles(list, pctiles, func, name)
136 136
     end
137 137
     s = s .. "\n" .. name
138 138
     for _, v in ipairs(pctiles) do
139
-        s = s .. "\t" .. func(list[math.floor(v * #list)])
139
+        s = s .. "\t" .. func(list[math.ceil(v * #list)])
140 140
     end
141 141
     return s .. "\n"
142 142
 end
... ...
@@ -329,24 +329,43 @@ local actions = {
329 329
     s = {
330 330
         desc = "(s)tatistics",
331 331
         nd = true,
332
-        fn = function(config, deck, deckfname)
332
+        nq = true,
333
+        fn = function(config, deck, deckfname, qs)
334
+            local tcc = 0
333 335
             local tsc = 0
334 336
             local tfc = 0
337
+            local spc = 0
335 338
             local expdeck = {}
336 339
             for _, card in ipairs(deck) do
340
+                local rtc
337 341
                 for _, pr in ipairs(card) do
342
+                    if not qs or (pr.text:find(qs) or pr.ans:find(qs)) then
343
+                        rtc = true
338 344
                         table.insert(expdeck, pr)
339 345
                         tsc = tsc + pr.succ
340 346
                         tfc = tfc + pr.fail
347
+                        if pr.delay < 0 then
348
+                            spc = spc + 1
349
+                        end
350
+                    end
351
+                end
352
+                if rtc then
353
+                    tcc = tcc + 1
341 354
                 end
342 355
             end
356
+            local qfn
357
+            if qs then
358
+                qfn = string.format(" (filtered with query %q)", qs)
359
+            else
360
+                qfn = ""
361
+            end
343 362
             io.write(string.format(
344
-                "%s has %d cards and %d total prompts\n",
345
-                deckfname, #deck, #expdeck
363
+                "%s%s has %d cards and %d total prompts\n",
364
+                deckfname, qfn, tcc, #expdeck
346 365
             ))
347 366
             io.write(string.format(
348
-                "(average %.2f prompts per card).\n",
349
-                #expdeck / #deck
367
+                "(average %.2f prompts per card, %d/%.1f%% prompts suspended).\n",
368
+                #expdeck / tcc, spc, 100 * spc / #expdeck
350 369
             ))
351 370
             io.write(string.format(
352 371
                 "The deck's prompts have been reviewed a total of %d times\n",
... ...
@@ -356,30 +375,46 @@ local actions = {
356 375
                 "(average %.2f reviews per prompt), overall retention %.2f%%.\n",
357 376
                 (tsc + tfc) / #expdeck, 100 * tsc / (tsc + tfc)
358 377
             ))
359
-            table.sort(expdeck, function(a, b)
360
-                return a.ease < b.ease
361
-            end)
378
+            table.sort(expdeck, function(a, b) return a.ease < b.ease end)
362 379
             io.write("\n" .. showpctiles(expdeck, { 0.01, 0.05, 0.1, 0.25, 0.5, 0.8, 0.95 }, function(pr)
363 380
                 return string.format("%.2f", pr.ease)
364 381
             end, "Ease"))
365
-            table.sort(expdeck, function(a, b)
366
-                return a:retention() < b:retention()
367
-            end)
382
+            table.sort(expdeck, function(a, b) return a.delay > 0 and a.delay < b.delay end)
383
+            io.write("\n" .. showpctiles(expdeck, { 0.01, 0.05, 0.2, 0.5, 0.8, 0.95, 0.99 }, function(pr)
384
+                return disptime(pr.delay)
385
+            end, "Delay"))
386
+            table.sort(expdeck, function(a, b) return a:retention() < b:retention() end)
368 387
             io.write("\n" .. showpctiles(expdeck, { 0.01, 0.05, 0.1, 0.15, 0.2, 0.25, 0.4 }, function(pr)
369 388
                 return math.floor(100 * pr:retention())
370 389
             end, "Ret. %"))
371
-            table.sort(expdeck, function(a, b)
372
-                return a.succ + a.fail < b.succ + b.fail
373
-            end)
374
-            io.write("\n" .. showpctiles(expdeck, { 0.25, 0.5, 0.7, 0.85, 0.95, 0.99, 0.995 }, function(pr)
390
+            table.sort(expdeck, function(a, b) return a.succ + a.fail < b.succ + b.fail end)
391
+            io.write("\n" .. showpctiles(expdeck, { 0.25, 0.5, 0.7, 0.85, 0.95, 0.99, 0.998 }, function(pr)
375 392
                 return pr.succ + pr.fail
376 393
             end, "Reviews"))
377
-            table.sort(expdeck, function(a, b)
378
-                return (a.created or 99^98) > (b.created or 99^99)
379
-            end)
394
+            table.sort(expdeck, function(a, b) return (a.created or 99^98) > (b.created or 99^99) end)
380 395
             io.write("\n" .. showpctiles(expdeck, { 0.1, 0.25, 0.5, 0.75, 0.9, 0.95, 0.99 }, function(pr)
381 396
                 return disptime(os.time() - pr.created)
382 397
             end, "Age"))
398
+            table.sort(deck, function(a, b) return #a < #b end)
399
+            io.write("\n" .. showpctiles(deck, { 0.2, 0.5, 0.8, 0.95, 0.99, 0.998 }, function(card)
400
+                return #card
401
+            end, "Prompts"))
402
+            table.sort(expdeck, function(a, b) return a.time + a.delay < b.time + b.delay end)
403
+            io.write("\nUpcoming due prompts wrt days from now:\n")
404
+            local ppi = 1
405
+            local mpi = 1
406
+            for dc = 1,100 do
407
+                for uc = ppi,#expdeck do
408
+                    if expdeck[uc].time + expdeck[uc].delay - os.time() > dc * 86400 then
409
+                        mpi = uc
410
+                        break
411
+                    end
412
+                end
413
+                if dc <= 10 or dc % 10 == 0 then
414
+                    io.write(string.format("%d\t%s %d\n", dc, ("\u{2588}"):rep(math.ceil((mpi - ppi) / 10)), mpi - ppi))
415
+                end
416
+                ppi = mpi
417
+            end
383 418
         end
384 419
     },
385 420
 
... ...
@@ -95,6 +95,12 @@ if action.nd then
95 95
             else
96 96
                 io.write("Bad prompt index (must be cardnum:promptnum)\n")
97 97
             end
98
+        elseif action.nq then
99
+            local qs
100
+            if arg[2] then
101
+                qs = arg[2]
102
+            end
103
+            deck = action.fn(config, deck, deckfname, qs)
98 104
         else
99 105
             deck = action.fn(config, deck, deckfname)
100 106
         end
101 107