コネヒト開発者ブログ

コネヒト開発者ブログ

カテゴリ類推の機械学習モデルをプロダクションに導入した話

こんにちは。インフラエンジニアの永井(shanagi)です。

今回は、昨年から取り組んでいる機械学習の分野で、自分の作ったモデルをサービスに本番リリースする機会があったので、PoCで終わりがちな機械学習をプロダクト導入にこぎつけるためにどのようなプロセスを歩んだのかとそこで得た自分なりの知見を中心にご紹介できればと思います。

機械学習のプロダクト導入に向けては歩むステップが非常に多く、個々の詳細な内容について細かく書くと非常にボリューミーな内容になってしまうので、詳細は割愛し機会があればまたどこかでご紹介出来ればと思います。

内容は、ざっくり下記2つに絞りました。

  • どんな機能をリリースしたのか?
  • 導入までの全体アプローチ

ちなみに、なぜインフラ畑の自分が機械学習をやっているのかについては、昨年末に下記ブログにまとめたのでもし興味がある方がいれば読んでみてもらえればと思います。

kobitosan.hatenablog.com

どんな機能をリリースしたのか?

まずは今回どのような機能をリリースしたのかを紹介します。 ママリはママ達の悩みや疑問を解決するQAプラットフォームなので、毎日ユーザであるママさん達から多くの質問投稿があります。

ママリ内のカテゴリとしては、「妊娠・出産」「育児・グッズ」「お金・保険」などがあり、質問文の内容に合わせて投稿時にユーザに選択してもらっています。 今回は、この質問投稿時のカテゴリ選択において、質問本文の内容から適切なカテゴリを類推してユーザに推薦する「カテゴリ類推」エンジンをリリースしました。

↓質問の本文からカテゴリを類推している様子です!カテゴリを考え中の時にカテゴリ類推のAPIが呼ばれています。 f:id:nagais:20200512144003p:plain

詳しくは、この後の章で触れるのですがこのリリースによって、下記の指標にプラスの影響を出すことが出来ました。

- 回答率の向上
- 質問投稿時のCVRの向上

機械学習の導入は、導入時はマイナス影響なしの状態で入れてそこからモデルアップデートを通して数値を上げていくものという期待値調整をするので、初期モデルである程度プラスの成果が出たのは運がよかった面もあるな思っています。

導入までの全体アプローチ

前提として昨年からコネヒトでは、機械学習を活用したプロダクトの改善を組織として推し進めていくという取り組みを行っています。組織から機械学習導入を期待されているというのは、説明コストが大幅に下がること(PoCまでのハードルが下がる)を意味しており今回のカテゴリ類推導入に向けても大きな後ろ盾になりました。

全体のステップ

今回カテゴリ類推を本番リリースするにあたり大まかに下記のステップをたどりました。

①仮説作りのためのデータ分析
↓
②仮説を裏付けるためのデータ分析
↓
③モデル作成
↓
④オフライン検証と品質チェック
↓
⑤デモ作成(AWSとAndroidアプリ)
↓
⑥A/Bテスト(PoC)と効果測定
↓
⑦本リリース

それぞれどんなことをしたのかとそこで得た知見ベースで振り返っていこうと思います。

進める上で気をつけた点として、ある程度の精度はオフライン検証で出来るが、実際のユーザの行動は出してみないとわからない部分が大きいのでできるだけ早くA/Bテストまで持っていくことを意識しました。

①仮説作りのためのデータ分析

機械学習導入を期待されているといっても闇雲に機械学習を入れればいいというわけではもちろんありません。 サービスが抱える課題を解くためのツールとして機械学習が適切であればそれを使います。

その課題を可視化して理解し、仮説(機械学習で解決すべき課題)に落とし込むのにはデータ分析が必要です。 解くべき課題に関しては、主にサービスのKPIやそれを細分化したものの達成を設定することが多いと思います。今回のカテゴリ類推においても、当時のサービスKPIの一つになっていた回答率を分析することからはじめました。

データ分析を進める上での工夫として、属人化しがちなデータ分析の知見を気軽に共有するために、GitHubのissueでデータ分析のログを残すようにしています。 仮説を裏付ける際や簡単なモデルの試作品を作る際に使うjupyter notebookのソースも同じリポジトリで管理するようにしており、後からでも過去のプロジェクトを気軽に参照出来るようにしています。

f:id:nagais:20200512143537p:plain

可視化したデータは下記のようなダッシュボードにまとめておくことで、以後のA/Bテスト時の結果計測にも使えるような形にしておきました。

f:id:nagais:20200511205800p:plain

②仮説を裏付けるためのデータ分析

①のデータ分析の結果、質問に対して適切なカテゴリが選択されると回答がつく確率が上がりそうなことがわかりました。 このカテゴリ選択を適切にすることで回答率を上げられそうという仮説を裏付けるためのデータ分析に入ります。 同時に、どのようにして投稿のカテゴリを適切に設定するかを検討しました。その中で、今回採用する機械学習を使った質問投稿時の「カテゴリ類推」を導入すれば、ユーザが入力する投稿内容を元に適切なカテゴリを設定出来てUXも上がりそうという仮説が最終的に出来上がりました。

この仮説を裏付けるために更にカテゴリと回答に絞った分析を行い下記のような事実が浮かび上がってきました。(一部抜粋)

これらは質問文の内容から適切なカテゴリが入ることで回答を増やしてくれそうという仮説の裏付けになりました。

  • 特定のカテゴリに偏りがある(質問内容とは関係なくカテゴリを選択している質問が多くある)
  • ユーザは好きだったり興味のあるカテゴリを回遊しながら回答してくれていることが多そう

③モデル作成

続いて、ローカルのjupyter notebookで「カテゴリ類推」のモデル作成を行いました。 ざっくりメモですが、どんなことをやったか羅列しておきます。

  • 学習データの作成
    • 過去の膨大な質問データを使えるので加工等は不要
    • 1ヶ月分のデータを取ってpandasで分布みたりしてデータ件数を揃える
  • 質問文を機械学習で使える形に前処理する
    • 小文字化とテキストから不要な文字を削除や置換
    • neologdnを使った正規化とUnicode正規化
    • MeCabを使ったトークナイズ(どの品詞を使うと一番精度高いか色々と試したり)
  • 学習データとテストデータの分割
    • scikit-learnのtrain_test_splitを使う
    • 最初層化抽出してなくて、層化抽出することで大きく精度が伸びたのはなつかしい
  • 特徴抽出
    • 文字列をベクトルに変換する手法
    • Bag of WordsとTF-IDFを試す
    • 最終的に、TF-IDF(min_df,max_dfでストップワード兼ねる)を使った
  • アルゴリズム選定
    • scikit-learnを使っていたので、SVM,ロジスティック回帰,ランダムフォレストを試す
    • GridSearchしながら同じ条件でどのアルゴリズム一番精度が出るかを繰り返した
    • 恥ずかしながら当時はニューラルネットワークはまだ手をつけてなかったので試してない(今後検討)

