|
7 | 7 | "id": "jmXx-hS9ZMVj" |
8 | 8 | }, |
9 | 9 | "source": [ |
10 | | - "# FSRS4Anki v4.10.0 Simulator" |
| 10 | + "# FSRS4Anki v4.10.2 Simulator" |
11 | 11 | ] |
12 | 12 | }, |
13 | 13 | { |
|
17 | 17 | "id": "lurCmW0Jqz3s" |
18 | 18 | }, |
19 | 19 | "source": [ |
20 | | - "[](https://colab.research.google.com/github/open-spaced-repetition/fsrs4anki/blob/v4.8.3/fsrs4anki_simulator.ipynb)\n", |
| 20 | + "[](https://colab.research.google.com/github/open-spaced-repetition/fsrs4anki/blob/v4.10.2/fsrs4anki_simulator.ipynb)\n", |
21 | 21 | "\n", |
22 | 22 | "↑ Click the above button to open the simulator on Google Colab.\n", |
23 | 23 | "\n", |
|
90 | 90 | } |
91 | 91 | ], |
92 | 92 | "source": [ |
93 | | - "# %pip install -q fsrs_optimizer==4.18.0\n", |
| 93 | + "%pip install -q fsrs_optimizer==4.18.2\n", |
94 | 94 | "import pandas as pd\n", |
95 | 95 | "import numpy as np\n", |
96 | 96 | "import random\n", |
| 97 | + "\n", |
97 | 98 | "# for local development\n", |
98 | 99 | "# import os\n", |
99 | 100 | "# import sys\n", |
|
111 | 112 | "df = pd.read_csv(\"./revlog.csv\")\n", |
112 | 113 | "df.sort_values(by=[\"card_id\", \"review_time\"], inplace=True, ignore_index=True)\n", |
113 | 114 | "\n", |
114 | | - "new_card_revlog = df[(df[\"review_state\"] == New) & (df[\"review_rating\"].isin([1, 2, 3, 4]))]\n", |
| 115 | + "new_card_revlog = df[\n", |
| 116 | + " (df[\"review_state\"] == New) & (df[\"review_rating\"].isin([1, 2, 3, 4]))\n", |
| 117 | + "]\n", |
115 | 118 | "first_rating_prob = np.zeros(4)\n", |
116 | 119 | "first_rating_prob[new_card_revlog[\"review_rating\"].value_counts().index - 1] = (\n", |
117 | 120 | " new_card_revlog[\"review_rating\"].value_counts()\n", |
118 | 121 | " / new_card_revlog[\"review_rating\"].count()\n", |
119 | 122 | ")\n", |
120 | | - "recall_card_revlog = df[(df[\"review_state\"] == Review) & (df[\"review_rating\"].isin([2, 3, 4]))]\n", |
| 123 | + "recall_card_revlog = df[\n", |
| 124 | + " (df[\"review_state\"] == Review) & (df[\"review_rating\"].isin([2, 3, 4]))\n", |
| 125 | + "]\n", |
121 | 126 | "review_rating_prob = np.zeros(3)\n", |
122 | 127 | "review_rating_prob[recall_card_revlog[\"review_rating\"].value_counts().index - 2] = (\n", |
123 | 128 | " recall_card_revlog[\"review_rating\"].value_counts()\n", |
124 | 129 | " / recall_card_revlog[\"review_rating\"].count()\n", |
125 | 130 | ")\n", |
126 | 131 | "\n", |
127 | | - "df[\"review_state\"] = df[\"review_state\"].map(lambda x: x if x != New else Learning)\n", |
| 132 | + "df[\"review_state\"] = df[\"review_state\"].map(\n", |
| 133 | + " lambda x: x if x != New else Learning)\n", |
128 | 134 | "\n", |
129 | 135 | "recall_costs = np.zeros(3)\n", |
130 | 136 | "recall_costs_df = recall_card_revlog.groupby(by=\"review_rating\")[\n", |
|
150 | 156 | "state_duration[last_state] = duration_sequence[0]\n", |
151 | 157 | "for i, state in enumerate(state_sequence[1:]):\n", |
152 | 158 | " state_count[state] = state_count.setdefault(state, 0) + 1\n", |
153 | | - " state_duration[state] = state_duration.setdefault(state, 0) + duration_sequence[i]\n", |
| 159 | + " state_duration[state] = state_duration.setdefault(\n", |
| 160 | + " state, 0) + duration_sequence[i]\n", |
154 | 161 | " if state != last_state:\n", |
155 | 162 | " state_block[state] = state_block.setdefault(state, 0) + 1\n", |
156 | 163 | " last_state = state\n", |
|
159 | 166 | "\n", |
160 | 167 | "if Relearning in state_count and Relearning in state_block:\n", |
161 | 168 | " forget_cost = round(\n", |
162 | | - " state_duration[Relearning] / state_block[Relearning] / 1000 + recall_cost,\n", |
| 169 | + " state_duration[Relearning] /\n", |
| 170 | + " state_block[Relearning] / 1000 + recall_cost,\n", |
163 | 171 | " 1,\n", |
164 | 172 | " )\n", |
165 | 173 | "\n", |
|
364 | 372 | " if factor is None:\n", |
365 | 373 | " return (graduatingInterval, 2.5) if rating != 4 else (easyInterval, 2.5)\n", |
366 | 374 | " delay = real_interval - interval\n", |
367 | | - " again_interval = max(\n", |
368 | | - " round(interval * newInterval * intervalModifier + 0.01), minimumInterval\n", |
| 375 | + " again_interval = min(\n", |
| 376 | + " max(round(interval * newInterval * intervalModifier + 0.01), minimumInterval),\n", |
| 377 | + " maximumInterval,\n", |
369 | 378 | " )\n", |
370 | | - " hard_interval = max(\n", |
371 | | - " round(interval * hardInterval * intervalModifier + 0.01),\n", |
372 | | - " interval + 1,\n", |
373 | | - " minimumInterval,\n", |
| 379 | + " hard_interval = min(\n", |
| 380 | + " max(\n", |
| 381 | + " round(interval * hardInterval * intervalModifier + 0.01),\n", |
| 382 | + " interval + 1,\n", |
| 383 | + " minimumInterval,\n", |
| 384 | + " ),\n", |
| 385 | + " maximumInterval,\n", |
374 | 386 | " )\n", |
375 | | - " good_interval = max(\n", |
376 | | - " round((interval + delay / 2) * factor * intervalModifier + 0.01),\n", |
377 | | - " hard_interval + 1,\n", |
378 | | - " minimumInterval,\n", |
| 387 | + " good_interval = min(\n", |
| 388 | + " max(\n", |
| 389 | + " round((interval + delay / 2) * factor * intervalModifier + 0.01),\n", |
| 390 | + " hard_interval + 1,\n", |
| 391 | + " minimumInterval,\n", |
| 392 | + " ),\n", |
| 393 | + " maximumInterval,\n", |
379 | 394 | " )\n", |
380 | | - " easy_interval = max(\n", |
381 | | - " round(real_interval * factor * intervalModifier * easyBonus + 0.01),\n", |
382 | | - " good_interval + 1,\n", |
383 | | - " minimumInterval,\n", |
| 395 | + " easy_interval = min(\n", |
| 396 | + " max(\n", |
| 397 | + " round(real_interval * factor * intervalModifier * easyBonus + 0.01),\n", |
| 398 | + " good_interval + 1,\n", |
| 399 | + " minimumInterval,\n", |
| 400 | + " ),\n", |
| 401 | + " maximumInterval,\n", |
384 | 402 | " )\n", |
385 | 403 | " if rating == 1:\n", |
386 | 404 | " return again_interval, max(factor - 0.2, 1.3)\n", |
|
556 | 574 | "\n", |
557 | 575 | " if day >= moving_average_period:\n", |
558 | 576 | " new_card_per_day_average_per_period[day] = np.true_divide(\n", |
559 | | - " new_card_per_day[day - moving_average_period : day].sum(),\n", |
| 577 | + " new_card_per_day[day - moving_average_period: day].sum(),\n", |
560 | 578 | " moving_average_period,\n", |
561 | 579 | " )\n", |
562 | 580 | " review_card_per_day_average_per_period[day] = np.true_divide(\n", |
563 | | - " review_card_per_day[day - moving_average_period : day].sum(),\n", |
| 581 | + " review_card_per_day[day - moving_average_period: day].sum(),\n", |
564 | 582 | " moving_average_period,\n", |
565 | 583 | " )\n", |
566 | 584 | " time_per_day_average_per_period[day] = np.true_divide(\n", |
567 | | - " time_per_day[day - moving_average_period : day].sum(),\n", |
| 585 | + " time_per_day[day - moving_average_period: day].sum(),\n", |
568 | 586 | " moving_average_period,\n", |
569 | 587 | " )\n", |
570 | 588 | " else:\n", |
|
598 | 616 | " print(\"learned cards:\", total_learned)\n", |
599 | 617 | " print(\"time in minutes:\", round(total_time / 60, 1))\n", |
600 | 618 | " print(\"remembered cards:\", total_remembered)\n", |
601 | | - " print(\"time per remembered card:\", round(total_time / 60 / total_remembered, 2))\n", |
| 619 | + " print(\"time per remembered card:\", round(\n", |
| 620 | + " total_time / 60 / total_remembered, 2))\n", |
602 | 621 | " print(\"leeches:\", total_leeches)\n", |
603 | 622 | "\n", |
604 | 623 | " save = card[card[\"retrievability\"] > 0].copy()\n", |
|
0 commit comments