Monoxer Intern Report #17_CSV Data Export機能の追加と改善

自己紹介

モノグサの春インターンに2ヶ月間参加した中尾です。春から立命館大学の学部3年生です。普段は技術書や技術記事を読んだりしています。今回は遠方からの参加ということで、最初と最後に1週間強ほどずつ出社し、他はリモートでの勤務となっていました。

参加を決めた理由

春のインターン生をAtCoderJobsで募集しているというポストをXでみた友人に教えてもらって存在を知りました。AtCoder自体は最近はやっていなかったのですが、半年ほど夢中で取り組んでいたので深い思い入れがありましたし、モノグサに関してもAtCoderをやっていた時に解説記事などでお世話になったけんちょんさんが入社したというポストを見たことがあったので、存在は知っていました。当時ちょうどインターンに参加したいと思って色々探していた私にはまさに渡りに船で、すぐに応募を決めました。モノグサのブログやインタビュー記事、ネットニュースなどを調べるにつれ、参加したいという思いは強まっていきました。そこで実際に面接を受けた結果、選考を通過することができ、参加することを決めました。

取り組んだこと

組織の管理者がユーザを管理するためのWeb管理ツールにある、CSV Data Export機能の追加や改善に取り組みました。 CSV Data Export機能とは、ユーザに関する情報をCSVファイル形式で出力できる機能です。ダウンロードしたCSVファイルをExcelに取り込んで、データを分析するために使用されます。現在は、一部の組織向けに限定で公開している機能です。 私が取り組んだ課題は主に3つあります。

記憶度の出力項目に所属クラス情報を追加する

課題背景

CSV Data Export機能に、ユーザの記憶度を出力できるものがあります。記憶度とは、学習するBookに対して、どのくらい記憶しているのかを表す指標です。組織の管理者は、情報が欲しいBookを選択して、組織に所属する各ユーザの選択されたBookに対する記憶度をCSVファイルとして出力することができます。 今まで、この機能に対して、各ユーザの「スクールID」「スクール名」「クラスID」「クラス名」などの所属クラスの情報が付属していませんでした。なので、所属クラスの情報を必要とする分析を行うためには、お客様自身で、出力したCSVファイルとユーザの所属クラスの情報を組み合わせる必要がありました。 また、「学習回数の出力」などの他の機能にはこれらのクラス情報が付属していたため、記憶度と他の機能の出力項目の違いをお客様に説明する必要もありました。 よって、この課題を解決することで、お客様の手間も省け、ビジネスチームがお客様に出力項目の違いを説明する必要もなくなります。

やったこと

フロントエンドの実装

「出力するCSVデータの項目」に所属クラス情報を追加しました。

記憶度の出力予約画面

バックエンドの実装

ユーザの「組織メンバーID」から所属クラス情報が取得できるMapを作成し、それを使って出力項目に追加していきました。

結果

実装箇所としてはあまり多くないのですが、ビジネスとしてはインパクトがあると考えられます。 記憶度の出力項目に所属クラスの情報が追加されたことで、お客様自身で所属クラスの情報を付与する手間がなくなりました。また、ビジネスチームも他の機能との出力項目の違いをお客様に説明する必要がなくなりました。

管理者週間アクティブ率を出力できるようにする

課題背景

管理者週間アクティブ率とは、1週間でWeb管理ツールを使用した管理者の割合を表すものです。塾現場では管理者を管理したいというニーズが高いため、この機能を追加することになりました。この機能は、Monoxerを導入した組織が、出力されたデータを基に管理者がきちんとWeb管理ツールを利用しているかを確認し、利用を促したりするために利用されます。

やったこと

フロントエンドの実装

「管理者アクティブ率の出力」というボタンを設置し、そこから出力予約画面に飛べるようにしました。

出力予約画面への遷移ボタン

出力予約画面では、集計する期間や集計対象を選択して、出力予約が行えるようにしました。Monoxerでは組織階層の下にスクール階層というものがあり、組織AにはスクールA, スクールB, スクールCがあるというようになっています。よって、集計対象としてスクールを選択することで、スクール単位での管理者のアクティブ率というのも出力できるようにしました。

出力予約画面

ちなみになぜ「出力」ではなく「出力予約」なのかというと、データの出力に時間がかかるからです。先ほど紹介した記憶度の出力だと、長い場合2時間半ほどかかるので、出力予約という形にして、CSVファイルが準備できたらダウンロードできるようにしています。

バックエンドの実装

こちらは2ステップあります。

  1. 出力予約リクエストの処理

    出力予約画面で選択されたパラメータを含むリクエストが飛んでくるので、それを処理します。任意の出力予約を処理するハンドラがあるので、そこに今回の機能の処理を追加する形になります。集計期間が意図された値か、集計対象が存在しているかなどをチェックして、OKであれば予約をDBに格納します。なぜDBに格納するかというと、CSVファイルの生成はバッチ処理で行う仕組みになっているためです。

  2. CSVファイルの生成

    こちらでは管理者のアクティブ率を計算するため必要なデータをDBから取得して、出力するデータを算出し、CSVファイルを生成します。 まず、管理者週間アクティブ率を計算するためには「組織の管理者一覧」と「対象期間の管理者のアクセスログ」が必要になるので、それらをDBから取得します。 次に、集計期間を1週間ごとに区切って、各期間でアクセスしていた管理者の数をカウントし、アクティブ率を計算します。 このようにして、「集計開始日」「集計終了日」「アクティブ率」をCSVデータとして出力します。

    以上が組織単位での管理者アクティブ率の出力方法です。スクール単位だともう少し処理が複雑になりますが、流れとしては同じです。