手元である程度の精度が出るモデルが出来たのでオフライン検証と品質チェックに進みます。

④オフライン検証と品質チェック

オフライン検証として、学習データに含まれないN日分のデータからの正答率を出して指標としました。

オフライン検証の結果、ある程度精度の出る(ユーザに違和感なく提供出来そうな)モデルが出来ました。 ただ、機械的に正答率が高くても、ユーザにとって不快な推薦をしてしまうとサービス価値の毀損につながります。ママリはコミュニティサービスなので、せっかく質問しようとしたユーザにカテゴリの推薦で不快な思いをさせてしまっては機会損失につながります。

ここの部分の不安を解消するために、CSチームと連携して、オフライン検証の結果間違ったデータに関して品質チェックを行ってもらいました。 結果、ユーザに致命的に不快感を与えるような予測はないという裏付けをもらってから次のステップに進みました。

⑤デモ作成(AWSとAndroidアプリ)

ディレクターや社内で説明するのに動いているものを見せるのが一番説得力が増すと考えて、Androidエンジニアに協力してもらいデモ用のAPIを叩くデモアプリを作ってもらいました。 今回このデモの果たしてくれた役割は大きく、やはり動くものをサクッと作るのは大事だなと思いました。

⑥A/Bテスト(PoC)と効果測定

デモやデータ分析と品質チェックの結果をディレクターに説明して、A/BテストへのGoサインを無事こぎつけました。

A/Bテストを行う上では、当たり前ですがトラッキングするためのダッシュボードを事前に作っておくことが重要でした。 今回は①で作ったダッシュボード+mixpanelでアプリver毎のイベントをトラッキングすることで効果測定を行いました。 結果指標として掲げていた項目で明らかな優位が見られました!

- 回答率の向上
- 質問投稿時のCVRの向上

裏話でもないですが、ユーザに直接届くものを作ってリリースする機会はこれまであまりなかったので、結果を毎時ドキドキ見ていたのを思い出します。 興奮してこんなツイートもしてました。

⑦本リリース

効果測定の結果、明らかな優位が見られたので簡単なレポートをまとめ関係者に共有し本リリースが決まりました。 ここでのレポーティングは事前にデータ分析する時に効果測定時のレポートを意識しながら可視化したのが役立ちサクッと作りました。

その後、A/Bテスト時は実現までのスピードを重視し手動作成したモデルを使っていたので、前処理とモデル作成のバッチ処理を作成し自動化しました。バッチはAWS上でECS+Fargateベースで動かしています。

最後にどんなアーキテクチャで動いているのかを載せておきます。

f:id:nagais:20200512101636p:plain

今回は技術的な内容には踏み込まずにデータ分析から機械学習のプロダクト導入に至るまでの道筋についてご紹介しました。 コネヒトでは、これからも今回の事例のようにテクノロジーの力でプロダクトを伸ばしていってくれる仲間を絶賛募集しています。ご興味ある方は是非一度お話だけでもさせてもらえるとうれしいです。

www.wantedly.com

ママリでAWSを使った動画配信をはじめました。

こんにちは! フロントエンドエンジニアのもりやです。

ママリではよりユーザーにとってわかりやすく情報を伝えるべく、4/22 からママリ内の人気記事などを動画にし配信する取り組みをはじめました。

news.connehito.com

今回、動画配信にあたって AWS 上で動画変換と配信を行ったので、使用したサービスやシステム構成などを解説しようと思います。

システムの全体像

AWSサービスを使って、以下のような構成で作りました。

f:id:hyirm:20200511084620p:plain CloudCraft

※この図は動画の配信のみに絞っています。動画の情報をアプリに配信するAPIなどは別にあります。

大まかに説明するとこんな感じです。

  • CloudFront + S3 を使ってHTTP (HLS) で配信
  • MediaConvert を使ってMP4形式の動画をHLS 形式へ変換
  • API Gateway + Lambda を使って動画変換のAPIを提供
    • DynamoDB を使って動画の情報を保存

以下、詳しく説明します。

動画のフォーマット

配信にあたり、まず動画をどのように配信するかを決めました。 今回配信する動画は、数十秒程度がメインなのでそのまま動画ファイルを配信する方法も検討しました。 ただ、1分を超える動画もありますし、全部ダウンロードしないと再生できないというのは体験的に良くないのでストリーミングでの配信に決めました。

動画のストリーミング配信は全く知見がなかったので色々調べたところ、以下の2つが主流のようです。

  • HLS (HTTP Live Streaming)
  • MPEG-DASH(ISO/IEC 23009)

あまり詳細な仕様までは調べきれていないですが、いろいろ調べた結果、HLSの方がシンプル、MPEG-DASHはDRMなどの複雑な要件にも対応できるがその分仕様も複雑、という印象でした。

今回の配信要件はシンプルで、iOS/Android でもネイティブのエンジニアの方から再生できることが可能であることを確認したのでHLSを採用することにしました。 ちなみに、HLSはAppleが提唱している規格なので、iOSは当然対応していますし、HLS形式の動画はSafariで直接開くことも可能です。(他のブラウザは対応していません)

CloudFront + S3

HLSは配信にあたって静的なHTTPサーバーにファイルを配置するだけで良いので、よくある CloudFront + S3 で配信しています。

MediaConvert

S3に置いてある動画ファイルを変換して、変換した動画ファイルをS3に出力してくれるサービスです。 今回の動画配信で最も重要なサービスでした。

ジョブの作成

MediaConvert は「ジョブ」という単位で変換を実行します。 ジョブは、以下のような入力と出力を設定して、変換の詳細を設定します。

変換の全体像

f:id:hyirm:20200511084710p:plain:w320

入力が一つに対して、出力が複数あることが分かるかと思います。 例えば、1つの動画からHLSとMPEG-DASHの2つを同時に変換して出力することができます。

ちなみに入力も複数作れるようなのですが、今回複数入力を使う用途はなく私にも用途が分からないので、説明は割愛します。 (動画の結合とか、複数の動画を横に並べて結合したりできるんでしょうか?)

