{
  "cells": [
    {
      "cell_type": "code",
      "source": [
        "!date\n",
        "!python --version"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "PCb3G6VQ0UNw",
        "outputId": "8af9c839-9d28-4db8-aa31-03f4347fe688"
      },
      "execution_count": 13,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Mon Apr 21 06:26:17 AM UTC 2025\n",
            "Python 3.11.12\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "biQ6Vtx0tRAO"
      },
      "source": [
        "# 極性分類システムの構築例（ルールベース）\n",
        "- 参考\n",
        "    - [CMU CS11-711 Advanced NLP](http://phontron.com/class/anlp2024/)\n",
        "\n",
        "## 本演習の目標\n",
        "- テキスト分類システムを構成する部品と全体像を把握する。\n",
        "- 実例を題材として分類精度を確認するとともに、失敗要因分析を通してシステム更新し、性能向上を試みる。\n",
        "    - 主な更新箇所：特徴抽出、評価関数\n",
        "- 性能向上策が寄与したかどうかを検証するために、実験条件と評価結果を記録する。\n",
        "\n",
        "## 全体の流れ\n",
        "- A. データセット用意\n",
        "- B. 特徴抽出\n",
        "- C. 分類器構築\n",
        "- D. 性能評価\n",
        "- E. 失敗分析\n",
        "\n",
        "## Tips\n",
        "本来ならば形態素解析を通してステミング（原型化）をした方がベターですが、今回は分かち書きのみに留めています。このため「良い」と「よい」「よかった」等は異なる単語として扱われます。興味のある人は[mecabを用いた形態素解析](https://ie.u-ryukyu.ac.jp/~tnal/2025/dm/static/4-nlp/typical_methods_mecab.html#id2)を参照ください。今回は処理結果の例を後述のデータセットに含めてあります。分かち書き、形態素解析等の詳細は後日扱います。\n",
        "\n",
        "## データセット\n",
        "データは[調査と解析班](https://r.st.ie.u-ryukyu.ac.jp/assessment/)で収集された、知能除法コース専門科目の2021年度前期科目を対象に自由記述欄のデータです。これに當間が主観で「良い評価(1)、悪い評価(-1)、どちらでもない(0)」を sentiment 列に付与しました。これをExcelファイルとして用意したものが ``r_assesment_sentiment.xlsx`` です。このファイルを用意してから実行してください。（プログラムでは curl コマンドでダウンロードしています）\n",
        "- r_assesment_sentiment.xlsx\n",
        "  - 列説明\n",
        "    - title: 授業名\n",
        "    - grade: 対象学年\n",
        "    - required: 必修科目(True), 選択科目(False)\n",
        "    - q_id: 問い番号\n",
        "    - comment: 自由記述内容（原文）。\n",
        "    - wakati1: commentをmecabで分かち書きしたテキスト。\n",
        "    - wakati2: commentをmecabで分かち書きし、レマタイズしたテキスト。\n",
        "    - sentiment: 極性ラベル。良い評価(1)、悪い評価(-1)、どちらでもない(0)。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "alUvMGeNtRAS"
      },
      "source": [
        "## A. データセット用意"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "!curl -O https://ie.u-ryukyu.ac.jp/~tnal/2025/dm/static/r_assesment_sentiment.xlsx"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "o1KtXqTV1WkZ",
        "outputId": "95d3a74a-f3fa-414b-bbba-c37287cd70e5"
      },
      "execution_count": 14,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current\n",
            "                                 Dload  Upload   Total   Spent    Left  Speed\n",
            "100 53514  100 53514    0     0  22086      0  0:00:02  0:00:02 --:--:-- 22094\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "metadata": {
        "id": "ny2oktpwtRAS",
        "outputId": "176ff935-1181-41d4-a12c-5d213460db82",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 289
        }
      },
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "   title  grade  required     q_id                       comment  \\\n",
              "0  工業数学Ⅰ      1      True  Q21 (1)                          特になし   \n",
              "1  工業数学Ⅰ      1      True  Q21 (2)            正直わかりずらい。むだに間があるし。   \n",
              "2  工業数学Ⅰ      1      True  Q21 (2)          例題を取り入れて理解しやすくしてほしい。   \n",
              "3  工業数学Ⅰ      1      True  Q21 (2)                          特になし   \n",
              "4  工業数学Ⅰ      1      True  Q21 (2)  スライドに書く文字をもう少しわかりやすくして欲しいです。   \n",
              "\n",
              "                                    wakati1  \\\n",
              "0                                     特に なし   \n",
              "1             正直 わかり ず らい 。 むだ に 間 が ある し 。   \n",
              "2            例題 を 取り入れ て 理解 し やすく し て ほしい 。   \n",
              "3                                     特に なし   \n",
              "4  スライド に 書く 文字 を もう少し わかり やすく し て 欲しい です 。   \n",
              "\n",
              "                                     wakati2  sentiment  \n",
              "0                                      特に ない          0  \n",
              "1              正直 わかる ぬ らい 。 むだ に 間 が ある し 。         -1  \n",
              "2          例題 を 取り入れる て 理解 する やすい する て ほしい 。         -1  \n",
              "3                                      特に ない          0  \n",
              "4  スライド に 書く 文字 を もう少し わかる やすい する て 欲しい です 。         -1  "
            ],
            "text/html": [
              "\n",
              "  <div id=\"df-68ac995f-6d36-4dc6-a2cb-00d0811a1663\" class=\"colab-df-container\">\n",
              "    <div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>title</th>\n",
              "      <th>grade</th>\n",
              "      <th>required</th>\n",
              "      <th>q_id</th>\n",
              "      <th>comment</th>\n",
              "      <th>wakati1</th>\n",
              "      <th>wakati2</th>\n",
              "      <th>sentiment</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>工業数学Ⅰ</td>\n",
              "      <td>1</td>\n",
              "      <td>True</td>\n",
              "      <td>Q21 (1)</td>\n",
              "      <td>特になし</td>\n",
              "      <td>特に なし</td>\n",
              "      <td>特に ない</td>\n",
              "      <td>0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>工業数学Ⅰ</td>\n",
              "      <td>1</td>\n",
              "      <td>True</td>\n",
              "      <td>Q21 (2)</td>\n",
              "      <td>正直わかりずらい。むだに間があるし。</td>\n",
              "      <td>正直 わかり ず らい 。 むだ に 間 が ある し 。</td>\n",
              "      <td>正直 わかる ぬ らい 。 むだ に 間 が ある し 。</td>\n",
              "      <td>-1</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>工業数学Ⅰ</td>\n",
              "      <td>1</td>\n",
              "      <td>True</td>\n",
              "      <td>Q21 (2)</td>\n",
              "      <td>例題を取り入れて理解しやすくしてほしい。</td>\n",
              "      <td>例題 を 取り入れ て 理解 し やすく し て ほしい 。</td>\n",
              "      <td>例題 を 取り入れる て 理解 する やすい する て ほしい 。</td>\n",
              "      <td>-1</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>工業数学Ⅰ</td>\n",
              "      <td>1</td>\n",
              "      <td>True</td>\n",
              "      <td>Q21 (2)</td>\n",
              "      <td>特になし</td>\n",
              "      <td>特に なし</td>\n",
              "      <td>特に ない</td>\n",
              "      <td>0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>工業数学Ⅰ</td>\n",
              "      <td>1</td>\n",
              "      <td>True</td>\n",
              "      <td>Q21 (2)</td>\n",
              "      <td>スライドに書く文字をもう少しわかりやすくして欲しいです。</td>\n",
              "      <td>スライド に 書く 文字 を もう少し わかり やすく し て 欲しい です 。</td>\n",
              "      <td>スライド に 書く 文字 を もう少し わかる やすい する て 欲しい です 。</td>\n",
              "      <td>-1</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>\n",
              "    <div class=\"colab-df-buttons\">\n",
              "\n",
              "  <div class=\"colab-df-container\">\n",
              "    <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-68ac995f-6d36-4dc6-a2cb-00d0811a1663')\"\n",
              "            title=\"Convert this dataframe to an interactive table.\"\n",
              "            style=\"display:none;\">\n",
              "\n",
              "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n",
              "    <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n",
              "  </svg>\n",
              "    </button>\n",
              "\n",
              "  <style>\n",
              "    .colab-df-container {\n",
              "      display:flex;\n",
              "      gap: 12px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert {\n",
              "      background-color: #E8F0FE;\n",
              "      border: none;\n",
              "      border-radius: 50%;\n",
              "      cursor: pointer;\n",
              "      display: none;\n",
              "      fill: #1967D2;\n",
              "      height: 32px;\n",
              "      padding: 0 0 0 0;\n",
              "      width: 32px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert:hover {\n",
              "      background-color: #E2EBFA;\n",
              "      box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
              "      fill: #174EA6;\n",
              "    }\n",
              "\n",
              "    .colab-df-buttons div {\n",
              "      margin-bottom: 4px;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert {\n",
              "      background-color: #3B4455;\n",
              "      fill: #D2E3FC;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert:hover {\n",
              "      background-color: #434B5C;\n",
              "      box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
              "      filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
              "      fill: #FFFFFF;\n",
              "    }\n",
              "  </style>\n",
              "\n",
              "    <script>\n",
              "      const buttonEl =\n",
              "        document.querySelector('#df-68ac995f-6d36-4dc6-a2cb-00d0811a1663 button.colab-df-convert');\n",
              "      buttonEl.style.display =\n",
              "        google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
              "\n",
              "      async function convertToInteractive(key) {\n",
              "        const element = document.querySelector('#df-68ac995f-6d36-4dc6-a2cb-00d0811a1663');\n",
              "        const dataTable =\n",
              "          await google.colab.kernel.invokeFunction('convertToInteractive',\n",
              "                                                    [key], {});\n",
              "        if (!dataTable) return;\n",
              "\n",
              "        const docLinkHtml = 'Like what you see? Visit the ' +\n",
              "          '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
              "          + ' to learn more about interactive tables.';\n",
              "        element.innerHTML = '';\n",
              "        dataTable['output_type'] = 'display_data';\n",
              "        await google.colab.output.renderOutput(dataTable, element);\n",
              "        const docLink = document.createElement('div');\n",
              "        docLink.innerHTML = docLinkHtml;\n",
              "        element.appendChild(docLink);\n",
              "      }\n",
              "    </script>\n",
              "  </div>\n",
              "\n",
              "\n",
              "<div id=\"df-8800d2ac-6e65-41ca-9b7b-6cc45a01e535\">\n",
              "  <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-8800d2ac-6e65-41ca-9b7b-6cc45a01e535')\"\n",
              "            title=\"Suggest charts\"\n",
              "            style=\"display:none;\">\n",
              "\n",
              "<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n",
              "     width=\"24px\">\n",
              "    <g>\n",
              "        <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n",
              "    </g>\n",
              "</svg>\n",
              "  </button>\n",
              "\n",
              "<style>\n",
              "  .colab-df-quickchart {\n",
              "      --bg-color: #E8F0FE;\n",
              "      --fill-color: #1967D2;\n",
              "      --hover-bg-color: #E2EBFA;\n",
              "      --hover-fill-color: #174EA6;\n",
              "      --disabled-fill-color: #AAA;\n",
              "      --disabled-bg-color: #DDD;\n",
              "  }\n",
              "\n",
              "  [theme=dark] .colab-df-quickchart {\n",
              "      --bg-color: #3B4455;\n",
              "      --fill-color: #D2E3FC;\n",
              "      --hover-bg-color: #434B5C;\n",
              "      --hover-fill-color: #FFFFFF;\n",
              "      --disabled-bg-color: #3B4455;\n",
              "      --disabled-fill-color: #666;\n",
              "  }\n",
              "\n",
              "  .colab-df-quickchart {\n",
              "    background-color: var(--bg-color);\n",
              "    border: none;\n",
              "    border-radius: 50%;\n",
              "    cursor: pointer;\n",
              "    display: none;\n",
              "    fill: var(--fill-color);\n",
              "    height: 32px;\n",
              "    padding: 0;\n",
              "    width: 32px;\n",
              "  }\n",
              "\n",
              "  .colab-df-quickchart:hover {\n",
              "    background-color: var(--hover-bg-color);\n",
              "    box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
              "    fill: var(--button-hover-fill-color);\n",
              "  }\n",
              "\n",
              "  .colab-df-quickchart-complete:disabled,\n",
              "  .colab-df-quickchart-complete:disabled:hover {\n",
              "    background-color: var(--disabled-bg-color);\n",
              "    fill: var(--disabled-fill-color);\n",
              "    box-shadow: none;\n",
              "  }\n",
              "\n",
              "  .colab-df-spinner {\n",
              "    border: 2px solid var(--fill-color);\n",
              "    border-color: transparent;\n",
              "    border-bottom-color: var(--fill-color);\n",
              "    animation:\n",
              "      spin 1s steps(1) infinite;\n",
              "  }\n",
              "\n",
              "  @keyframes spin {\n",
              "    0% {\n",
              "      border-color: transparent;\n",
              "      border-bottom-color: var(--fill-color);\n",
              "      border-left-color: var(--fill-color);\n",
              "    }\n",
              "    20% {\n",
              "      border-color: transparent;\n",
              "      border-left-color: var(--fill-color);\n",
              "      border-top-color: var(--fill-color);\n",
              "    }\n",
              "    30% {\n",
              "      border-color: transparent;\n",
              "      border-left-color: var(--fill-color);\n",
              "      border-top-color: var(--fill-color);\n",
              "      border-right-color: var(--fill-color);\n",
              "    }\n",
              "    40% {\n",
              "      border-color: transparent;\n",
              "      border-right-color: var(--fill-color);\n",
              "      border-top-color: var(--fill-color);\n",
              "    }\n",
              "    60% {\n",
              "      border-color: transparent;\n",
              "      border-right-color: var(--fill-color);\n",
              "    }\n",
              "    80% {\n",
              "      border-color: transparent;\n",
              "      border-right-color: var(--fill-color);\n",
              "      border-bottom-color: var(--fill-color);\n",
              "    }\n",
              "    90% {\n",
              "      border-color: transparent;\n",
              "      border-bottom-color: var(--fill-color);\n",
              "    }\n",
              "  }\n",
              "</style>\n",
              "\n",
              "  <script>\n",
              "    async function quickchart(key) {\n",
              "      const quickchartButtonEl =\n",
              "        document.querySelector('#' + key + ' button');\n",
              "      quickchartButtonEl.disabled = true;  // To prevent multiple clicks.\n",
              "      quickchartButtonEl.classList.add('colab-df-spinner');\n",
              "      try {\n",
              "        const charts = await google.colab.kernel.invokeFunction(\n",
              "            'suggestCharts', [key], {});\n",
              "      } catch (error) {\n",
              "        console.error('Error during call to suggestCharts:', error);\n",
              "      }\n",
              "      quickchartButtonEl.classList.remove('colab-df-spinner');\n",
              "      quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n",
              "    }\n",
              "    (() => {\n",
              "      let quickchartButtonEl =\n",
              "        document.querySelector('#df-8800d2ac-6e65-41ca-9b7b-6cc45a01e535 button');\n",
              "      quickchartButtonEl.style.display =\n",
              "        google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
              "    })();\n",
              "  </script>\n",
              "</div>\n",
              "\n",
              "    </div>\n",
              "  </div>\n"
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "dataframe",
              "variable_name": "assesment_df",
              "summary": "{\n  \"name\": \"assesment_df\",\n  \"rows\": 170,\n  \"fields\": [\n    {\n      \"column\": \"title\",\n      \"properties\": {\n        \"dtype\": \"category\",\n        \"num_unique_values\": 16,\n        \"samples\": [\n          \"\\u5de5\\u696d\\u6570\\u5b66\\u2160\",\n          \"\\u6280\\u8853\\u8005\\u306e\\u502b\\u7406\",\n          \"\\u30a2\\u30eb\\u30b4\\u30ea\\u30ba\\u30e0\\u3068\\u30c7\\u30fc\\u30bf\\u69cb\\u9020\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"grade\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 0,\n        \"min\": 1,\n        \"max\": 3,\n        \"num_unique_values\": 3,\n        \"samples\": [\n          1,\n          2,\n          3\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"required\",\n      \"properties\": {\n        \"dtype\": \"boolean\",\n        \"num_unique_values\": 2,\n        \"samples\": [\n          false,\n          true\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"q_id\",\n      \"properties\": {\n        \"dtype\": \"category\",\n        \"num_unique_values\": 5,\n        \"samples\": [\n          \"Q21 (2)\",\n          \"Q22\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"comment\",\n      \"properties\": {\n        \"dtype\": \"string\",\n        \"num_unique_values\": 153,\n        \"samples\": [\n          \"\\u30fb\\u6559\\u79d1\\u66f8\\u304c\\u5fc5\\u8981\\u306a\\u306e\\u304b\\u5fc5\\u8981\\u3067\\u306a\\u3044\\u306e\\u304b\\u304c\\u66d6\\u6627\\u306a\\u307e\\u307e\\u6388\\u696d\\u304c\\u59cb\\u307e\\u308a\\u3001\\u975e\\u5e38\\u306b\\u4e0d\\u5b89\\u3060\\u3063\\u305f\\u305f\\u3081\\u3001\\u6559\\u79d1\\u66f8\\u304c\\u5fc5\\u9808\\u304b\\u305d\\u3046\\u3067\\u306a\\u3044\\u306e\\u304b\\u306f\\u6700\\u521d\\u306b\\u306f\\u3063\\u304d\\u308a\\u3057\\u3066\\u6b32\\u3057\\u3044\\u3002\\n\\u30fb\\u8ab2\\u984c\\u3092\\u51fa\\u3059\\u3060\\u3051\\u51fa\\u3055\\u305b\\u3066\\u304a\\u3044\\u3066\\u3001\\u63a1\\u70b9\\u3082\\u305b\\u305a\\u3001\\u3069\\u3046\\u3044\\u3063\\u305f\\u89e3\\u7b54\\u304c\\u6b63\\u3057\\u3044\\u306e\\u304b\\u3068\\u3044\\u3063\\u305f\\u6307\\u91dd\\u3082\\u51fa\\u3059\\u306e\\u304c\\u3068\\u3066\\u3082\\u9045\\u3044\\u3002\\u8ab2\\u984c\\u306f\\u89e3\\u304f\\u3060\\u3051\\u3067\\u306f\\u77e5\\u8b58\\u306e\\u5b9a\\u7740\\u306b\\u3064\\u306a\\u304c\\u3089\\u306a\\u3044\\u3068\\u601d\\u3044\\u307e\\u3059\\u304c\\u3001\\u305d\\u3053\\u3089\\u3078\\u3093\\u306f\\u3069\\u3046\\u306a\\u3093\\u3067\\u3057\\u3087\\u3046\\u304b\\u3002\\n\\u30fb\\u914d\\u5e03\\u8cc7\\u6599\\u3068\\u3057\\u3066\\u3001\\u904e\\u53bb\\u554f\\u3082\\u914d\\u5e03\\u3057\\u3066\\u304f\\u308c\\u308b\\u3068\\u3068\\u3066\\u3082\\u52a9\\u304b\\u308b\\u306a\\u3001\\u3068\\u601d\\u3044\\u307e\\u3059\\u3002\\u3054\\u691c\\u8a0e\\u304a\\u9858\\u3044\\u3057\\u307e\\u3059\\u3002\",\n          \"\\u30fb\\u4e2d\\u9593\\u30c6\\u30b9\\u30c8\\u3092\\u5ef6\\u671f\\u3057\\u7d9a\\u3051\\u3001\\u6700\\u7d42\\u7684\\u306b\\u4e2d\\u9593\\u30fb\\u671f\\u672b\\u8a66\\u9a13\\u3092\\uff12\\u9031\\u7d9a\\u3051\\u3066\\u3084\\u308b\\u3053\\u3068\\u3068\\u306a\\u308a\\u3001\\u8a08\\u753b\\u6027\\u304c\\u6b20\\u3051\\u3066\\u3044\\u308b\\u3002\\n\\u30fb\\u914d\\u5e03\\u8cc7\\u6599\\u306e\\u8aa4\\u5b57\\u8131\\u5b57\\u304c\\u591a\\u3059\\u304e\\u308b\\u3002\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"wakati1\",\n      \"properties\": {\n        \"dtype\": \"string\",\n        \"num_unique_values\": 153,\n        \"samples\": [\n          \"\\u30fb \\u6559\\u79d1\\u66f8 \\u304c \\u5fc5\\u8981 \\u306a \\u306e \\u304b \\u5fc5\\u8981 \\u3067 \\u306a\\u3044 \\u306e \\u304b \\u304c \\u66d6\\u6627 \\u306a \\u307e\\u307e \\u6388\\u696d \\u304c \\u59cb\\u307e\\u308a \\u3001 \\u975e\\u5e38 \\u306b \\u4e0d\\u5b89 \\u3060\\u3063 \\u305f \\u305f\\u3081 \\u3001 \\u6559\\u79d1\\u66f8 \\u304c \\u5fc5\\u9808 \\u304b \\u305d\\u3046 \\u3067 \\u306a\\u3044 \\u306e \\u304b \\u306f \\u6700\\u521d \\u306b \\u306f\\u3063\\u304d\\u308a \\u3057 \\u3066 \\u6b32\\u3057\\u3044 \\u3002 \\n \\u30fb \\u8ab2\\u984c \\u3092 \\u51fa\\u3059 \\u3060\\u3051 \\u51fa\\u3055 \\u305b \\u3066 \\u304a\\u3044 \\u3066 \\u3001 \\u63a1\\u70b9 \\u3082 \\u305b \\u305a \\u3001 \\u3069\\u3046 \\u3044\\u3063 \\u305f \\u89e3\\u7b54 \\u304c \\u6b63\\u3057\\u3044 \\u306e \\u304b \\u3068\\u3044\\u3063\\u305f \\u6307\\u91dd \\u3082 \\u51fa\\u3059 \\u306e \\u304c \\u3068\\u3066\\u3082 \\u9045\\u3044 \\u3002 \\u8ab2\\u984c \\u306f \\u89e3\\u304f \\u3060\\u3051 \\u3067 \\u306f \\u77e5\\u8b58 \\u306e \\u5b9a\\u7740 \\u306b \\u3064\\u306a\\u304c\\u3089 \\u306a\\u3044 \\u3068 \\u601d\\u3044 \\u307e\\u3059 \\u304c \\u3001 \\u305d\\u3053\\u3089 \\u3078\\u3093 \\u306f \\u3069\\u3046 \\u306a \\u3093 \\u3067\\u3057\\u3087 \\u3046 \\u304b \\u3002 \\n \\u30fb \\u914d\\u5e03 \\u8cc7\\u6599 \\u3068\\u3057\\u3066 \\u3001 \\u904e\\u53bb\\u554f \\u3082 \\u914d\\u5e03 \\u3057 \\u3066 \\u304f\\u308c\\u308b \\u3068 \\u3068\\u3066\\u3082 \\u52a9\\u304b\\u308b \\u306a \\u3001 \\u3068 \\u601d\\u3044 \\u307e\\u3059 \\u3002 \\u3054 \\u691c\\u8a0e \\u304a\\u9858\\u3044 \\u3057 \\u307e\\u3059 \\u3002\",\n          \"\\u30fb \\u4e2d\\u9593\\u30c6\\u30b9\\u30c8 \\u3092 \\u5ef6\\u671f \\u3057 \\u7d9a\\u3051 \\u3001 \\u6700\\u7d42\\u7684 \\u306b \\u4e2d\\u9593 \\u30fb \\u671f\\u672b\\u8a66\\u9a13 \\u3092 \\uff12 \\u9031 \\u7d9a\\u3051 \\u3066 \\u3084\\u308b \\u3053\\u3068 \\u3068 \\u306a\\u308a \\u3001 \\u8a08\\u753b \\u6027 \\u304c \\u6b20\\u3051 \\u3066 \\u3044\\u308b \\u3002 \\n \\u30fb \\u914d\\u5e03 \\u8cc7\\u6599 \\u306e \\u8aa4\\u5b57\\u8131\\u5b57 \\u304c \\u591a \\u3059\\u304e\\u308b \\u3002\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"wakati2\",\n      \"properties\": {\n        \"dtype\": \"string\",\n        \"num_unique_values\": 153,\n        \"samples\": [\n          \"\\u30fb \\u6559\\u79d1\\u66f8 \\u304c \\u5fc5\\u8981 \\u3060 \\u306e \\u304b \\u5fc5\\u8981 \\u3060 \\u306a\\u3044 \\u306e \\u304b \\u304c \\u66d6\\u6627 \\u3060 \\u307e\\u307e \\u6388\\u696d \\u304c \\u59cb\\u307e\\u308b \\u3001 \\u975e\\u5e38 \\u306b \\u4e0d\\u5b89 \\u3060 \\u305f \\u305f\\u3081 \\u3001 \\u6559\\u79d1\\u66f8 \\u304c \\u5fc5\\u9808 \\u304b \\u305d\\u3046 \\u3060 \\u306a\\u3044 \\u306e \\u304b \\u306f \\u6700\\u521d \\u306b \\u306f\\u3063\\u304d\\u308a \\u3059\\u308b \\u3066 \\u6b32\\u3057\\u3044 \\u3002 * \\u30fb \\u8ab2\\u984c \\u3092 \\u51fa\\u3059 \\u3060\\u3051 \\u51fa\\u3059 \\u305b\\u308b \\u3066 \\u304a\\u304f \\u3066 \\u3001 \\u63a1\\u70b9 \\u3082 \\u3059\\u308b \\u306c \\u3001 \\u3069\\u3046 \\u3044\\u3046 \\u305f \\u89e3\\u7b54 \\u304c \\u6b63\\u3057\\u3044 \\u306e \\u304b \\u3068\\u3044\\u3063\\u305f \\u6307\\u91dd \\u3082 \\u51fa\\u3059 \\u306e \\u304c \\u3068\\u3066\\u3082 \\u9045\\u3044 \\u3002 \\u8ab2\\u984c \\u306f \\u89e3\\u304f \\u3060\\u3051 \\u3060 \\u306f \\u77e5\\u8b58 \\u306e \\u5b9a\\u7740 \\u306b \\u3064\\u306a\\u304c\\u308b \\u306a\\u3044 \\u3068 \\u601d\\u3046 \\u307e\\u3059 \\u304c \\u3001 \\u305d\\u3053\\u3089 \\u3078\\u3093 \\u306f \\u3069\\u3046 \\u3060 \\u3093 \\u3067\\u3059 \\u3046 \\u304b \\u3002 * \\u30fb \\u914d\\u5e03 \\u8cc7\\u6599 \\u3068\\u3057\\u3066 \\u3001 \\u904e\\u53bb\\u554f \\u3082 \\u914d\\u5e03 \\u3059\\u308b \\u3066 \\u304f\\u308c\\u308b \\u3068 \\u3068\\u3066\\u3082 \\u52a9\\u304b\\u308b \\u306a \\u3001 \\u3068 \\u601d\\u3046 \\u307e\\u3059 \\u3002 \\u3054 \\u691c\\u8a0e \\u304a\\u9858\\u3044 \\u3059\\u308b \\u307e\\u3059 \\u3002\",\n          \"\\u30fb \\u4e2d\\u9593\\u30c6\\u30b9\\u30c8 \\u3092 \\u5ef6\\u671f \\u3059\\u308b \\u7d9a\\u3051\\u308b \\u3001 \\u6700\\u7d42\\u7684 \\u306b \\u4e2d\\u9593 \\u30fb \\u671f\\u672b\\u8a66\\u9a13 \\u3092 \\uff12 \\u9031 \\u7d9a\\u3051\\u308b \\u3066 \\u3084\\u308b \\u3053\\u3068 \\u3068 \\u306a\\u308b \\u3001 \\u8a08\\u753b \\u6027 \\u304c \\u6b20\\u3051\\u308b \\u3066 \\u3044\\u308b \\u3002 * \\u30fb \\u914d\\u5e03 \\u8cc7\\u6599 \\u306e \\u8aa4\\u5b57\\u8131\\u5b57 \\u304c \\u591a\\u3044 \\u3059\\u304e\\u308b \\u3002\"\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    },\n    {\n      \"column\": \"sentiment\",\n      \"properties\": {\n        \"dtype\": \"number\",\n        \"std\": 0,\n        \"min\": -1,\n        \"max\": 1,\n        \"num_unique_values\": 3,\n        \"samples\": [\n          0,\n          -1\n        ],\n        \"semantic_type\": \"\",\n        \"description\": \"\"\n      }\n    }\n  ]\n}"
            }
          },
          "metadata": {},
          "execution_count": 15
        }
      ],
      "source": [
        "import pandas as pd\n",
        "\n",
        "filename = \"r_assesment_sentiment.xlsx\"\n",
        "assesment_df = pd.read_excel(filename)\n",
        "assesment_df.head()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "metadata": {
        "id": "vSagALY6tRAU",
        "outputId": "d9f509c8-4172-4877-98f2-9afbca5f13aa",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "x_data[0]='特に なし', type(x_data[0])=<class 'str'>\n",
            "y_data[0]=0, type(y_data[0])=<class 'int'>\n"
          ]
        }
      ],
      "source": [
        "# サンプル0のwakati1列とsentiment列を確認\n",
        "\n",
        "x_data = list(assesment_df['wakati1'])\n",
        "y_data = list(assesment_df['sentiment'])\n",
        "\n",
        "print(f\"{x_data[0]=}, {type(x_data[0])=}\")\n",
        "print(f\"{y_data[0]=}, {type(y_data[0])=}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "metadata": {
        "id": "b4lGVKp2tRAU",
        "outputId": "c7b057a8-acb5-423f-ae7f-74954ccefa42",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "len(X_train)=136, len(y_train)=136\n",
            "len(X_test)=34, len(y_test)=34\n",
            "X_train[0]='python の 内容 は 予想 を 上回る ほど の 量 だっ た ので 、 まだ 理解度 が 完璧 と は 言え ない 状況 です 。 夏休み は 復習 を し て 、 ２ 学期 から また 新しい 言語 を 学ん で いき たい と 思い ます 。', y_train[0]=0\n"
          ]
        }
      ],
      "source": [
        "# 学習用データ、テスト用データに分割\n",
        "from sklearn.model_selection import train_test_split\n",
        "\n",
        "# train_size = 学習用データの割合。\n",
        "# random_state = 疑似乱数生成するためのシード値。\n",
        "#   シード値を固定しておくと「シャッフルするけど毎回同じシャッフル結果」を利用できる。\n",
        "#   結果を再現できるため、動作確認や失敗分析をし易い。\n",
        "# shuffle = シャッフするなら True。\n",
        "X_train, X_test, y_train, y_test = train_test_split(x_data, y_data, train_size=0.8, random_state=1, shuffle=True)\n",
        "print(f\"{len(X_train)=}, {len(y_train)=}\")\n",
        "print(f\"{len(X_test)=}, {len(y_test)=}\")\n",
        "print(f\"{X_train[0]=}, {y_train[0]=}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "j6lGb3DTtRAU"
      },
      "source": [
        "## B. 特徴抽出\n",
        "簡易的に特徴量関数を設計しています。本来なら次元毎に特徴量関数を用意し、次元毎の数値を定めて特徴ベクトルを設計します。しかしここでは簡易的な実装として以下のように処理しています。\n",
        "\n",
        "- step 1: 良い評価に用いられる単語群（good_words）、悪い評価に用いられる単語群（bad_words）を用意。\n",
        "- step 2: サンプル毎に good_words, bad_wordsの出現した回数をカウント。\n",
        "- step 3: それぞれの出現回数とバイアスを加えた3次元の特徴ベクトルを構築する。（実際には辞書として用意してるだけ）\n",
        "  - 例えばgood_words1回、bad_words0回、バイアスを1（デフォルトでほんのり良いとする）とすると、{\"good_word_count\": 1, \"bad_word_count\": 0, \"bias\":1} という辞書を構築する。ベクトル風に書くなら `1, 0, 1` の3次元の特徴ベクトルに相当する。\n",
        "\n",
        "これらの設計は主観のため、good_words, bad_wordsをそれぞれどのように用意するか、出現時に+1カウントアップするだけで良いのか、バイアスをどう設計すべきか、そもそも3次元で良いのか、、、といったことは「ひとまずこの設計でやった」にすぎない。この結果が満足いかない場合には、失敗要因分析を通じて再設計し改善を目指すことになる。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 18,
      "metadata": {
        "id": "AYmaIwOxtRAV",
        "outputId": "f4a25da2-41e9-4092-82eb-1123bf7e6eb2",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "features={'good_word_count': 1, 'bias': 1}: text='社会人 に 向け て の これから を 考える いい 機会 に なっ た ので よかっ た です 。'\n"
          ]
        }
      ],
      "source": [
        "def extract_features(x: str) -> dict[str, float]:\n",
        "    '''特徴抽出部：テキストを受け取り、指定した特徴抽出結果を辞書型で返す。\n",
        "\n",
        "    step 1: 句点（。）単位で処理するために文に分割する。\n",
        "    step 2: good_words や bad_words の出現回数をカウント。ただし完全一致ではなく、部分一致。\n",
        "    step 3: バイアスを設定。\n",
        "    '''\n",
        "    features = {}\n",
        "    x_split = x.split(' ') # step 1: 句点区切りで文に分割。\n",
        "\n",
        "    # step 2: 良い（悪い）評価に用いられる単語を列挙しておき、該当するたびにカウントする\n",
        "    good_words = ['よかっ', 'でき']\n",
        "    bad_words = ['ず', '難']\n",
        "    for x_word in x_split: # step 2: 文単位で上記指定語が含まれるたびにカウントアップ\n",
        "        if x_word in good_words:\n",
        "            features['good_word_count'] = features.get('good_word_count', 0) + 1\n",
        "        if x_word in bad_words:\n",
        "            features['bad_word_count'] = features.get('bad_word_count', 0) + 1\n",
        "\n",
        "    # step 3: デフォルトスコア用のバイアス値（固定）\n",
        "    features['bias'] = 1\n",
        "\n",
        "    return features\n",
        "\n",
        "# 実行例\n",
        "text = X_train[8]\n",
        "features = extract_features(text)\n",
        "print(f\"{features=}: {text=}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xaqvTkrPtRAV"
      },
      "source": [
        "## C. 分類器構築\n",
        "Bで設計した特徴ベクトルを元に「荷重和スコアが0を超えるなら1 (positive)、0未満なら-1 (negative)、それ以外なら0 (normal)」と判断する分類器を構築している。なお荷重和を求める工程では good_word_count, bad_word_count, bias それぞれ異なる重みを用意した上スコアを求めている。\n",
        "\n",
        "特徴抽出同様に、重みをどのように設計するか、荷重和スコアを元にどのように判定するかといった細かな部分は「ひとまずこの設計でやった」だけである。必要に応じてチューニングすることになる。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "metadata": {
        "id": "Z93ODAs3tRAV",
        "outputId": "c5bbb609-7d99-450c-c5ea-16919ce06858",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "score=0.5, estimated_label=1, true_label=0, X_train[i]='python の 内容 は 予想 を 上回る ほど の 量 だっ た ので 、 まだ 理解度 が 完璧 と は 言え ない 状況 です 。 夏休み は 復習 を し て 、 ２ 学期 から また 新しい 言語 を 学ん で いき たい と 思い ます 。'\n",
            "score=0.5, estimated_label=1, true_label=0, X_train[i]='特に なし'\n",
            "score=0.5, estimated_label=1, true_label=1, X_train[i]='配布 資料 が 教科書 の 内容 に 沿っ て おり 、 わかり やすかっ た 。'\n",
            "score=0.5, estimated_label=1, true_label=1, X_train[i]='Zoom の 音声 、 資料 画像 の 画質 など 特に 問題 なく 授業 を 受け られ た 。'\n",
            "score=0.5, estimated_label=1, true_label=-1, X_train[i]='たまに 説明 が ない コード が あっ たり し た ので 少し 戸惑っ た 。 いずれ はやっ て いく もの で は ある が 、 、 、'\n"
          ]
        }
      ],
      "source": [
        "# 良い（悪い）の単語に対する重み。バイアスにも重みを用意。\n",
        "feature_weights = {'good_word_count': 1.0, 'bad_word_count': -1.0, 'bias': 0.5}\n",
        "\n",
        "def run_classifier(x: str) -> tuple[int, float]:\n",
        "    '''入力されたテキストの極性を推定する。\n",
        "\n",
        "    入力 (x)：テキスト\n",
        "    出力1 (int): 推定ラベル: 良い評価(1)、悪い評価(-1)、どちらでもない(0)。\n",
        "    出力2 (score): 算出スコア。\n",
        "    '''\n",
        "    score = 0\n",
        "    for feat_name, feat_value in extract_features(x).items():\n",
        "        score = score + feat_value * feature_weights.get(feat_name, 0)\n",
        "    if score > 0:\n",
        "        return 1, score\n",
        "    elif score < 0:\n",
        "        return -1, score\n",
        "    else:\n",
        "        return 0, score\n",
        "\n",
        "for i in range(5):\n",
        "    estimated_label, score = run_classifier(X_train[i])\n",
        "    true_label = y_train[i]\n",
        "    print(f\"{score=}, {estimated_label=}, {true_label=}, {X_train[i]=}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7lUk8xPMtRAV"
      },
      "source": [
        "## D. 性能評価\n",
        "今回のモデルは学習を行わず、ルールベースで構築したシンプルなモデルである。そのためテストデータだけではなく学習データに対する評価も行っている。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "metadata": {
        "id": "GldZN2VutRAW",
        "outputId": "30c8ec57-9eca-483e-dcf9-5d96c328e0d3",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Train accuracy: 0.493\n",
            "Test accuracy: 0.529\n"
          ]
        }
      ],
      "source": [
        "def calculate_accuracy(x_data: list[str], y_data: list[int]) -> float:\n",
        "    '''推定結果の一致率を返す。\n",
        "\n",
        "    入力1 (x_data): テキスト群。\n",
        "    入職2 (y_data): 正解ラベル群。\n",
        "    出力 (float): 一致率。\n",
        "    '''\n",
        "    total_number = 0\n",
        "    correct_number = 0\n",
        "    for x, y in zip(x_data, y_data):\n",
        "        y_pred, score = run_classifier(x)\n",
        "        total_number += 1\n",
        "        if y == y_pred:\n",
        "            correct_number += 1\n",
        "    return correct_number / float(total_number)\n",
        "\n",
        "train_accuracy = calculate_accuracy(X_train, y_train) # 学習データに対する正解率\n",
        "test_accuracy = calculate_accuracy(X_test, y_test)    # テストデータに対する正解率\n",
        "print(f'Train accuracy: {train_accuracy:0.3f}')\n",
        "print(f'Test accuracy: {test_accuracy:0.3f}')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lhCpeqMItRAW"
      },
      "source": [
        "## E. 失敗分析\n",
        "学習データにおける失敗事例を観察し、性能向上のためにどのような工夫が行えそうか検討してみよう。\n",
        "\n",
        "- システム改善に向けて要因分析をする際に、テストデータを用いてはいけません。それは **リーク（Data Leakage）** になります。\n",
        "- なお以下では「失敗した事例をランダムに5件選ぶ」形で出力しています。一般的には全ての失敗事例を眺めるのは大変だからです。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "metadata": {
        "id": "TUOXB_cAtRAW",
        "outputId": "5efbb596-bfb4-446f-dbc4-8ce589834761",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "・ 資料 の 説明 で 色 ペン を 使う とき 、 資料 の 上 から 書く の を やめ て ほしい 。 字 が 汚い 上 に 、 資料 の 文字 と 重なっ て 読み づらい 。 \n",
            " ・ 予習 を し て 説明 を 聞い て も 、 何 を 言っ て いる か わから ない から 、 頭 に 入っ て こ ない 。 もう少し はっきり と 話し て ほしい 。\n",
            "true label: -1\n",
            "predicted label: 1\n",
            "\n",
            "python の 内容 は 予想 を 上回る ほど の 量 だっ た ので 、 まだ 理解度 が 完璧 と は 言え ない 状況 です 。 夏休み は 復習 を し て 、 ２ 学期 から また 新しい 言語 を 学ん で いき たい と 思い ます 。\n",
            "true label: 0\n",
            "predicted label: 1\n",
            "\n",
            "中間 ・ 期末 の レポート など の 提出 を メール で 行う の は 良い が 、 出来れ ば 受理 さ れ た か どう か の 確認 が できる 形 に し て いただき たい ( 成績評価 において 提出 物 の 割合 が 大きい ため 、 正しく 受理 さ れ た か どう か が 気 に なる )\n",
            "true label: -1\n",
            "predicted label: 1\n",
            "\n",
            "課題 の 点数 を 早め に 公開 し て もらえる と よかっ た と 思い ます 。 \n",
            " また 、 試験 に関して 疑問 点 を メール に 送っ て い た と 思い ます が 、 それ に 回答 し て いただける と よかっ た と 思い ます 。\n",
            "true label: -1\n",
            "predicted label: 1\n",
            "\n",
            "特に なし\n",
            "true label: 0\n",
            "predicted label: 1\n",
            "\n"
          ]
        }
      ],
      "source": [
        "import random\n",
        "def find_errors(x_data, y_data, num=5):\n",
        "    '''num件の失敗事例を出力する。\n",
        "    step 1: 指定されたデータセットに対する失敗事例ID集合 (error_ids) を作成。\n",
        "    step 2: error_idsからランダムに num 件選び、出力する。\n",
        "\n",
        "    NOTE: 乱数で選ばれる点に注意。\n",
        "    '''\n",
        "\n",
        "    # step 1: 指定されたデータセットに対する失敗事例ID集合 (error_ids) を作成。\n",
        "    error_ids = []\n",
        "    y_preds = []\n",
        "    for i, (x, y) in enumerate(zip(x_data, y_data)):\n",
        "        pred, score = run_classifier(x)\n",
        "        y_preds.append(pred)\n",
        "        if y != y_preds[-1]:\n",
        "            error_ids.append(i)\n",
        "\n",
        "    # step 2: error_idsからランダムに num 件選び、出力する。\n",
        "    for _ in range(num):\n",
        "        my_id = random.choice(error_ids)\n",
        "        x, y, y_pred = x_data[my_id], y_data[my_id], y_preds[my_id]\n",
        "        print(f'{x}\\ntrue label: {y}\\npredicted label: {y_pred}\\n')\n",
        "\n",
        "find_errors(X_train, y_train)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HP_YP-NAtRAW"
      },
      "source": [
        "## 難しいケース\n",
        "「これで良い」という万能な解決策はなく、状況に応じて「ベターな意思決定」をすることになる。\n",
        "\n",
        "### 難しいケース1: 低出現語 （low frequency words)\n",
        "- 状況: コーパス内にそもそも殆ど出現していない。\n",
        "- 対応策？\n",
        "    - 全ての失敗事例についてシステム更新し続ける？\n",
        "    - 他資源（例えば商品レビュー）を用いて出現回数を増加させる？"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "metadata": {
        "id": "z7CxqOt7tRAW",
        "outputId": "3c1b3692-8edf-4e41-cbf9-acf201323aee",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "[('た', 329), ('が', 259), ('の', 248), ('。', 229), ('て', 201)]"
            ]
          },
          "metadata": {},
          "execution_count": 22
        }
      ],
      "source": [
        "from collections import Counter\n",
        "\n",
        "comments = assesment_df['wakati1']\n",
        "all_comments = ' '.join(comments)\n",
        "splited_comments = all_comments.split(' ')\n",
        "counts = Counter(splited_comments)\n",
        "counts.most_common(5)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 23,
      "metadata": {
        "id": "KM8a3WzEtRAX",
        "outputId": "772883fc-9bf0-4823-c7fd-135e1777e273",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "[('！', 1),\n",
              " ('つい', 1),\n",
              " ('試し', 1),\n",
              " ('フレームワーク', 1),\n",
              " ('いろんな', 1),\n",
              " ('もらっ', 1),\n",
              " ('コーディング', 1),\n",
              " ('GitHub', 1),\n",
              " ('チーム', 1),\n",
              " ('アプリケーション', 1),\n",
              " ('JavaScript', 1),\n",
              " ('CSS', 1),\n",
              " ('/', 1),\n",
              " ('HTML', 1),\n",
              " ('モバイルアプリ', 1),\n",
              " ('ほう', 1),\n",
              " ('会', 1),\n",
              " ('報告', 1),\n",
              " ('どちら', 1),\n",
              " ('焼き', 1)]"
            ]
          },
          "metadata": {},
          "execution_count": 23
        }
      ],
      "source": [
        "# 低出現語\n",
        "counts.most_common()[::-1][:20]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7SESakiDtRAX"
      },
      "source": [
        "### 難しいケース2: 活用する語\n",
        "- 状況: 動詞、形容詞、形容動詞、助動詞といった「活用により変化する語」のため、ルール追加しても漏れが出てしまう。\n",
        "- 対応策？\n",
        "    - 原型を利用する？\n",
        "        - 言語ごとに固有の形態素解析が必要。\n",
        "        - 参考: 日本語の代表的な形態素解析器: [2019年末版 形態素解析器の比較](https://qiita.com/hi-asano/items/aaf406db875f1c81530e)\n",
        "        - 精度は100%ではないし、目的によっては「自分にとっては不適切な処理」をすることもあることに注意。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "metadata": {
        "id": "bZ9K3Oh6tRAX",
        "outputId": "500350d1-df9a-4043-b5cd-375fb2813bc0",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "まだ １ 年 次 という こと も あり 、 特に 難しく なく て よかっ た です 。\n",
            "難しかっ た です\n",
            "この 講義 の おかげ で 、 周り の 人 と 話す こと が でき た ので とても よかっ た です 。 この 講義 が なけれ ば 私 は 前期 の 間 で 友達 を 作る こと は 難しかっ た の で は ない か と 思い ます 。 また 、 企業 人 インタビュー や 履修 計画 表 作成 を通して 自分 の 将来 を 見通す こと が でき た の は とても 大きい です 。 この よう な 機会 を 設け て くださ り ありがとう ござい まし た 。\n",
            "プログラミング を 全く 触っ た こと が なかっ た ので とても 難しかっ た 。\n",
            "課題 は 学び はじめ にとって は 難しかっ た けど 達成感 は GOOD\n",
            "比較的 人気 で 修得 が 簡単 な python で すら この 難し さ なら 、 先 が 思いやら れ ます 。\n",
            "課題 について は 解答 と 解説 が しばらく 明示 さ れ ず 、 解答 自体 は 試験 の 1 , 2週間 ほど 前 に 公開 さ れ た ものの 解説 が ない ため 理解 が し づらかっ た です 。 \n",
            " 試験 について は 、 特に 期末試験 について な の です が 、 大半 の 人 が 勉強 でき て い ない で あろ う 分野 の 問題 が 出さ れ た という こと と 問題 の 量 が それなり に 多かっ た ため に 非常 に 難しく 感じ まし た 。 実際 の クラス 平均 点 も 低かっ た です 。 \n",
            " また 、 中間試験 と 期末試験 を 2週 連続 で 実施 する の は 来年以降 の 授業 で は やめ て いただき たい です 。 どうしても 対面 で 実施 でき ない の なら すぐ に オンライン に 切り替え て 中間試験 の 期間内 に 実施 する べき だ と 思い ます 。 大変 でし た 。 \n",
            " 最後 に 課題 と 試験 に 評価 方法 な の です が 、 webclass で の 完全 解答 型 の ため 採点 が 少し 厳しい と 感じ まし た 。 そこ も できれ ば 何らかの 形 で 改善 し て いただける と いい と 思い ます 。\n",
            "・ 課題 の 点数 が 、 この 講義 が 全て 終わっ た のに 未だ すべて 採点 さ れ て い ない 点 が 不服 。 受講 者 が 多い だ とか 、 採点 する 側 も 忙しい だ と か 色々 ある と 思い ます が 、 そもそも 採点 する 側 が 捌き きれ ない ほど 課題 を 出し て いる という 現状 は 適切 でしょ う か 。 \n",
            " ・ 自身 の 努力 不足 かも しれ ませ ん が 、 率直 に 言っ て 試験 の 難易度 が 難しい 。 課題 で 解い た 問題 と 比べ て も 難易度 が 数 段 違う と 思い ます 。 この 授業 で は 「 配布 資料 」 「 課題 」 「 普段 の 講義 」 が 主 に 提供 さ れ まし た が 、 それら を 用い て 勉強 を し 、 また 足り ない と 思っ た ところ を 自分 で 調べ て 学習 し て も 、 試験 で 思う よう な 点 が 取れ ませ ん でし た 。 なので 試験 難易度 の 高さ に は 不満 が 残り ます 。 \n",
            " ・ 評価 方法 の 課題 20% 、 テスト 40 + 40 = 80% は 他 の 授業 で も よく 見 られる 配分 な ので 、 それ 自体 に は 不満 は あり ませ ん 。 しかし 、 先 ほど 書い た 通り 、 課題 が 採点 さ れ ない 点 や 、 試験 の 難易度 に 不満 が ある ため 、 結果的 に この 配分 も 良く ない の で は ない か 、 と 思い ます 。\n",
            "試験 内容 に 初めて 見る 問題 が あっ た ． さらに その後 の 解説 も あまり なかっ た ので 難易度 が 他 の 授業 に 比べ て 高 すぎる と 感じ まし た ． それ は ， 内容 が 難しい と いう より も 授業 で 試験 に 出る 内容 を 網羅 し 切れ て い ない こと による もの と 思い まし た ． 遠隔 の 試験 で あっ た こと が 大きい という こと は 重々 承知 の 上 で ， 問題 内容 が 伝わり 辛かっ た ので 他 の 授業 の よう に どうにか 対応 し て 欲しかっ た です ． また ， 平均 点 が 他 の 授業 と 比べ て 低 すぎる ので 追加 で 課題 など が 欲しかっ た です ．\n",
            "講義 全体 の 感想 として は 、 毎年 単位 を 落とす 人 が 多い という の も 納得 できる 難し さ だっ た と 思い ます 。 生徒 にとって 不親切 な 点 が 多く 、 本当に 前年度 まで の 生徒 から の 要望 は ちゃんと 取り入れ られ て いる の だろ う か と 疑問 に 思い まし た 。 \n",
            " 講義 の 難易度 を 簡単 に し て ほしい という わけ で は なく 、 今後 少し でも 生徒 に 親切 な 授業 に し て もらえれ ば 単位 も 取り やすく なる の か な という 風 に 感じ まし た 。 \n",
            " 講義 で 学ん だ 内容 自体 は とても 良かっ た です 。\n",
            "・ この 授業 は 単位 を 落とす 学生 が 多い と 聞い た が 、 その 通り だ と 思う 。 先生 の 説明 が 、 予習 を し て い て も わかり づらい し 、 課題 ・ 試験 の 内容 も 難しい 。 \n",
            " ・ 課題 の 採点 が まだ さ れ て い ない 。 忙しい の は 学生 皆 承知 し て いる が 、 5月 出し た 課題 で すら 採点 さ れ て い ない の は いかが な もの か と 思う 。\n",
            "朝 から ２ 時間 連続 で 非常 に 大変 で 、 内容 も 難しかっ た が 、 先生 の 教え 方 も 人柄 も 良かっ た おかげ で 、 最後 まで 乗り越え られ た と 思う 。\n",
            "講義 を通して 、 確率統計 に関する 知識 を 獲得 する こと が でき た と 思い ます 。 これら の 知識 を 利用 し て 個人的 に 実験 し て み たい こと も 出来 た ので 、 講義 を 受け て 良かっ た なぁ と しみじみ 思い ます 。 \n",
            " 自分 は 数学 は 普通 〜 やや 得意 な 方 です が 、 難易度 は 「 難しい が 勉強 すれ ば 必要 な 知識 を 獲得 できる 」 という ちょうど 良い 難易度 でし た 。 先生 の 説明 も 分かり やすく 、 また 、 たびたび 実際 に これら の 知識 を どう 使う の か 、 という 実践 的 な 面 で も お話 が 聞け て とても 面白かっ た です 。 \n",
            " ありがとう ござい まし た\n",
            "講義 中 は 内容 が 難しく 感じ て い た が 、 後日 見返し たり する と 理解 でき た こと が よく あっ た 。 \n",
            " 今後 の 研究 など を 踏まえ た 講義 を し て くれ た ので 、 ため に なる こと が 多かっ た 。\n",
            "課題 が 難しい もの が 多く 、 時間 を 多く とっ て もらえ た の は 非常 に 良かっ た です が かなり きつかっ た です 。 ありがとう ござい まし た 。\n"
          ]
        }
      ],
      "source": [
        "for word in comments:\n",
        "    if '難し' in word:\n",
        "        print(word)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fYAJomFZtRAX"
      },
      "source": [
        "### 難しいケース3：否定\n",
        "- 状況：否定語により極性が反転することがある。\n",
        "    - ``まだ １ 年 次 という こと も あり 、 特に 難しく なく て よかっ た です 。``\n",
        "- 対応策？\n",
        "    - 否定語が何に係っているかを推定する？ => 構文解析\n",
        "    - 参考: [自然言語処理用語と解析器まとめ](https://qiita.com/yura/items/6c1481ca652d3d131e47)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "U_3qlI7rtRAX"
      },
      "source": [
        "### 難しいケース4: 暗喩、例え\n",
        "- ``思わずクソゲーと叫びたくなるような難易度``\n",
        "    - 「難」という単語があるのでそれだけで negative 判断しやすいが、どのぐらい negative かという度合いを図ろうとすると難しい。\n",
        "- 他の例\n",
        "    - ``猫に小判``, ``花より男子``\n",
        "    - ``it's a piece of cake``\n",
        "    - [オノマトペ](https://www2.ninjal.ac.jp/Onomatope/category.html)\n",
        "        - ``さらさらとした髪``\n",
        "- 対応策？\n",
        "    - ？？？"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "metadata": {
        "id": "Ns0e7FsQtRAX"
      },
      "outputs": [],
      "source": []
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "dm",
      "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.9.6"
    },
    "colab": {
      "provenance": [],
      "toc_visible": true
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}