結果

管理者週間アクティブ率が出力できるようになったことで、Monoxerの利用実態についてデータに基づいた分析や利用の促進が可能になり、お客様の「組織の管理者を管理したい」というニーズを満たすことができました。

追加の実装箇所

実は、記憶度の出力項目に所属クラスの情報を追加する課題が終わった後に、大手のお客様が記憶度を出力しようとするとエラーになってしまう問題が発生しました。調査の結果、私が実装した箇所に不備があったことが発覚し、それを修正することで問題は解決しました。レビューはしっかりと行っていたのですが、それでも不備が入り込んでしまったことの原因として、CSVファイルを生成する関数にテストが存在しないことがありました。これらの関数は複雑な処理をしているため、レビューだけでバグを無くすのは困難です。よって、今回の管理者週間アクティブ率を出力する関数にはテストを追加することにしました。結果として不備が2つ見つかり、そのうちの1つは実際にアクティブ率の計算結果に影響を及ぼす可能性のあるものでした。このように、早期に不備に対応することができ、他のCSVファイル生成関数にもテストを追加する足がかりを作ることができたのは、地味ではありますが今回のインターンの中でも重要な成果であると思っています。

出力項目に属性情報を追加できるようにする

課題背景

属性情報とは、「学年」「出席番号」「校舎」「選択科目」など、組織で個別に設定できるユーザに関する情報のことです。現状では、これらをCSVファイルの項目に追加することができません。よって、これらの情報を用いて分析を行いたい場合は、お客様自身でCSVファイルとアカウント情報を組み合わせる必要があります。このような作業は二度手間です。また、そもそもCSVファイルを分析ではなく表のように扱いたい小規模な組織のお客様にとっては、完全に手作業で属性情報を付与していくことによってミスをしてしまう危険性もあります。 よって、この課題を解決することで、お客様の苦しみを解決することができます。

やったこと

Design Docの執筆

機能の要件を満たす上で、どの方針にどんなメリット、デメリットがあるのかを記述し、どれをなぜ採用したのか。不安要素は何で、それは実際に問題となるのか。などを記述しました。 例えば、属性選択のコンポーネントのデザインで以下の3つが良い方針として浮かび上がりました。

  • 画面スクロール
    • メリット
      • ページに比べて操作が楽
    • デメリット
      • 既存の基盤コンポーネントがなく、新たに実装する必要がある
      • デザインを工夫しないと、スクロールできることがわかりづらい
      • Web管理ツールのターゲットによっては、必ずしもスクロールが使いやすいデザインであるとは限らない

スクロールでの選択画面

  • ページネーション
    • メリット
      • 既存の基盤コンポーネントが使用できる
      • 操作方法がわかりやすい
      • デザインとして見栄えが良い
    • デメリット
      • ページ遷移の操作がやや面倒
      • 表示件数を増やすと、縦に伸びて画面を占有してしまう
      • 属性の追加は必須項目でないのに、画面の占有率が高く、存在感が大きい

ページネーションでの選択画面

  • Modal&ページネーション
    • メリット
      • 既存の基盤コンポーネントが使用できる
      • 操作方法がわかりやすい
      • 表示件数を増やしても予約画面には影響がない
    • デメリット
      • ページ遷移の操作がやや面倒
      • デザインとして単純なページネーションに比べて、見栄えが悪い

Modal&ページネーションでの選択画面

このように、それぞれの方法のメリットデメリットを検討し、結果としてModal&ページネーションを採用しました。特に単純なページネーションではなくModalを採用した理由としては、「属性の追加は必須項目でないのに、画面の占有率が高く、存在感が大きい」がクリティカルでした。 最初私はスクロールを推していましたが、「Web管理ツールのターゲットによっては、必ずしもスクロールが良いデザインであるとは限らない」というのは考えられておらず、人によって良いデザインは異なるかもしれないというのは私にとって深い学びになりました。

他にも、出力項目に属性を追加する必要があるのですが、無制限に追加できるようにするとデザインが崩れてしまう恐れがあります。よって、以下の2つの案を検討しました。

  • 選択数に制限を持たせる
    • メリット
      • 何が追加されるのか明確にわかる
    • デメリット
      • 制限を持たせることによって、お客様が不便に思うケースが生じる可能性がある
  • 「選択された属性情報」などの表現で代替
    • メリット
      • 選択数に制限がない
    • デメリット
      • 何が追加されるのかが明確に表現できない

これに関してはビジネス側とも連携をとって、どのくらいの選択数が必要かを確認しました。すると、5つあれば十分との回答がありました。また、選択数に制限を持たせることでCSVファイルのサイズも抑えられるので、この方針に決定しました。このように、ビジネスの都合だったり、付随する問題についても考慮して設計を行うのは面白いなと思いました。

フロントエンドの実装

予約画面で追加する属性を選択できるようにしました。 選択し直す際に選択している項目が上にくるようにしたり、検索ボタンをなくして入力するだけで動的に検索結果が表示されるようにするなど、お客様が使いやすいよう工夫しました。