入力の設定

f:id:hyirm:20200511084801p:plain

入力は S3 に配置した動画ファイルのパスを指定します。 他にもたくさん設定項目がありますが、今回はここの設定以外は特に使っていません。 動画は奥が深い・・・。

出力の設定(動画)

f:id:hyirm:20200511084926p:plain

出力先の S3 プレフィックスを入力します。 (※プレフィックスであり、このままの名前で出力されるわけではありません。)

また、下の方の「出力」欄を見ると、2つの出力があるのが分かるかと思います。 例えばHLSであれば、複数のビットレートの動画を1つの配信に含め、クライアントがネットワークの状況に応じて切り替えることができます。 そういった場合に、1つの出力グループに対して、複数の出力を設定することができます。 (ちなみに、今回のママリの配信では諸事情により1つの出力にしています)

f:id:hyirm:20200511084953p:plain

各出力に対して、動画の詳細を設定できます。 こちらも大量の設定項目がありますが、主に使ったのは以下の2つです。

  • ビデオコーデックと解像度
  • ビットレート

他は特にいじらなくても、デフォルトのままで特に問題ありませんでした。

出力の設定(キャプチャ画像)

今回、動画に配信する際にサムネイル用の画像も一緒に作りたいということで、動画内から1秒おきにキャプチャ画像を作り、その中から適切な画像を選んで配信する、という方法を取りました。

例えば、30秒の動画なら、30枚のJPEG画像が出力され、その中からサムネイルとして良さそうなものを選ぶ、という感じです。

f:id:hyirm:20200511085029p:plain

こんな感じの出力設定をします。 画質にあまり拘らなければ、フレームレートを調整すれば大丈夫です。 1/1 で1秒に1枚、という設定になります。

変換の実行

設定が完了したら、変換を実行します。 以下のようにジョブリストに表示され「COMPLETE」と表示されれば完了です。 ちなみに設定にエラーがある場合は「ERROR」と表示されます。

f:id:hyirm:20200511085044p:plain

変換が完了すると S3 にはこのように出力されます。

f:id:hyirm:20200511085108p:plain

※ジョブ作成時に設定したプレフィックスなどによって出力先は変わります。

出力先を CloudFront で配信している S3 バケットにしておくと、変換完了後にすぐインターネットからアクセスできるので便利でした。

API Gateway + Lambda

AWS SDK でも実行できるのですが、curl やスクリプト、管理画面などから使いやすいように、シンプルなAPIを提供するようにしました。

  1. アップロードの情報を提供するAPI
    • S3 の Pre-Signed URL を使って、アップロードに必要な一時URLを生成して返却するAPIです。
    • アップロード自体は、アクセス元の責務にしてます。
  2. 変換をリクエストするAPI
    • MediaConvert にジョブを作るAPIです。
    • ジョブIDなどは DynamoDB で管理しています。
  3. 動画情報を取得するAPI
    • MediaConvert に問い合わせて、ジョブの情報を取得して返却します。
    • 変換が完了している場合は、インターネットからアクセスできるURLなども返却します。

なお、API Gateway は API Key でアクセスを制限しています。

変換作業

今回は、1本辺り数十秒程度がメインの動画を200本以上、再生時間だと2時間以上の動画ファイルをアップロード&変換しました。 curl などで手動アップロードも可能ですが、時間がかかる、ヒューマンエラーが発生しやすい、設定ミスなどで再変換したい場合でも再実行しやすくしたい、といった目的のため Node.js でスクリプトを書きました。

詳細は省きますが Node.js を使いアップロードを最大10並列で実行するスクリプトを書いて実行しました。 大体変換完了まで16分ほどで終わったので、かなり早くできました。 MediaConvert は複数実行すると並列に変換してくれるので、単に2時間の動画を変換するよりも早く終わります。便利ですね!

料金

CloudFront での配信料金

これは動画に限らないですが CloudFront からインターネットへの転送は 1GB あたり 0.114 USD かかります。 $1 = 107円で、100GB の配信をしたとすると 0.114USD * 100GB * 107円 = 約1,220円 かかります。

aws.amazon.com

MediaConvert での変換料金

今回の肝である MediaConvert での変換にはどのぐらいの料金がかかるのか紹介します。 最近のスマホは解像度が高くなっているので、MediaConvert の算定方法だと 4K に該当する画質で変換しました。

aws.amazon.com

フレームレートは <30fps でやったので、 1分間の変換料金は 0.034USD になります。 $1 = 107円で、60分の動画を変換した場合、 0.034USD * 60分 * 107円 = 約218円 になります。 めっちゃ安いですね!

VODやってる会社さんとかはわかりませんが、今回のように小規模な動画配信を行う場合、 動画変換の開発や設定、サーバー維持費など考慮すればめちゃくちゃコスパいいサービスだな、と感じました。

その他

S3 API Gateway Lambda DynamoDB などの料金などがありますが、CloudFront での配信料金に比べると微々たるもの、もしくは無料枠で収まる程度でしかなかったので、省略します。

おわりに

今回初めての動画配信でしたが、HLS で配信し、AWS のサービスを使うことでかなり容易に構築や配信準備を行うことができました。 動画配信は敷居が高いイメージでしたが、今回のようなシンプルな配信と AWS のサービスを組み合わせる場合は割と楽にできます。

未知の領域に踏み込んでみるのは楽しいですね。 コネヒトでは、新しいことにどんどんチャレンジしたいエンジニアを募集中です!

www.wantedly.com www.wantedly.com www.wantedly.com

BigQueryのスケジューリングクエリで日付別シャード化テーブルを作成する

こんにちは!テクノロジー推進グループでエンジニアをやってるaboです。

この記事では、Google BigQueryのスケジューリングクエリを使って日付別シャード化テーブルを作成する方法を紹介します。

日付別シャード化テーブルはBigQueryにおけるテーブル分割の方法の1つです。弊社では費用と計算コスト減を目的にテーブル分割を行なっており、その中でも日付別シャード化テーブルは以下のようなメリットがあり、採用しています。

  • where句でテーブル名の絞り込みが出来るのでスキャン量が調整出来て便利
  • テーブルが日付ごとに分かれるので、バッチ失敗時のリランやテーブル再生成が気軽に行える

cloud.google.com

では実際に日付別シャード化テーブルを作成する手順に移ります。

手順

1. クエリを用意して「スケジュールされたクエリを新規作成」を選択

このクエリの結果がそのままテーブルの中身になります。下記の画像の例では、抽出対象となるテーブルが日付別シャード化テーブルになっており、前日分のデータを抽出しようとしています。

f:id:aboy_perry:20200422193705p:plain
クエリを書いて、スケジュールを新規作成

2. クエリ結果の書き込み先のテーブル名をシャード化したい日付にあわせて入力

ここが本題ですが、テーブル名の指定には、文字列のほか、run_daterun_time という2つのパラメータが使えます。特にrun_timeパラメータを使うと前日の日付でシャード化することができたりします。抽出対象とするデータが前日分だからシャード化する日付も前日のものにしたい、というケースで活躍します。

以下が入力例です。

例1)テーブルの日付をバッチ実行日にしたい

table名_{run_date}

例2)テーブルの日付をバッチ実行日の前日にしたい

table名_{run_time-24h|"%Y%m%d"}

f:id:aboy_perry:20200422203355p:plain
スケジュール設定画面

ハマりポイント

run_daterun_timeUTCになるので注意が必要です!つまりスケジュールをJST 09:00以前にした場合、run_daterun_timeはJSTの実行日の前日を示します。例2ではそこからさらに-24hしているため最終的にJSTの実行日の前々日でシャード化されることになります ԅ( ˘ω˘ԅ)

他の入力例や詳細は下記をご覧ください。

cloud.google.com

3. 残りの入力欄に適当な値を設定して、「スケジュール」を実行

f:id:aboy_perry:20200422225501p:plain
スケジュールを実行

これでスケジューリングしたクエリが実行されたら、日付別シャード化テーブルができてるはずです!👏 下の画像のように、日付別シャード化テーブルはBigQueryのGUI上で日付ごとに選択できたり、見やすくなっています。

f:id:aboy_perry:20200422231227p:plain
日付別シャード化テーブル

また、「スケジュールされたクエリ」画面では、スケジュールの詳細を見ることができ、次に実行される予定の時間を確認したり、クエリやスケジュールの変更を行うことができます。

f:id:aboy_perry:20200422224520p:plain
スケジュールされたクエリの一覧

日付別シャード化テーブルからデータを抽出する

できた日付別シャード化テーブルは、WHERE句で _table_suffix を用いて日付をまたいで検索することができます。

以下はhoge_events_{日付}という日付別シャード化テーブルから、過去3日分のデータを抽出する例です。

SELECT *
FROM
    `dataset_name.hoge_events_*` as events
WHERE
    _table_suffix BETWEEN FORMAT_DATE("%Y%m%d", DATE_SUB(CURRENT_DATE("Asia/Tokyo"), INTERVAL 3 DAY)) AND FORMAT_DATE("%Y%m%d", DATE_SUB(CURRENT_DATE("Asia/Tokyo"), INTERVAL 1 DAY))

また、今月分のデータを指定する場合はLIKEを使って以下のようにもできます。

SELECT *
FROM
    `dataset_name.hoge_events_*` as events
WHERE
    _table_suffix LIKE FORMAT_DATE("%Y%m%%", CURRENT_DATE("Asia/Tokyo"))

おわりに

UTCである点はハマりポイントかなと思いますが、簡単に日付別シャード化テーブルを作ることができます。テーブル分割を取り入れ、コストを削減していきましょう〜。


コネヒトでは、データを活用してプロダクトを成長させたい!機械学習やりたい!といった方を募集中です!

www.wantedly.com

www.wantedly.com

www.wantedly.com

レコメンドエンジン導入までの取り組みとアーキテクチャについて

こんにちは!MLエンジニアのたかぱい(@takapy)です。

今回は、ママリのアプリ内にレコメンドエンジンを導入したので、導入までの取り組みやアーキテクチャについてご紹介できればと思います。


目次


ママリ内での課題

ママリはサービスとして6年目を迎え、サービスの成長とともにアプリ内の記事数も増えており、それに伴いユーザーが本来欲しい情報にたどり着くことも難しくなってきました。

加えて「子育て層のユーザー」という切り口1つとっても、0才児のママと1才児のママでは悩みや欲しい情報がまったく異なります。

このような背景から、これまで人的に行っていたルールベースでの記事配信に対し課題を感じており、機械学習で解決できないか、ということで取り組み始めました。

アーキテクチャ概要

全体のアーキテクチャは以下のようになっています。

アプリのログはBigQueryに蓄積されているため、そこからデータを取得・構造化した後、推薦記事を計算してDynamoDBに保存しています。

APIはFlaskで構築し、APIのログはAthena経由でRedashから参照できるようにしています。
このRedashはBigQueryのデータも参照できるので、ここでAPIのログとBigQueryの行動ログデータを突き合わせて、各種指標(CTRなど)をモニタリングしています。

f:id:taxa_program:20200330195638p:plain
アーキテクチャ

EDAとアルゴリズムについて

まずはデータの理解を深めるために、簡単なEDAを実施しました。
ママリの記事にはカテゴリ*1がついているのですが、あるユーザー属性別にカテゴリ毎の閲覧数を見てみると、大きな偏りがあることが分かりました。
(例えば、ユーザー属性Aの人は、「子育て・家族カテゴリ」の記事をよく見ているが、ユーザー属性Bの人は「住まいカテゴリ」の記事をよく見ている、など)

f:id:taxa_program:20200330184036p:plain
特定カテゴリにおけるユーザー属性別の記事閲覧数例

この結果を元に、ユーザーを数十種類のクラスタにハードクラスタリングし、「クラスタ単位」と「クラスタ×ユーザー単位」の2種類に分け、推薦記事を計算しました。

「クラスタ単位」とは、以下のようにクラスタ粒度でRatingテーブルを作成して推薦記事を計算するイメージです。こうすることで、新規ユーザーに対してもある程度嗜好性を考慮した記事を推薦してくれることを期待しています。

f:id:taxa_program:20200330184949p:plain
クラスタ単位の推薦記事計算例

「クラスタ×ユーザー単位」とは、ユーザーごとにそれぞれのクラスタ内で推薦記事を計算するイメージです。

f:id:taxa_program:20200330185134p:plain
クラスタ×ユーザー単位の推薦記事計算例

また、今回は「0→1」での導入だったため、レコメンドの精度よりは実装までのスピードを意識して取り組みました。
そのため、推薦アルゴリズムには業界内での成功事例があり、かつ比較的実装コストも低い協調フィルタリングと、Matrix Factorization(MF)を採用しようと決め、この2つのアルゴリズムでオフライン検証に進みました。

オフライン検証の失敗と学び