出力予約画面での追加する属性の選択ボタン

追加する属性の選択Modal

バックエンドの実装

管理者週間アクティブ率の出力と流れとしては同じです。

  1. 出力予約リクエストの処理

    選択された属性の数が制限を超えていないか、選択された属性が本当にその組織に存在するのかなどをチェックします。OKであれば予約をDBに格納します。

  2. CSVファイルの生成

    選択された属性の情報、組織のメンバーに対する属性の値をDBから取得します。ユーザの「組織のメンバーID」から属性の値の配列が取得できるMapを作成し、それを使って出力項目に追加していきました。

結果

属性情報を出力項目に追加できるようになり、お客様が手作業で属性情報をCSVに付与する必要がなくなりました。これにより、簡単に属性情報を必要とする分析が可能になり、お客様の苦しみが解決されました!

インターンの感想

この2ヶ月間で、本当に様々なことを学ばせていただきました。開発の観点では、Design Docを書いて、実装をして、テストを書いて、レビューをいただいて修正するという開発の一連のプロセスを経験することができました。その経験を通して、レビューやテストの大切さ、設計をする上では様々なことを考慮しなければならないこと、どのようなコードを書くべきかなどを学ぶことができました。経験の観点では、実際に2ヶ月間チームの一員として働くことで、会社の雰囲気や仕事上のコミュニケーション、プロダクトに対してどのように人が関わっているかなど、仕事に対する具体的なイメージを持つことができました。また、開発をしていると設計や実装において意見がぶつかることがありますが、その時にきちんと自分の意見を伝え、相手の意図を汲み取って尊重し、お互いが気持ちよく合意を取れるように議論をするというのがとても大切だと思いましたし、そのような環境が構築できているモノグサは良い会社だなと思います。 このインターンを通して、エンジニアとしてとても成長できたと感じています。この経験を活かして、今後も成長できるように精進していきます。このような機会を提供してくださったモノグサの皆様に深く感謝を申し上げます。2ヶ月間ありがとうございました!

Monoxer Intern Report #16_文章分割確認ツールの開発

自己紹介

こんにちは。モノグサのソフトウェアエンジニアのインターンに参加した堤歩斗です。普段は東京都立大学でコンピュータサイエンスの学習をしています。モノグサでは1ヶ月半ほどインターンをしていました。 この記事ではインターンを振り返りモノグサで取り組んだことやインターン中のあれこれについて紹介したいと思います。

参加を決めた理由

モノグサを知ったのはICPC2022アジア横浜地区大会のスポンサーブースでお話を聞いたときでした。その他にもAtCoder上でモノグサプログラミングコンテストを開催していたり、CodeQUEENのスポンサーを務めるなど、モノグサは競技プログラミングに理解のある会社なのだなという印象を持っていました。 私は比較的長い期間で本格的な開発に携われるインターンに行ってみたいと思っていました。 そんな中、モノグサの春インターンを見つけました。モノグサのインターンは期間が1ヶ月以上と希望にマッチしており、大学の春休み期間に取り組むのにちょうど良いと思いました。さらに、応募の決め手となったのはAtCoderJobsでの要求ランクがC(AtCoderのレートが緑)でちょうど応募可能だったためです。競技プログラミングで得た機会を生かしてみようと思い応募しました。

取り組んだこと

色々なことに取り組みました。最初はiOSとAndroidのアプリ開発に触れました。そして最後にはwebフロントエンドからバックエンドの開発まで、幅広くフルスタックでの開発を体験できました。そんな中から今回はインターン中にメインで取り組んだテーマについて紹介します。

Monoxerでは、「文章記憶機能」を提供しています。文章記憶機能というのは以下のような機能で、

  • 試験勉強に必要な文章や歴史的に有名な詩、業務に必要なマニュアルやトークスクリプトなど、様々なシーンで記憶が必要な文章が存在しています。
  • モノグサでは、この「ミラーの法則」を参考にして、文章をチャンク(情報のかたまり)に分割したうえで、チャンクごとの記憶を促すための出題する機能を開発いたしました。

引用元:文章をチャンクに分割して記憶する「文章記憶機能」をリリース | Monoxer・解いて憶える記憶アプリ

今回私は文章記憶機能における問題作成時のチェックプロセスを自動化するツールの開発を行いました。

文章記憶機能では、覚えたい元の文章を分割することで問題を作成します。 今回自動化したいチェックプロセスというのは、元の文章を分割して出来た短い文章のブロック(図1のL1に相当)同士で類似したものがないかをチェックするというものです。

図1 文章記憶コンテンツの構造

なぜ、このようなチェックをする必要があったのでしょうか?それは類似したものがあった場合に問題の選択肢にそれらが同時に出現することがあるからです。(図2 似たような選択肢が出現するスクリーンショット)

図2 似たような選択肢が出現するスクリーンショット

このスクリーンショットでは「当社で確認し、」と「当社で確認した」という選択肢が同時に出現しています。この問題の正解は「当社で確認した」なのですが、「当社で確認し、」を選択しても良いように思えます。 このように似たような選択肢が出現すると、文章の内容を十分に記憶出来ているのに誤答と判定されてしまうという問題が発生します。