全ユーザーの直近3週間の行動ログ(アプリの閲覧履歴、ユーザーのアクションを含む)をBigQueryから取得し、構造化しました。
そこからデータを時系列に、古い2週間と直近1週間に分割し、前者を学習データ、後者をテストデータとしてオフライン検証を行いました。

オフライン検証では、推薦したアイテムをクリックするか否かを評価するため、Recallという指標を用いました。Recallとはユーザーが実際に嗜好したアイテムのうち、推薦したアイテムでカバーできたものの割合です。

結果、このオフライン検証では良い数値がでませんでした。

そもそもオフラインでの評価は、我々がおすすめしようとするまいと、ユーザーが嗜好(クリック)したものを予測しているので、それを正確に予測できることにどれだけ意味があるのか、という議論ポイントはあると思っています。
そんな中でオフライン検証ではあまり良い予測ができないケースもある(良い予測ができても、それがそのままオンラインでの精度にならない)ということを学べたのは、今回の収穫の1つであったと思います。

とはいえ、PoCばかり進めていても仕方ないよね、ということから、未知の部分は多いもののプロダクションでどういう動きをするか見てみよう、ということでA/Bテストを実施しました。

A/Bテストについて

冒頭で説明したアーキテクチャは最終的なもので、A/Bテスト時の構成はかなりシンプルにしました。

今回、オフライン検証で良い数値が出た訳でもないため、現状の表示条件(ルールベース)よりCTRが下がる恐れがありました。
そんな中で全体のアーキテクチャを先に設計・構築してしまうと、実装までのスピードが遅くなったり、仮に指標が下がってしまった場合の時間/金銭的コストが大きくなってしまいます。

そのため、下図のような最小限の構成としました。

f:id:taxa_program:20200330191934p:plain
A/Bテスト時のアーキテクチャ

結果的に、A/BテストではCTRが7ポイント向上し、検定を行いそのCTRに有意差が確認できたことから、プロダクションへ本格導入することに決定しました。

レコメンドアルゴリズムについて

今回試した2つのアルゴリズムについて簡単にご紹介します。
(詳細な実装方法などはWeb上に優良な記事がありますので、ここでは概要の説明に留めます)

強調フィルタリング(アイテムベース)

協調フィルタリングは大別して「ユーザーベース」と「アイテムベース」の手法があります。今回実装したのはアイテムベースの協調フィルタリングです。

まず、上記Rating行列から全てのアイテム間の類似度を計算して、類似度行列を生成します。この時の類似度計算方法には「ユークリッド距離」や「コサイン類似度」を使用できます。今回はコサイン類似度を使用しました。

f:id:taxa_program:20200330192217p:plain
類似度行列作成例

次に、推薦アイテムを計算したいユーザーのベクトルと、この類似度行列の積をとります。
下記例では、user Dに対して推薦したいアイテムを計算しています。計算結果からすでに評価しているitem 2を除外すると、item 4の値が一番高いため、user Dにはitem 4を推薦すればよい、ということになります。

f:id:taxa_program:20200330192410p:plain
userDに対する推薦記事計算例

Matrix Factorization

Matrix Factorizationはその名前の通り、Rating行列をuserの特徴量行列(P)とitemの特徴量行列(Q)に分解します。
例えば、m人のユーザーとn個のアイテムを考えたときに、m > k > 0であるk次元に次元削減して変換することを目的とします。
これは、評価値を表すRating行列(R)を、ユーザー要素を表すk × mの行列(P)と、アイテム要素を表すk × nの行列(Q)に近似することです。


R \approx PQ^T

図にすると以下のようなイメージです。

f:id:taxa_program:20200330193600p:plain
行列分解例

そして、分解された2つの行列の積をとると、新しいuser×itemのRating行列が生成されます。このRating行列は密な行列となるので、値の高いアイテムをそのまま推薦すればよいことになります。
例えば、user Aに対してはすでに評価しているitem 1とitem 2を除外すると、item 3を推薦すればよい、ということになります。

f:id:taxa_program:20200330193324p:plain
最終的な行列

最後に

今回は0からレコメンドエンジンを構築するまでの取り組みや、そのアーキテクチャについてお話しました。

私自身、レコメンドエンジンの構築はMovieLensのデータセットなどを使ってやってみた経験しかなかったので、実サービスに対して取り組むことで、実際にユーザーの反応を見ることができたり、安定して配信するための基盤作りに携われたり、とても面白かったです。

今回のレコメンドエンジンはまだまだ課題もあり、これからユーザーの反応を見ながらアップデートしていく予定なので、その時はまた取り組みをご紹介できればと思います。

*1:「子育て・家族」「病院」「住まい」など

Sign in with AppleでのiOSアプリとサーバーとの連携

こんにちは!エンジニアの柳村です。

Twitterなどの3rd partyのログイン機能を提供しているアプリは6/30までに対応が必要です。(2ヶ月延期されましたね!)

アプリ単体でSign in with Appleをできるようにするのはとても簡単です。しかし大抵のアプリの場合はそれだけでは完結せず、サーバー側でSign in したユーザーと紐付ける必要があります。

サーバー側はFirebase AuthenticationやAuth0といったIDaaSにまかせるという手もありますが、今回は自前で実装することを前提にその実現方法を見ていきたいと思います。

全体の流れ

クライアント側とサーバー側のざっとした流れはこのようになります。

f:id:yanamura:20200327094652p:plain
sign in with apple flow

クライアントからサーバー側にid_tokenを渡すやり方とauthorization_codeを渡すやり方の2つの方法がありますが、ここではauthorization_codeを使ったやり方のみ紹介します。また、nonceの生成やクライアントサーバ間の受け渡し方法についても割愛します。

iOSアプリ側

Apple Developer Programでやること

アプリのIdentifierのCapabilitiesにSign in with Appleを設定します。 その際に、configureボタンを押してPrimary App IDを設定します。

また、Identifierを更新するとProvisioning ProfileがInvalidになってしまうので更新する必要があります。

XcodeのProject設定でやること

TARGETSのSigning&Capabilitiesで+Capabilityを押してSign in with Appleを追加します。

実装

iOSアプリ側でやることは、Sign in with Appleをするボタンを用意し、ボタンが押されたらASAuthorizationAppleIDProviderを生成し、performRequest()を呼ぶとログインに成功するとcallbackが呼ばれ、authorization_codeが取得できるので、これをサーバーに渡すだけです。(ドキュメント: Implementing User Authentication with Sign in with Apple)

ボタンの用意

import AuthenticationServices
...

let appleButton = ASAuthorizationAppleIDButton() // デザインを変えたい場合はUIButtonなどに変えれば良い
appleButton.rx.controlEvent(.touchUpInside)
    .subscribe(onNext: { [unowned self] in
        let appleIDProvider = ASAuthorizationAppleIDProvider()
        let request = appleIDProvider.createRequest()
        request.requestedScopes = [.email]
        request.nonce = `something` // nonceについては割愛します

        let authorizationController = ASAuthorizationController(authorizationRequests: [request])
        authorizationController.delegate = self
        authorizationController.presentationContextProvider = self
        authorizationController.performRequests()
    })
    .disposed(by: disposeBag)

delegateの実装

extension XXViewController: ASAuthorizationControllerDelegate {
    @available(iOS 13.0, *)
    func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
        switch authorization.credential {
        case let appleIDCredential as ASAuthorizationAppleIDCredential:
            // ここでauthorizationCodeやidTokenが取得できる。
            print("#apple \(String(data: appleIDCredential.identityToken!, encoding: .utf8))")
            print("#apple \(String(data: appleIDCredential.authorizationCode!, encoding: .utf8))")

            // サーバーにauthorizationCode送る処理
        default:
            break
        }
    }
}

extension XXViewController: ASAuthorizationControllerPresentationContextProviding {
    @available(iOS 13.0, *)
    func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
        return view.window!
    }
}

サーバー側

Apple Developer Programでやること

Keysでkeyを追加します。 Sign in with AppleをENABLEにし、configureボタンを押してPrimary App IDを設定します。 作成が完了すると秘密鍵(.p8)をダウンロードします。この秘密鍵と作成したKeyのKey IDは、次でclient secretを作成するのに使います。

サーバー側の実装概要

サーバー側でやることは大きく2ステップで、まずAppleの/auth/token APIを叩いてid token(JWT)を取得します。 次にid tokenをAppleの/auth/keys APIを叩いて取得した公開鍵でverifyしてuser identifierを取得します。

id tokenの取得

1. client secret(JWT)の作成

以下のheaderとpayloadを使ってJWTを生成します。

header

{
  alg: ES256,
  kid: // Apple Developer ProgramのKeysで作成したKeyのKeyID
}

payload

{
  iss: // TEAM ID,
  iat: 今の時間,
  exp: 今の時間+適当な値(max 15777000),
  aud: https://appleid.apple.com,
  sub: // Bundle ID
}

署名はApple Developer ProgramのKeysで作成したときにダウンロードした秘密鍵を使います。

2. /auth/tokenにPOSTする

以下のデータをhttps://appleid.apple.com/auth/tokenにPOSTします。API仕様

{
    client_id: // Bundle ID
    client_secret: // 1. でつくったclient secretをいれる,
    code: , // iOSアプリから受け取ったauthorization_codeをセットする
    grant_type: 'authorization_code',
    redirect_uri: ""// 空文字
}

成功するとid_tokenが含まれたJSONが取得できます。

id tokenのverify

上で取得したid token(JWT)をverifyする必要があります。

1. 公開鍵の取得

https://appleid.apple.com/auth/keysをGETするとJWKSが取得できます。(API仕様

これには複数のJWKが含まれています。この中から、JWKのkidとid tokenのheaderのkidと一致するものを使って公開鍵を生成します。

2. id tokenのverify

ドキュメントVerify the Identity Token に以下のように記載があります。

- Verify the JWS E256 signature using the server’s public key

- Verify the nonce for the authentication

- Verify that the iss field contains https://appleid.apple.com

- Verify that the aud field is the developer’s client_id

- Verify that the time is earlier than the exp value of the token


これに従って、1. で取得した公開鍵を使ってid tokenをverifyし、id tokenのpayloadのnonce, iss, aud, timeを検証します。

id tokenのpayloadに含まれる内容は以下になります。(ドキュメント)

{
  iss: 'https://appleid.apple.com'
  sub: // The unique identifier for the user.
  aud: // Bundle ID
  exp: // expire time
  iat: // The time the token was issued.
  nonce: // nonce
  nonce_supported: true or false, 
  email: // The user's email address.
  email_verified: true or false,
}

subがuser identifierになるので、これを使ってユーザーを識別します。

まとめ

このように、iOSアプリ側は割と簡単に実装できますが、サーバー側は結構やることがあります。Googleみたいにサーバ側用のライブラリが用意されていればよいのですが、残念ながらAppleは用意してくれていません。。Githubにいくつかライブラリがありましたが、実装が間違っている(特にid tokenのverify周り)ものがときどき見受けられたので選定には注意が必要かなと思いました。Sign in with Appleを導入し、かつ自前でサーバー側も実装する場合は余裕を持って取り組んだほうがよさそうかなと思いましたので、まだ3ヶ月くらいありますが早めに対応したほうがよさそうでした。

最後に宣伝です!

コネヒトではエンジニアを募集しておりますので少しでも興味のある人はお話だけでも聞きにきてください! www.wantedly.com

Zoomウェビナーを使ったオンライン勉強会の裏側

こんにちは。2017年11月にAndroidエンジニアとしてjoinした関根です。03/11(水)にリモートワークを考えよう、というテーマでオンラインの勉強会を開催しました。パネリストとオーディエンスのみなさま、誠にありがとうございました!今回はその勉強会の配信の裏側を書かせて頂きます。

なお、当日の様子とLTスライドは下記の記事内に掲載しています。 www.wantedly.com

開催する上で考えたこと

今回のイベントは普段のオフラインの勉強会とは違い下記のような制約がありました。

  • パネリストがオンラインかつ複数拠点で発表できること
  • オーディエンスがなるべく手間をかけずに参加できること
  • オンラインでもLTに対して質疑応答が可能なこと
  • オンラインでも参加者全員がコラボレーションの体感が得られること

これらの制約をクリアし、どのようなツールでどのようなコミュニケーション設計にすれば、普段の勉強会と変わらない体験を提供できるかのかを考えるところから始めました。

どのツールを利用するか

結論から書くと今回はタイトルにある通りZoomウェビナーを利用しました。 選択した理由としては下記の点です。

  • 画面共有機能でスライドを共有できるのでパネリストが集まる必要がなかったこと
  • 質疑応答機能、チャット機能、手を上げる機能など双方向のコミュニケーションを取る機能が充実していたこと
  • 視聴者はアプリのインストールが不要で参加できること