今回のケースではスクリーンショット中の「当社で確認し、」と「当社で確認した」のような表記揺れや文末の表現の違いがある文章を検出するだけでなく、「迅速に」と「素早く」といったような言い換え表現も検出したいという背景がありました。(図3 検出したい文章の例)

図3 検出したい文章の例

そこで、このチェックを自動で行うために、SentenceTransformerという自然言語処理ライブラリを用いました。

SentenceTransformerは、文などのテキストデータをベクトル表現に変換するためのライブラリです。SentenceTransformerのモデルは、文を入力として受け取り、固定長のベクトルにエンコードします。このベクトル表現を用いることで、文間の類似度を計算することが可能になります。すなわち、SentenceTransformerを用いると文レベルでの意味論的な情報を捉えることが出来ます。 *1

実際には単純にSentenceTransformerで文章の最小単位(図1のL1に相当)同士の類似度を計算するだけではなく、その文章を誤って選んだ場合にどうなるか?という部分を加味して判定するようにしました。具体的には、「正解の選択肢を選んだ場合に完成する元の文章」と「類似した誤答選択肢を選んだ場合に完成する類似した文章」の二つの類似度を計算することで、誤答選択肢として適切かどうかをより正確に判定できるようになりました。

また、このツールの使用者はエンジニアではなく社内のコンテンツを作成する方々になります。そのため、普段のコンテンツ作成で使用しているGoogle スプレッドシートからGUIでの操作が出来るようにしました。そこで、以下の2つを開発しました。

  • 類似度の計算処理等を実行するバックエンドAPI
  • APIを叩き、結果を視覚的に表示するGoogle スプレッドシートのアドオン

また、SentenceTransformerを使用するには、Pythonで提供されているライブラリを利用する必要があります。そのため、Pythonの実行環境が必要です。そこで今回はGCPのCloud Runへ新たにデプロイすることになりました。

Cloud Runはコンテナを直接実行できるマネージドな実行環境で、リクエストベースでの自動スケーリングが行われます。すなわち、リクエストがあった場合にのみ動作し、しばらくリクエストが無い場合にはスケールダウンされるということです。今回作成したいツールはコンスタントにリクエストがあるものではなく、コンテンツ作成の作業時という限られたタイミングでのみ使用できれば良いので、Cloud Runは最適な選択肢でした。さらに、Cloud Runではコンテナを直接実行できるので、実行環境の新規構築としては比較的簡単です。 *2

今回はインフラチームの方と連携しながら、必要な知識を学びつつ、Cloud Runのデプロイにかかるプロセスを習得しました。この過程で、Cloud Runの仕組み、コンテナ技術、GCPの基本操作など、クラウドインフラに関する幅広い知識が得られました。

また、SentenceTransformerを使用するに当たり、パフォーマンスと精度についても課題がありました。デプロイにおいては、これら二つの要素を最適化することが重要な挑戦となりました。応答時間と消費するリソースの改善を精度を犠牲にすることなく、実現する必要があります。そのために、モデルの軽量化やキャッシュの利用などを施しました。このプロセスを通じて、パフォーマンスと精度の間のバランスを取ることの難しさを学びました。

インターンの感想

今回のインターンでは本当に幅広い領域を扱わせていただきました。「どんな文章を検出するべきなのか」というプロダクト理解から、「デプロイやシステム構成」といったインフラ領域、さらにバックエンドとフロントエンドの一通りの実装などに取り組みました。その中で自分で考えた内容に対して様々な方面からレビューをいただき、一つの機能を完成させていくという一連のプロセスが体験できました。主体性を持って幅広い領域の開発を経験できたことは非常に興味深かったです。

さらに、本格的なコードレビューを受けてプロダクトに自身のPullRequestをマージするという経験は学生にはなかなか得られるものではなく、様々な学びがありました。また、PullRequestだけでなく、Design Docという開発にまつわる文書のレビューも社内から広く受けられるモノグサの文化に感心しました。

そして、モノグサでは非常に働きやすい環境が整っているなとも感じました。インターンの最初に支給されるPCのキーボード配列の希望調査があったときから、インターンを終える今日まで、社員のことを第一に考えていることを随所に感じました。

このインターン体験を通じて、幅広いスキルを身につけることができました。また、実務でのコードレビューやプロダクト開発の一端を担うなど、貴重な経験をさせていただき、成長できたと自負しています。技術的なスキルだけでなく、チームで働く重要性や、プロダクト開発の過程における細かな配慮を学ぶ機会もありました。最後に、この機会を提供してくださったモノグサの皆様に心から感謝を申し上げます。ありがとうございました。

Monoxer Intern Report #15_タブレットUIのレスポンシブ化

自己紹介

夏からモノグサでソフトウェアエンジニアインターンをしていました、筑波大学情報科学類一年の甲賀です。

参加を決めた理由

AtCoderのコンテストで会社の存在を知り、AtCoder Jobsの求人から応募しました。 X(Twitter)などで所属を公表している競技プログラマの社員の方がいることや、ハッカソン形式などではなく実務に近い形式で参加できるという点に魅力を感じ参加を決めました。

取り組んだこと

主にアプリUIのレスポンシブ化に取り組みました。 Monoxerのアプリは主に教育現場で使われていることもあり、利用者の過半数がタブレット(特にiPad)ユーザーです。しかし、当時のアプリのUIはタブレットでの表示に最適化されておらず、レイアウトが崩れてしまうことがありました。