コネヒトでZoomを試験導入中で使い慣れていたことや、ビデオ通話が高品質で安定していたことが理由としてありますが、先述した制約の全てを解消することができたのでZoomを選んで正解だったと考えています。注意点ですが、Zoomウェビナーはプランにより最大参加人数が決まっているので、最適なプランを選びましょう。*1

配信トラブルがあった場合

オンラインイベントがはじめてだったので、イベント時に配信トラブルが起きることも考えられました。Zoomウェビナーにはレコーディング機能があり、後日動画を公開することが可能で安心感がありました。 録画したものはYoutubeに公開していますので、是非ご覧ください! www.youtube.com

コミュニケーション設計はどうするか

オフライン勉強会を開催が決定して一番悩んだのが、コミュニケーション設計をどうするかでした。 普段の勉強会とは違い全参加者がオンラインでコミュニケーションをとる必要があるので、普段の勉強会とは違った難しさがありました。

参加者の役割と可能な操作

まず簡単にZoomウェビナーの各参加者の役割を解説します。 この役割のメンバーがそれぞれにどのようにコミュニケーションをとってもらいリモートワークへの理解を深めるかを考えなければいけませんでした。

役割 ビデオ通話 チャット Q&A投稿 手を挙げる機能
ホスト オペレーター できる できる 回答のみ できない
パネリスト 登壇者 できる できる 回答のみ できない
オーディエンス 観客 パネリストに昇進することで可能 できる 質問と質問への投票 できる

これを前提のどのようなコミュニケーションを取ることが最適か相談し方針を決めていきました。概ね以下のような議論を行いました。

コミュニケーションの課題と対策

オフラインでのリアクションをオンラインでどのように再現するか?

オフラインの勉強会では自然と生まれる拍手や歓声がオンラインでは難しいので以下のような状況が想定されました。

  • パネリストにオーディエンスの反応が伝わりにくい
  • 全参加者が勉強会に参加してる感が薄まる

これはチャット機能を利用し、👏👏👏👏👏👏👏や888888888のようなコメントを書き込んでもらうことで登壇者に参加者のリアクションが伝わるような工夫をしました

質疑応答はどのように実施するか?

オフラインの勉強会で行われているのと同じように、質疑応答の時間を取らないとリモートワークの知識を深める場としての意義が少し低下してしまう様に思いました。これについてはZoomウェビナーの機能を踏まえ以下の2つの案があがりました。

  1. 質疑応答機能を利用して、テキストで質問する。
  2. 手を挙げる機能を押したオーディエンスのビデオ通話を許可し直接質問してもらう

これはZoomが初めての参加者が多くいることが予測されたので、オーディエンスがよりシンプルな操作で質問できる2.の案を採用しました。

ホストとパネリストのコミュニケーションはどうするか?

オフラインのイベントでは、イベント中のコミュニケーションは、カンペを出す、耳打ちをするなどで取ることが可能ですが、今回はパネリストの方がそれぞれ別の場所にいるため、他の方法を取る必要がありました。これは以下のような案があがりました。

  1. Slackなどチャットツールで連絡を取り合う
  2. Zoom内でホストとパネリストのみへの発言機能を利用する

結論としてZoomウェビナーのチャット機能では誤操作の可能性があったため、Slackでコミュニケーションを取る方法を採用しました。

これ以外にも相談したことは数多くあるのですが、紹介しきれないのでここまでとし、次は当日の流れを紹介します。

当日の流れ

当日は以下のタイムラインで進行をして行きました。

17:30 - 18:30(リハーサル)
18:50 - 19:00(前説)
19:00 - 19:40(LT&質疑応答)
19:40 - 19:45(結び)

それぞれの様子を簡単に紹介して行きます。

リハーサル

Zoomウェビナー機能の実践セッションを利用しホストとパネリストで、リハーサルを行いました。 パネリストの皆様とイベント開始前に簡単な打ち合わせをしながら下記の確認をしました。

  • 画面共有の操作手順の確認
  • 映像と音声の見え方聞こえ方チェック
  • 質疑応答の流れの共有

他にも質疑応答時の流れをリハーサルしたり、オーディエンスからの見え方を確認するなど、ギリギリまでバタバタとしながら本番に臨みました。

前説

司会からオーディエンスに向けて以下のような説明を行いました。

  • 登壇者の画面がみれているかの確認
  • リアクションの取り方の説明
    • チャットの画面を開いて、リアクションの練習をしてもらう
  • 質疑応答の説明
    • 手をあげる機能を利用してもらう
    • ホスト側でビデオ通話を許可するので直接質問してもらう

開始時に会場側でハウリングが発生したり*2、司会の映像が遅れるなどのトラブルもありましたが、参加者のみなさんに、前説からチャットで盛り上げていただいたので、あたたかい気持ちでスムーズにイベントを開始することができました。

LT&質疑応答

概ねスムーズに進行できたと思いますが、はじめてのオンラインイベントらしく、下記のようなちょっとしたトラブルもありました。

  1. 手を挙げる機能を利用した質疑応答で、立候補者がでなかった
  2. オーディエンスのチャット設定がパネリストだけに見えるようになっていた

これらのトラブルにも以下のように、参加者の皆さまのご協力により、それぞれ対応をすることができました。

  1. パネリストの方にチャットから質問を選んでもらうやり方に切り替える
  2. 司会からチャットの設定を変更するようにオーディエンスに促してもらう

パネリストとオーディエンスの皆さま、スムーズなイベント進行にご協力いただきありがとうございました!!

反省点

今回はじめてオンライン勉強会を開催したため、様々な点で反省はあるのですが、特に質疑応答の体験をもう少しよくできたと感じています。次回開催時はZoomの質疑応答機能を利用してみたいと思っています。 最後となりますが、今回のイベントの経験オンライン勉強会用のチェック項目を掲載し、本記事の締めとさせて頂きます。*3

オンライン勉強会用チェック項目
事前準備

- 周りの音が入り込まない静かな環境を用意できるか
  - ヘッドフォンがあると安心
- 配信で利用するPCは安定して映像音声を届けられるか
  - 可能ならば予備のPCを用意しておく
- オンラインでのリアクションを決める
- 質疑応答の方法/流れを決める
 - オーディエンスへの説明の方法も一緒に決める
- 録画機能を利用するかを決める
  - 事後配信をするかも一緒に
- 参加者に配信URLを共有するタイミングを決める
- リハーサル時間を当日に用意する
   - 特に質疑応答の手順は複雑なので入念に

本編中

 - ハウリングに気をつけよう
 - オーディエンスのコメント設定は全員向けになっているか
   - デフォルトではパネリストにだけ見える設定
 - 周りの雑音に気をつけよう
 - 録画機能状況に気をつけよう
 - 配信画面への映り込みに気をつけよう