私は主に、

  • ホーム画面
  • キーボード入力形式の問題の画面
  • 選択肢形式の問題の画面

の三つの画面についてUIの改善に取り組みました。

iOS版アプリのUIはstoryboardというファイルで管理されています。主にこのファイルにレイアウトについての制約を追加し、必要に応じてコードにも変更を加えていくといった形で開発を進めていきました。デザイナーの方とデザインを相談しながら、最終的には次のようなUIとなりました。

画面にしてみてみると単純ですが、映っているUIの他にも細かい機能や考慮する点が多く、アプリ開発の経験がなかったこともあり、思いの外大変で苦戦しました。 例として、上記のりんごの画像のように問題画像の横幅の最大長を制限する変更をする際、storyboardでは各制約にpriorityを設定でき、矛盾する制約がある場合などにはpriorityの高い制約が優先されます。そのため、単純に「画像の幅を⚪︎px以下にする」というような制約を追加しただけでは、すでにある他の制約が優先されてしまいうまく反映されないといったことが起こります。そのため、矛盾している他の制約を探してpriorityを下げる、もしくは矛盾しないよう制約の条件を変更する、などといった変更が必要でした。

また、メインで取り組んだタスクの他にも、様々な領域で細かいバグ修正といった開発をしました。結果的にはこれらのメインタスク以外のタスクがインターン期間の開発の1/3ほどを占めていた気もします。 Web、サーバー、アプリといった様々な領域で、触れた言語としてはSwift、Kotlin、Scalaと、幅広い分野に新しく触れることができ、とても勉強になりました。

インターンの感想

私は、このインターンに参加するまでは個人開発の経験しかなかったため、自分の書いたコードをちゃんとレビューしていただき、より良い設計方針を提案していただいたくなど、今後の開発やエンジニアとしてのキャリアに役立つような多くの経験を得ることができました。 また、多くの利用者の方の満足度に関わるインパクトの大きいタスクに取り組ませていただいたことが、開発のモチベーションにもつながった気がします。

メンターの方だけでなく、デザイナーの方や他のエンジニア、インターン生など色々な方と関わることができ、 ランチやボドゲなどにも誘っていただき楽しくインターン期間を終えることができました。ありがとうございました!

PG BATTLE 2023に参加して飛び賞をゲットした話

ソフトウェアエンジニアの@tobisatisより、競プロ部の活動報告をお届けします。

2023年10月21日に開催されたPG BATTLE 2023に参加しました。PG BATTLEは、同じ会社内や学校内の3人を1チームとして出場する競技プログラミングの団体戦です。2021年の大会から数えて3度目の参加となりました。

チーム結成

部員数が増えたこともあり、今回は6人で2チームを編成できました。アンケートに回答し、参加意欲の高い順、参加意欲が同じなら提出が早い順で、上から3の倍数人を集めるという手順でメンバーを決めました。チーム名とAtCoder(日本最大の競技プログラミングのサービス)での各メンバーの最高レベル(色)は次の通りです。

  • チーム1「モノグサでいこう」
  • チーム2「Monoxer Blues」

結果

両チームとも240点を記録し、企業の部184位中「モノグサでいこう」が14位、「Monoxer Blues」が20位でした。企業の部では130位までの10位ごと13チームにスポンサー賞が与えられ、「Monoxer Blues」が「国際ソフトウェア賞」を獲得しました。

「Monoxer Blues」、左からscrblbug、tamura2004、konayuki

国際ソフトウェア株式会社様、ありがとうございました!部員一同、この場にて御礼申し上げます。

問題の感想

問題と詳しい解説は、PG Battleの公式サイトに掲載されています。

ましゅまろ

「モノグサでいこう」のましゅまろで参加しました。言語はC#です。

  • 1問目、コイントス

(1/2)Nを求めます。Nが小さいので、1.0をN回2で割ることで十分小さい誤差の値を得られます。

  • 2問目、微分

x^で文字列を分割して数値を得て、問題文にある通りに計算をすればよいです。オーバーフローに注意しましょう。

  • 3問目、2進数と10進数

BigIntegerを使ってBを2進数から10進数に変換し、適当にゼロ埋めを行って文字列で比較しました。組み込みの文字列比較で正しい答えを得られるのですが、1度しか提出できない緊張感のため、本番では上の文字から1文字ずつ比較しました。

  • 4問目、ダンス

「L番目からR番目の人をすべて取り除く操作の数」という小問題を再帰的に解いていくことで求まります。小問題は、左端の人を誰とペアにするかを決めていくことでより小さい問題に帰着させます。状態数O(N2)、遷移O(N)よりO(N3)で解けます。やはり緊張しましたが、入出力例の4が大きいケースだったので、ある程度安心して提出できました。

本番提出コードの一部を掲載します。(NとSの入力、ライブラリを省略)

var v = new bool[n + 1, n + 1];
var f = new ModInt[n + 1, n + 1];
ModInt F(int x, int y)
{
    if (x >= y)
    {
        return 1;
    }
    if (v[x, y]) return f[x, y];
    ModInt res = 0;
    for (var i = x + 1; i < y; i += 2)
    {
        if (s[x] == s[i]) continue;
        var l1 = (i - x - 1) / 2;
        var l2 = (y - 1 - i) / 2;
        var w = F(x + 1, i) * F(i + 1, y);
        var h = (l2 + 1).H(l1 + 1);
        res += w * h;
    }
    v[x, y] = true;
    f[x, y] = res;
    return res;
}
var ans = F(0, n);
return ans;

終わりに

競プロ部の普段の活動としては、主にコンテスト後の感想や考察の共有をslackにて行っています。

興味を持っていただけましたら、ぜひ過去の記事もあわせてご覧ください!

Monoxer で作れる問題あれこれ

Monoxer Advent Calender 2023 22 日目の記事です。

モノグサで Software Engineer として働いている杉江です。学習コンテンツの作成や表示に関わる領域を中心に、Monoxer をアップデートするべく日々開発しております。

Monoxer では様々な形式の問題を出すことができます。技術的に面白い形式や機能もたくさんあります。そこで今回は、2023 年 12 月現在に対応している問題形式について書いていきます。「Monoxer ってこういう問題も出せるんだ!」「この機能おもしろい!」などなど発見があればうれしいです。

選択問題

一方が問い・他方が答えになっているような一問一答形式の問題集に取り組んだ方は多いのではないでしょうか? Monoxer ではそういった形式の問題を出すことができ、問題文・答えの選択肢・誤答の選択肢を指定して問題を作ります。画像や数式が選択肢になることもあります。

選択問題であっても、答えを直接入力させる回答方式になることもあり*1、選択肢の並びだけでなんとなく記憶してしまうことを防止しています。

ペアエントリ

表に英単語・裏に日本語が書かれている単語帳や、表にイラスト・裏に名前が書かれているフラッシュカードを思い浮かべてみてください。Monoxer のペアエントリでは、このような「モノとモノのペア」の記憶ができます。ペアのそれぞれの要素が、問題文にも回答にもなりうる点が、選択問題の形式とは異なっており特徴的です。

回答は手書きにも対応しており、アルファベットや漢字など、文字そのものを記憶したいときに役立ちます。

アルファベット手書き機能についての Tech Blog 記事もぜひご覧ください!

tech.monoxer.com

余談ですが、Monoxer のプロダクトはペアエントリの機能からスタートしました。その後はクライアントやユーザーの声を聞きながら、次々と新しい機能・学習形式を提供しています。

文章穴埋め

問題文の一部が欠けており、その部分を穴埋めする形式です。ひとつの文章に対して、穴埋めにしたい箇所は複数選ぶことができ、出題するごとに穴埋めすべき場所が変わります。

ディクテーション

音声を聴いて、その内容を一字一句書きとる形式です。 音声はテキストから自動で作れるため、教材を作る際はテキストだけを用意すればよく、手軽に教材を作ることができます!(用意した音声をアップロードして、それをお手本とすることもできます)

文章全体のディクテーションだけでなく、指定した部分のみを空欄にしたような、部分的なディクテーションにも対応できます。

文章全体のディクテーションの例部分的なディクテーションの例

スピーキング

ユーザーがデバイスに向かって話し、その結果を評価できる形式を指しています。学習後にお手本の音声を聴いて復習することもできます。

この形式もディクテーションと同じく、自前の音声をお手本として使うこともできますし、テキストからお手本の音声を自動で作ることもできます。

数式

数学や物理などの問題を想定した形式もサポートしています。スマホやタブレット上で、こういった教科の学習ができるのを新鮮に感じる方もいらっしゃるかもしれません。

問題文の部分は 2 本指でズームイン・ズームアウトができます。途中式などのメモを手書きで書くこともできます。このように、実際に手を動かして計算したり考察したりできるように工夫されています。

回答するときは、数式を手書きするか、キーボードで答えの数式を入力します。

手書き数式認識については、過去にも Tech Blog に記事を出しています。以下もぜひご覧ください!

tech.monoxer.com

tech.monoxer.com

文章記憶

文章をチャンク(情報のかたまり)に分割したうえで、チャンクごとの記憶を促すための出題する機能です。今年リリースされたばかりの新しい機能です!

試験勉強に必要な文章や歴史的に有名な詩、業務に必要なマニュアルやトークスクリプトなど、様々なシーンで活用できます。

corp.monoxer.com

Monoxer でさまざまな問題が出題できることが伝われば幸いです。Monoxer が今後も進化を続け、よりよい学習体験が提供できるように、これからも開発を頑張っていきたいです。

Monoxer Advent Calendar 2023

Monoxer Advent Calendar 2023では、開発、ビジネス、コーポレートの様々な職種のメンバーが毎日1つずつ記事を公開していく予定なので、是非明日以降もチェックしてください!

Monoxerのカレンダーページです。 qiita.com

またモノグサ株式会社では一緒に働く仲間を募集しています。 少しでも興味を持ってくださった方は、ぜひお話しましょう! モノグサ株式会社の採用サイトです。モノグサは「記憶定着」をサポートする学習サービス「Monoxer」を運営する会社です。

採用サイト

careers.monoxer.com

*1:問題によってはそのような形式の出題が不都合になることもあるため、選択問題のみを出題する設定することも可能です

学習継続:モティベーションについて色々考えてみた。