ここまでお読み頂きありがとうございました!

*1:ZoomミーディングのアドオンなのでZoomミーディングのプロプラン以上の契約も必要です。

*2:犯人は私です

*3:Zoomウェビナーの文脈が強めです

リモートワークについて考える勉強会(オンライン開催)でもらった質問にすべて答えます

こんにちは、エンジニアの@dachi_023です。03/11(水)にリモートワークを考えよう、というテーマでオンラインの勉強会を開催しました。発表・参加していただいた皆さん、ありがとうございました!発表資料や雰囲気などは下記の弊社広報ブログにまとまっていますのでこちらもぜひご覧ください。

www.wantedly.com

近い内に録画した内容に字幕等つけたものをアーカイブ配信する予定ですので途中からしか見れなかった方や気になった方はそちらをお待ちください(というのを気軽にできるのもオンライン配信のいいところだな、と思いました)。

チャットでもらった質問について

今回はZoomのウェビナー機能を使って発表&その場でQAをしたんですが、時間の関係ですべての質問にはお答えすることができなかったので本投稿ですべてお答えしていきます。

※ 発表時に回答した質問についても再掲(もしくはより詳細に回答)しています。

職種によってリモート率とか変わったりしますか?

「この部は全然リモートしてないね」とかはないです。webサービスの会社なので基本はリモートワークでも働けます。ただ、会社に用事がある場合等は各々の判断で通勤のピークタイムを避けつつ出社しています。

sneekで背景見られたくない方とかはどうしてるんでしょうか?

(Zoomにはバーチャル背景があるが、他のサービスにはない。どうするか?という話)

Snap Cameraのフィルターには、顔の加工だけではなく背景も加工してくれるものがあるのでそういうのを使うといいかもしれません。

f:id:dachi023:20200312212651p:plain
例えばこれはナゲットなんですが、背景付きなので部屋が映りません

リモートワークで不便はありますか

導入直後はツールの使い方に慣れていないため、通話中に一斉に喋ってしまったりとかしてワチャワチャしてしまうことが多かったです。あとは子供が仕事中に絡んできたりするので最初は大変でした。

リモートワーク推進メンバーは、どうやって選定されましたか?

立候補した人で構成されています。そのメンバーで使えそうなツール候補のリストを作り、検証しながらどれを正式採用しましょうかね?という話を進めていきました。

リモートワークでも勤務時間ってあるんですか?

コアタイムがあるのでその時間内は確実に働いているようにしています。それ以外は家庭の状況などに合わせて働いています。なので、勤務時間の管理はオフィスワークしていた頃と変わらずやっています(打刻はSlack上からやっています)。

リモートで使用するツールの導入判断で、意外と重要なポイントってなにかありましたか?

リモートワークに限らないのですが「安定しているか」は大事だと思いました。例えば、Slackが頻繁に落ちるサービスだったらコミュニケーションが全然取れなくなってしまうリスクがあるので選びません、といった感じです。あとはツールを増やしすぎないように気をつけました。もちろん必要なら入れるんですが、複数のツールを組み合わせないといけないとなると単純に面倒なので・・・。

リモートワークを導入するのに大変だったことはありますか?

どういう心持ちでリモートワークすればいいだろうね、とかどういうツール使うと仕事が捗りそうかな、とかそういうドキュメントを沢山作ったのでその辺は結構時間がかかったかもしれません。あとは、私が対応したわけではないのですが、セキュリティまわりの対応とかは大変そうだなあと思って見ていました。

各自、在宅での誘惑はどのように向き合うようにしていますか?

私の場合はテレビが絶対見ることのできない方向にデスクを置いてます。今は目の前に壁があって、壁を見るかディスプレイを見るか、くらいしか選択肢がありません。あとは環境音とかがなるべく聞こえないように&通話したい時にすぐ繋げられるようにワイヤレスイヤホンを付けっぱなしにしています。

Zoom慣れない方へのレクチャーで工夫したことはありますか?

ミーティングの始め方はどうやるか?というレクチャーは厚めにやりました。Zoomはミーティングの設置だけでも設定する項目が多く面倒なので、ZoomのSlack App使ってミーティング開始するとログイン以外は不要で簡単ですよ!とかGoogle Calendarの予定にZoomのURLを紐付けると探しやすいよ!とかそういう話をしました。簡単に始められそうだな!という感覚を持ってもらうのを大事にしました。

初めてリモートワークをする人や、社内の人の反応はどうですか?

そこまで不便はしてなさそうかな?と思っています。不便だなと思った点などは共有してもらってなるべく早めに改善するようにして、ずっと不便な状態にはならないように気をつけています。

Zoom のホスト権限の管理などはうまく回ってらっしゃるのでしょうか

現時点だと推進メンバー、マネージャー以上のメンバー、人事や営業など外部の方とミーティングを設定する必要がある人に付与しています。マネージャー以上のメンバーとしているのはマネージャーに付与することで各チームに1人以上はホストがいる状況が作れるからです。

リモートのタスク管理とかで、問題とかありますか?

Asana, Trello, GitHub Project, ZenHubなど、チームごとに使っているものは異なりますがオンライン上で管理しているので特に困ることはありませんでした。あとはデイリースクラムや朝会などをZoomで開催し、タスクの確認をしてチーム内の認識を揃えるようにしています。

リモートで仕事外のコミュニケーションはどう取っていますか??(リモートランチや飲み会とか)

飲み会はやったことないですがランチはやりました(ちょうどこの発表当日の昼休みでZoomで繋いでランチしました)。最初は億劫になりがちなんですが慣れてくると良いものです。

管理が行き届かない場合のトラブル例とかはありますか?

コネヒトではトラブルとかは発生していないんですが、例えばメンバーの管理という観点で見ると「サボらないんですか?」はよく聞かれます。個人の意見としては、そこを管理する必要はない(= サボった分あとで頑張らないといけないのはサボった人なので・・・)と思います。モノの管理の話だと、リモートワークのために自宅に会社の備品などを持ち帰る必要があったりするのでその辺の管理は各自お願いしますね、とかでしょうか。

さいごに

以上となります!予想以上に多くの質問をいただくことができました。また、皆さんのリモートワークへの関心の高さも伺えたような気がしています。今後も引き続き参考になりそうな情報を発信していきます💪

PR

先月書いたブログでもまとめていますのでこちらも良ければ読んでみてください。

tech.connehito.com