Monoxer Advent Calender 2023 20日目の記事です。 モノグサでProduct Managerとして働いているマチューです。英語四技能のプロダクト、又新領域関係のプロダクトの担当をしています。 今回は、学習という観点で「モティベーション」について記事を書きました。

はじめに

真剣に勉強を始めようと決めたとき、学習者の皆さんは長い旅に出ることになります。通常、追い求めるゴールは遠く、到達するまでに数週間から数ヶ月かかることもある。例えば、英検2級から準1級を目指したとして、平均11ヶ月、約450時間勉強する必要があると言われています。これは膨大な労力である。やり遂げられる人もいれば、残念ながら目標に到達できずに途中で投げ出してしまう人も多くいるでしょう。

その違いはどこかから生まれるのだろうか? 「モティベーション」が一つの大きな要因だと考えられます。

モティベーションとは?

ウィキペディアによると、モティベーションは「個人が目標指向的な行動をとるように駆り立てる内的状態」と言われています。この定義から、すでにいくつかの重要な概念が浮かび上がってきます:

  • モティベーションに目標が必要であること。目標がなければ、行動を取る必要がない。
  • モティベーションの結果は、勉強する、体を鍛える、あるいは単に本を開くといった具体的な行動であること。
  • モティベーションは静的なものではなく、状態であること。様々な要因によって変化する。

そして最も重要なことは、モティベーションは人によって異なり、モティベーションに影響を与える様相も異なることです。

自分の学習経歴を振り返ってみたら

モティベーションへの理解を深く掘るために、自分の過去の学習を振り返って、下のグラフでまとめてみました:

このグラフをみて、私の学習経歴は成功、失敗、又は苦労の連続であったことがわかります。

一つの様相として、目的がボンヤリしていたり、弱かったりすると、学習を継続することは中々できなかったことがわかります。例えば、昔スペイン語の勉強を始めたのは、当時スペイン語圏への出張が多く、「スペイン語が話せたらかっこいい」・「便利かもしれない」と感じたからでした。あまり強い「理由」ではなかったことが原因だったのか、結局、スペイン語の教材を買って、2週間勉強して、それ以来一度も開きませんでした。皆さんもこのような体験ありますか?

加えて、勉強が自己中心的なものなのか、強制的にやらされているかによって、学習の継続に影響しているみたいです。私はフランス育ちの日仏のハーフで、中学時代、フランスで生活しながら、放課後日本語の漢字を勉強させられました。当時、日本語を覚えることに対して目的もなかったし、必要性を感じていなかったが、親の強制によって(今は親のモティベーションに感謝しています)、やめないまま高校の漢字まで覚えました。

結局のところ、途中でやめた学習と最後まで頑張ってできた学習の決め手は何でしょうか? それはやっぱり「モティベーション」なのではないか?と思いつつ、なぜ場合によって、モティベーションがでたり、でなかったりするかはわからない。もっと深ぼっていく必要があります。

モティベーション理論

モティベーションは心理学において非常にポピュラーな研究対象であり、モティベーションのメカニズムを説明しようとするモデルやセオリーが数多く存在します。 様々な理論の中で、”Situated Expectancy - Value Theory” (Eccles,2020) は、教育の文脈で人気の理論である。 次のグラフに以上のセオリーをまとめました。 このモデルによって、学習タスクを実行するかしないかの選択を迫られるたびに、学習者は「成功への期待」と「タスクの主観的価値」に基づいて判断することになっています。この判断は学習者の過去の学習経験や文化、自尊心、目標などの個人的要因にも影響されると思われます。簡単に説明すると、出題された時に、学習者は:

  • この学習タスクをうまくこなせる自信があるのか?
  • この学習タスクは自分にとって価値があるのだろうか?

と(無意識に)考えてしまう。もし上記の質問のどれかが否定的な答えにつながれば、学習者のモティベーションが低く、行動(学習)しないことになります。

モデルをさらに詳細に調べると、”タスクの主観的価値”は、下図のように3つのプラス(外在的価値、内発的価値、効用価値)とマイナス(機会費用、努力費用、感情費用)要素に分解されます: これは、個人が与えられた学習タスクの主観的価値を量るとき、無意識のうちに6つの価値要素を全体として見積もり、コスト・ベネフィットに見合うかどうかを自分で判断することを意味している。 この理論によると、学習体験がモティベーションにどのような影響を与えるかは、以下のように容易に想像できます: このように、学習体験や内容ににより、タスクの主観的価値が変わり、学習の継続判断に最終的に反縁されます。

プロダクトでできる、モティベーション対策

以上のモティベーション理論によって、プロダクトで学習者のモティベーションを支える手段は大きく3種類考えられます:

  • 学習で成功体験させるための工夫
  • 学習に纏わる苦しみの解消
  • 学習の価値の最大化

Monoxerのアプリの中に、そのような工夫はすでにいくつか用意されています。例えば、サクサクとクイズを解く学習体験の楽しさ、先生から送られる励ましのスタンプ、あるいは学習をする中で、記憶していく感覚そのものは学習者のモティベーションを支えてくれていると考えられます。それに加えて、ユーザーからのフィードバックに基づき、機能や学習体験の改善を進めています。例えば2023年12月に機能のアップデートをリリースし、スピーキング学習での認知的労力を大幅に軽減できたと思われます。

以下のグラフは、カテゴリーごとでのアプリの平均継続利用率と利用頻度を示しています。ご覧の通り、「Education」のカテゴリーは最も低い位置にあり、学習を長く続けるためのモティベーションはEdTechで最大の課題かと思われます。

(source: https://www.insiderintelligence.com/content/driving-engagement-with-analytics-flourishing-mobile-app-economy-sponsored-content)

モノグサでも今後モティベーションの課題に更に取り組み、全ての学習者のゴールまで辿り着けるようになることを目指します。

Monoxer Advent Calendar 2023

Monoxer Advent Calendar 2023では、開発、ビジネス、コーポレートの様々な職種のメンバーが毎日1つずつ記事を公開していく予定なので、是非明日以降もチェックしてください✏️

qiita.com

またモノグサ株式会社では一緒に働く仲間を募集しています。 少しでも興味を持ってくださった方は、ぜひお話しましょう!

careers.monoxer.com

ありそうでなかった学習と記憶のデータ

Monoxer Advent Calendar 2023 13日目です。

ごあいさつ

こんにちは。モノグサ株式会社の大橋です。以前の記事でも自己紹介しましたが、現在ソフトウェアエンジニアとしてデータ基盤の構築からデータ解析まで、データと名のつくことは何でもやっています。

この記事を読まれる皆さんの多くは日本の学校を卒業されたかと思いますが、学校での勉強というとどういうものを思い浮かべるでしょうか? 自分はなんだか問題集やプリントをたくさん解かされていたような気がします。

ところで、学校では日々大量の問題演習が行われる割にその効果検証を科学的に行っているという話はあまり聞きません。解いて丸付けしたデータが文字通り捨てられているのです。モノグサはデジタルツールの強みを活かし、創業以来蓄積された38億問以上の採点結果が全て保存されています。今回はこの「ありそうでなかった」データを集計して反復練習の効果について調べてみます。

反復と正解率の関係

単語問題の各回答について、同じ学習者が同じ問題を前に解いた回数を計算し、回数の小さい順に正解率を計算してプロットしたもの。1番左が初見正解率、次が2回目の正解率……

反復して覚えられるというなら、前に同じ問題を解いた回数が多ければ多いほど正解率が高いはずです。このグラフはその仮説を検証するものですが、10回前後までは順調に正解率の上昇が見られるもののそれ以降低下しています。これは反復練習の無意味さを意味するのでしょうか?

未検証ではありますが、私の仮説では正解率が反復効果だけでなく単語の覚えやすさにも依存していることが原因なのではないかと思っています。Monoxerで学習を続けると記憶済みになったものはほとんど出題されず、なかなか覚えられない覚えにくい単語だけが繰り返し出題されるようになります。すると、反復回数が多いことはその単語が覚えにくいことを暗示し、結果として正解率が下がってしまうのです。

1つの問題に固定してこのグラフをプロットすればこの仮説が検証できると思いますが、今回はアドベントカレンダーなので割愛します。気になる人は入社してね! (右肩上がりのグラフが出てくると思っていたので深掘りする作業時間を用意してませんでした……)

接触間隔と正解率の関係

やらないと忘れるという話も調べてみました。これについては、前に同じ問題を解いてからの経過時間が長いほど正解率が低下するという仮説を立てて検証しました。 ディクテーション問題(中難易度の出題形式)の各回答について、同じ学習者が同じ問題を前に解いてからの経過時間を計算し、経過時間の小さい順に20等分。それぞれのグループについて正解率を計算し、左から並べたもの。

上のグラフからわかる通り、経過時間が伸びるほどきれいに正解率が低下しています。この関係はディクテーションだけでなく単語入力や選択問題の形式でも観察されました。1番右(経過時間が最も長い群)の平均経過時間は1ヶ月程度なのですが、2番目に左(平均経過時間11.5秒)の3分の1以下の正解率になっています。

最も左の群の正解率がなぜ低いかは分かりませんが(データ不備でしょうか)、それ以外については予想以上にきれいな減少傾向が見られ、人間は忘れちゃうんだなあという事実を思い知らされます。

ほんとうはこの1番右の群がどういう分布になっていて、この群にいながら正解できる人にはどういう特徴が出るか調べたいのですが(これこそが長期記憶に他ならないのですから!)これも時間の関係で割愛です。やりたい人は入社してください!

エビデンスに基づいた学習体験を作りたい

反復回数や接触間隔が正解率に影響するという直感的には明らかな事実も、実際に裏付けられると今までより自信を持って反復練習を勧められるようになったのではないでしょうか。世の中には根拠が怪しかったり賛否が真っ二つに分かれるような教授法もたまにありますが、モノグサではエビデンスに基づいた学習体験を作ってみなさまにお届けしたいと思っています。

Monoxer Advent Calendar 2023

Monoxer Advent Calendar 2023では、開発、ビジネス、コーポレートの様々な職種のメンバーが毎日1つずつ記事を公開していく予定なので、是非明日以降もチェックしてください!

Monoxerのカレンダーページです。 qiita.com

またモノグサ株式会社では一緒に働く仲間を募集しています。 少しでも興味を持ってくださった方は、ぜひお話しましょう! モノグサ株式会社の採用サイトです。モノグサは「記憶定着」をサポートする学習サービス「Monoxer」を運営する会社です。

採用サイト

careers.monoxer.com