データサイエンスチームで、はじめてのインターンシップを受け入れました

はじめに

株式会社PREVENTのデータサイエンス(DS)チームの戸田です。今回はDSチームで受け入れたインターンシップの活動を報告します。

ツイッターのDM経由で連絡をいただいた東京大学 公共健康医学専攻の瀧澤さんは、9月6~24日の実稼働日が13日と非常に短い期間のなかで、こちらの用意した以下の課題を実施しました。

  1. 弊社解析業務のMyscope*1のデータクレンジング
  2. データセット仕様書や業務についての仕様書などのドキュメント整理
  3. 社内匿名加工済みデータを用いた先行文献の追従解析

有給のインターンシップという形でしたので、業務タスク(1, 2)をお願いしつつも何か学びをご提供できればと思い、先行文献の追従解析(3)を追加しました。盛りだくさんで課題が多過ぎたかと思いましたが見事にこなしていただきました。

リモートでのインターン受け入れ

9月30日まで東京では緊急事態宣言が出ていました。そのため、インターン開始の9月6~10日までホテルにてリモートで作業していただき、その後、マスク着用・入室時の手指のアルコール消毒など弊社が定める感染予防対策を徹底した上で、9月13日よりオフィスでインターンを開始しました。この辺りは瀧澤さんに柔軟に対応していただきました。

リモートのみでのインターン受け入れはなかなか難しいなという印象でしたので、今回のように前半リモート、後半は出社で今後のインターンを実施する可能性があります。

課題の成果報告

1. Myscopeのデータクレンジング

健康診断データおよびレセプトデータは、クライアントの保険者様からお預かりし、弊社内のレポート作成コードに合うように整形されます。Myscopeでは、機械的にクレンジング作業を行うためのアルゴリズムを組んでいますが、人によるチェックとコードの変更が必要な箇所があります。お預かりした生データから指定したフォーマットに変換する作業を期間中に2件行なってもらいました。

2. データセット仕様書や業務についての仕様書などのドキュメント整理

弊社内で保有しているデータについては、ER図が存在しているものの定義書やプロファイルがまだ不十分です。そこで、ER図と指定した参考資料を用いて定義書の作成してもらいました。エディタの指定はしませんでしたが、フォーマットはMarkdownに統一しました。 (レセプトDBの定義ドキュメントの一部) f:id:D_Sk:20211102110018p:plain

3. 先行文献の追従解析

今回参考にさせていただいた論文は2021年に公開されましたPhysician visits and medication prescriptions for major chronic diseases during the COVID-19 pandemic in Japan: retrospective cohort study(I.Osawa, et al, BMI Open, 2021)です。COVID19流行による緊急事態宣言前後での慢性疾患に対する医師の診察と処方行為についての日本の観察研究です。proportion of days covered:PDC(処方日数を対象期間の日数で除した割合)という指標を抜き出すことや時系列でデータを取り扱うことがレセプトの取り扱いを実践してもらう良い題材となると考え、インターン課題として選択しました。

結果のサマリー

弊社内匿名加工済みデータセット(225,237件、2017.01~2020.12)を用いて、論文にある指標を計測しました。 詳細をみるとまだ考察しきれていない部分はありますが、1回目および2回目の緊急事態宣言前後で受診回数が減少していることがわかります(スライド8枚目)。参考にした先行文献と類似した結果が得られました。

www.docswell.com

インターンシップを参加した感想

インターンシップに参加した瀧澤さんより感想をいただきました。

今回インターンシップをさせていただいた瀧澤です。
私はデータサイエンスの学習はしておりましたが、レセプトデータなどの生データに触れる機会はなく、「データサイエンス職に興味はあるが、実際の業務は自分に合っているのだろうか?」という不安がありました。今回のインターンシップで 、データ分析の8割を占めるといわれるクレンジング業務や実際のレセプトデータに触れることで、PREVENTのデータサイエンス職の業務内容がイメージしやすくなりました。学習したことが実際のデータではスムーズにいかないことも体験でき、とても充実し学びの多い経験となりました。 これまでレセプトデータとの関わりがなかったのですが、ドキュメント作成と論文追従を経て、受診から請求までのデータの流れをイメージできるようになりました。
PREVENTのインターンシップを経験し、よりデータ分析に関わりたい気持ちが強くなりました。この経験は自分にとって資産だと感じています。受け入れてくださったPREVENTの皆様、本当にありがとうございました!

まとめ

DSチームでのインターンの受け入れは初めてのことでした。非常に優秀な方でしたのでなんとか形にしていただき、さらには今後インターンシップの方針もだいたい定めることができました。この場を借りて瀧澤さんにはお礼を申し上げます。

今回の経験を踏まえて、インターンの方には基本的に

  1. 弊社解析業務のMyscopeのデータクレンジング
  2. データセット仕様書や業務についての仕様書などのドキュメント整理
  3. 社内匿名加工済みデータを用いた先行文献の追従解析

を実施していただく予定です(※ もちろん期間に応じて課題設定は行います)。ヘルスケアスタートアップが扱う生データに触れていただく機会とデータの活用方法について体験いただければと考えています。ただ、ある程度のドメイン知識が必要ですので、前半はドキュメント作成などのタスクで特有なデータ構造について学んでもらい、後半にはガンガンコードを書いてデータ分析を進めるという流れが良いかなと考えています。

DSチームのリソース的に多くの受け入れは困難ですが、ご興味のある方が是非ご連絡をいただければと思います。ヘルスケアベンチャーでDSチームが何しているの?実際にどんな業務があるの?今後の展望ってあるの?など、この分野でDSを目指したい方は是非一度コンタクトをとってみてください。

*1:Myscopeの詳しい説明についてはhttps://prevent.co.jp/service/myscope/

ベイジアンネットワークを用いた胃潰瘍罹患者における薬剤処方パターンの探索

【はじめに】

こんにちは。データサイエンスチームです。

今回はPREVENT社内に蓄積されたレセプトデータを用いて、因果探索を行なった事例を紹介します。

続きを読む

CORS(オリジン間リソース共有)とは?

はじめに

こんにちは、フロントエンドチームの高田(@proghallelujah)です。 webアプリケーションを開発していると、このような内容のエラーが出たことがある人は多いかもしれません

Access to XMLHttpRequest at 'https://hoge.com' from origin 'https://fuga.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

このエラーは一体どういったことを伝えているのでしょうか?また、エラー文内にあるCORSというものは一体なんでしょうか?今回はこちらについて解説していこうと思います。

CORSについて

CORSの意味

まず、このCORSというのはCross-Origin-Resource-Sharingの略で、日本語に訳すとオリジン間リソース共有と言います。

このCORSは、あるオリジンで動作しているウェブアプリケーションに、異なるオリジン内のリソースへのアクセスをオリジン間HTTPリクエストにより実行するようブラウザに指示するための仕組みです。


(補足)オリジンとは?

プロトコルドメイン、ポートによって定義されたものです。

例) http://hoge.com:80

こちらの場合、http(プロトコル)+hoge.com(ドメイン)+80(ポート)からできたオリジンです。


なぜCORSが必要か?

CORSは、webセキュリティポリシーの一つSame-Origin Policy(同一生成元ポリシー)によって定められた制限に対応しており、安全なオリジン間のリクエストやブラウザ・サーバー間のデータ転送を行うためのものです。

同一生成元ポリシーとは?

JavaScriptなどのプログラムを用いた通信において、そのプログラムが存在する同一のオリジン内でのみデータアクセスを可能にし他のオリジンへのアクセスをできないよう制限するための仕組みです。

オリジン1: http://hoge.com/dir/page.html
オリジン2: http://hoge.com/dir/shop/main.html

パスは異なっていますが、プロトコル、ドメインといったオリジンは同一のため、アクセスは可能となります
オリジン1: http://hoge.com/dir/page.html
オリジン2: https://hoge.com/dir/page.html

パスは同一ですが、プロトコルが違うため、アクセスは制限されます

なぜ制限するのか?

例えばXSS(クロスサイトスクリプティング)という攻撃手法があります。これは標的とするwebアプリに第三者が外部から悪意のあるスクリプトを埋め込み、アプリが意図をしていない動作を引き起こすようにします。

これは基本的に別のオリジンからの攻撃になるため、同一制限ポリシーがあることで防ぐことができます。

このように異なるオリジンからのアクセスを制限することにより、元オリジンのリソースに対して悪い影響を与えることを防ぐのを目的としています。

制限が適用されないケース

基本的にはJavaScriptによる非同期通信などに適用されますが、htmlベースのものでは制限されないものが多いです

  • <img>タグのsrc属性で読み込まれた画像
  • <link>タグのhref属性で読み込まれたCSS
  • <script>タグのsrc属性で読み込んだJavaScript

などなど、普段よく使っているものの中にも別のオリジンから読み込んでいるものが多くありますが、これらは同一オリジンポリシーが適用されません。

参考

MDN - オリジン間リソース共有 (CORS)

CORS(Cross-Origin Resource Sharing)

MDN - Origin (オリジン)

MDN - 同一オリジンポリシー

Wikipedia - クロスサイトスクリプティング

銀座Rails#24@リンクアンドモチベーション 勉強会の感想

こんにちは!株式会社 PREVENT の開発部門、バックエンドエンジニアチームの松原と申します。

厳しい残暑がようやく和らぎ始めましたが、いかがお過ごしでしょうか?

今回は、8月28日(金)に銀座 Rails に参加した感想と、イベント中に登場した技術、特に詳しく知らない点を学習も兼ねてまとめたいと思います!

ginza-rails.connpass.com

銀座 Rails のイベントに初めて参加したのですが、今回は Devise 、 Rails で行う Distributed Tracing 、 Rails で作る serverless CMS などを学びました。

業務で Rails を扱うようになり八ヶ月が経過しましたが、イベントでテーマとして取り上げられている技術は知らないものばかりで、 Rails に変換して考える段階まで至ることができませんでした。

Rails 的に考察できるととても面白そうなので、 Distributed Tracing について学習し直したいと思います。

Distributed Tracing (分散トレーシング)とは?

分散トレーシングとは、分散されたシステムで処理されるリクエストを追跡するためのものです。

分散トレーシングには主に二つの要素があり、その要素を Span と Trace と呼びます。

Span: 1サービス内の処理を表す。

Trace: Requestのstart-endを含むSpanの集合をあらわす。

イメージは以下のようになります。

f:id:syrengr:20200909190708p:plain

<出典: 分散トレーシングシステムのZipkinを使ってみた話>

分散トレーシングでは、 Span と Trace を可視化し、問題点と処理に時間がかかっている点を確認することができます。また、解決するための手助けをするシステムを分散トレーシングシステムといいます。

Open Tracing について

Open Tracing とは、開発者にシステムトレーサーの追加、またはトレーサーの切り替えを行う仕組みを提供する、分散トレーシングの実装です。

Open Tracing 仕様を実装したトレーサーとして、 Twitter 社が開発した Zipkin や、 Uber 社の Jaeger などがあり、詳しくは以下の資料が大変参考になりました! :)

www.slideshare.net

Distributed Tracing を Rails で行う方法

ネット上の資料を調べた結果、分散トレーシングを Rails で行うには以下の記事が参考になりそうだと思いましたが、翻訳しつつ拝読しても難易度は高く感じたため、今後まとまった時間が取れたらトライしてみたいです。

medium.com

OpenCensus (分散トレーシングを行うためのライブラリ集)を使用すると、 Rails で分散トレースを簡単に採用できるというお言葉が心強いです :)

イベントに参加させていただき、ありがとうございました!

以下でも同様の記事を書いておりますので、ご紹介させていただきます。

銀座Rails#24@リンクアンドモチベーション 勉強会の感想|Sayuri Matsubara|note

季節の変わり目、くれぐれもご自愛ください。それでは、失礼致します。

半年間リモートワークを続けてみて感じたこと

はじめに

こんにちは、フロントエンドチームの高田(@proghallelujah)です。

弊社は昨今世界中で発生しているCOVID-19危機のため、2020年3月ごろから一時的にリモートでの業務が可能になりました。 それまでは全ての業務を会社のオフィス内で行っていました(業務委託などの例外はあります)ので、最低限の規約の中でのスタートで本当に大丈夫だろうか?と最初は不安でしたが、今現在でも会社は問題なく動いております。 これは開発部門も例外ではなく、2020年9月現在では全ての開発メンバーが適宜リモートワークを活用しながら業務を行っております。半年間もリモートワークをしていることに記事を書きながら気付いたのですが今ではこれが当たり前になっており、たまに会社に出社するとあまりの人の少なさに少し寂しくなったりもします。

半年間リモートワークを続けてみてどうだったか?メリットデメリットを含め僕が感じたことを書いていこうと思います。

①: 時間を有効に使えるようになった

リモートワークの魅力の一つとして通勤時間が無くなることです。時間をフルに無駄なく使えることの素晴らしさを1日目から実感することができました。 朝起きてすぐに仕事ができるというのはかなり魅力的ですし、早くはじめれる分早く仕事を終え、自分の時間を増やすこともできました。 また、休憩時間に家のことができるので、部屋が少し綺麗になったりご飯の質も少し上がりました笑

ただし、家にいると身嗜みに無頓着になりがちで、僕は髭を剃らなすぎて大変なことになっていました。定期的なビデオ会議等あるので毎日ある程度はきちんとすることが必要です。

②: 予想以上に業務で困ることがなかった

弊社はリモートワーク以前からコミュニケーションツールとしてSlackを、ドキュメント作成にはesaを使用していました。なのでリモートワーク中でも業務についての連絡は特に以前と変わらずに滞りなく行えています。急ぎの用件があっても投稿をすれば間違いなく返答があるので今のところ根本的に業務で困ったことはありません。

ビデオ会議に関してはリモートワーク前は業務で使用することはなかったのですが、これも当初から問題なく運用できています。(弊社開発部門のリーダーは会議ツールに嫌われているのか初回入室のさいは声が聞こえない確率が高いというのが喫緊の問題です)

ただ、痒いところに手が届かないようなことはよくあるのでそのためのドキュメントやルール整備は日々進めていっております。

③: 人と喋る機会が少なくなった

僕は一人暮らしでペット等も飼っていないので丸一日中人と接することがない日もあります。ビデオ会議はもちろんありますが毎日しているわけでもないので、その日した唯一の会話が「袋はいりません」ということもあったり笑。

集中したいときに周りに雑音がなく自分の事に取り組めるのでコーディングにブーストをかけたりはできますが、たまにはみんなでワイワイしたいという気持ちもあります。 上記の通り業務に関するコミュニケーションは問題なく行えてますが、雑談となるとなかなか難しく、discordなどのもくもく・雑談用のコミュニケーションツールやチャンネルなどを用いたりもしましたがなかなかうまくいっていないのが現状です。

④: 家で良い作業をするためには設備投資が必要

僕は1SK(リビング1つとロフト1つ)のアパートに住んでいて、仕事やプライベートも全てリビングで行っているのですが(ロフトは寝室)そのせいか、仕事とプライベートの境界が少し曖昧になってしまっています。ただあまり大きい部屋でもないのでのでこれ以上机を増やすこともできず、こればかりは引っ越すくらいしか手がないのが難点ですね。

また、作業環境も座椅子とこたつテーブルなのですがあまり体にあってないのでだんだん腰が痛くなってきます。一日中同じ場所にいるということを考えると、やはり良い作業環境は必須だなと思います。最近は小さいスタンディングデスクなら置けるかなと試行中です。

⑤: 外に出る頻度が減った・日にあたることや運動の大切さ

通勤が無くなったことで平日に外に出る用事が少なくなり、最初は買い物などの用事をまとめて済ませて3日くらい家にこもりっぱなしという日もありました。必要なこと以外は家から出なくていいのはなかなか楽だなと思ったのですが、流石に不健康すぎると思って毎朝散歩やランニングをするようになりました。

軽い運動をしているということもありますが、日光に直接当たることで体内時計が補正されたのか、家にこもりっぱなしの時より体の調子がよくなった気がします。リモートワークを続けていると普段より体重が増えたという声もよく聞きますが、やはり意識的に運動する機会を作る機会が必要だと感じました。

最後に

リモートワークというのはとても魅力的なものですが、いざ実施するとなると大小様々な問題が発生すると思います。弊社では緊急で始まった施策ではありますがこれを機に正式な形としてのリモートワーク制度を実施するため、様々な施策や環境の整備が弊社では進められています。

現在でも日本中で広がり続けているCOVID-19ですが、PREVENTは病気予防・ヘルスケアに携わる企業としてこれに負けることなく、一人でも多くの方に健康的な生活を送り続けていただけるよう業務に取り組んでおります。

moment.jsで単位を日に指定してdiffを使う時、時間を考えず日が変わったかどうかだけで比較する

結論: startOf('days')で時間をまるめる

const dayOne = moment('2020-01-01 10:00:00').startOf('days');
const dayTwo = moment('2020-01-02 09:00:00').startOf('days');
console.log('dayOne', dayOne.format());
console.log('dayTwo', dayTwo.format());
console.log('diff', dayTwo.diff(dayOne, 'days'));

スクリーンショット 2020-03-22 22.51.26.png

はじめに

こんにちは、フロントエンドチームの高田(@proghallelujah)です。

moment.jsには指定した二つの日時を比較し、出力するdiffという機能があります。

この機能は、2つの日付の差分を時間単位まで観測し、デフォルトでは秒数で出力されます。 diffは第二引数で測定する時間単位を指定することが可能です。しかしその時、内部では秒数を任意の単位に再計算した値を返しています。 また、その時小数点以下は切り捨てられてしまいます

const dayOne = moment('2020-01-01 10:00:00');
const dayTwo = moment('2020-01-02 11:00:00');
const dayThree = moment('2020-01-02 09:00:00');
const dayFour = moment('2020-01-02 10:00:00');

console.log("dayTwo", dayTwo.diff(dayOne, 'days')); // dayTwoはdayOneの時間を過ぎているので1
console.log("dayTwo asFloat", dayTwo.diff(dayOne, 'days', true));
console.log("dayThree", dayThree.diff(dayOne, 'days')); // dayThreeはdayOneの時間を過ぎてないので0
console.log("dayThree asFloat", dayThree.diff(dayOne, 'days', true));
console.log("dayFour", dayFour.diff(dayOne, 'days')); // dayFourはdayOneと同じ時間なので1
console.log("dayFour asFloat", dayFour.diff(dayOne, 'days', true));

スクリーンショット 2020-03-22 22.49.55.png

(tips: 第三引数にtrueを渡すことで値から小数点を切り捨てず返されます)

以下はmomentjsでdiffを行なっている箇所です。 GitHub - moment.js/moment/src/lib/moment/diff.js


厳密な日付を計算するのであればこれが最良ですが、時間を考えず単純に日にちが変わったかどうかを計算したい、といった場合も多いと思います。 startOfを使えば、そのような機能を簡単に実装することができます。

startOfとは

momentの機能の一つで、指定した時間単位の始まりの値を出力します。 スクリーンショット 2020-03-22 23.02.30.png startOfでdayを指定すると、日のはじまり0:00:00に時刻を変換して出力されます。

参考: moment.js - Start of Time

ではstartOfを用いでdiffを使ってみます。

const dayOne = moment('2020-01-01 10:00:00').startOf('days');
const dayTwo = moment('2020-01-02 09:00:00').startOf('days');
console.log('dayOne', dayOne.format());
console.log('dayTwo', dayTwo.format());
console.log('diff', dayTwo.diff(dayOne, 'days'));

スクリーンショット 2020-03-22 22.51.26.png

diffは単位以下の値が同値の場合は1になるので、これで日にちが変わったかどうか計算することができます。

アンチパターンMath.roundを使う

小数点以下が切り捨てられるなら、Math.roundで繰り上げるようにすればよい、という案もあります。 しかし、Math.roundは意図せぬ値まで繰り上げてしまいます。

1. 第三引数にtrueを渡し、Math.roundを使う

const dayOne = moment('2020-01-01 01:00:00');
const dayTw0 = moment('2020-01-02 00:00:00');
const dayThree = moment('2020-01-01 17:00:00');
console.log(Math.round(dayTwo.diff(dayOne, 'days', true)), dayTwo.diff(dayOne, 'days', true));
console.log(Math.round(dayThree.diff(dayOne, 'days', true)), dayThree.diff(dayOne, 'days', true));

スクリーンショット 2020-03-22 23.10.12.png この場合、ある程度時間がたってしまった値だと、日付が同じでも繰り上げてしまいますので使用することができません。 なので、startOfが現状最良の手段だと思われます。


いかがでしたでしょうか?時間単位のはあくまで例に使っただけなので、その他の単位でも使用することができると思います。momentはドキュメントが丁寧でわかりやすく、自動翻訳でもそれなりに見ることができるので、皆さんもよかったらご一読ください。

moment.js - Docs

PREVENTの事業内容について

みなさんはじめまして。株式会社PREVENTの開発部門、フロントエンドエンジニアチームの高田(@proghallelujah)と申します。

こちらのブログでは、わたしたちが社内でどのようなプロダクトの開発を行なっているかや、普段用いている技術や運用方法について、また社内でどのような業務を行なっているかを紹介していこうと思います。

まずPREVENTがどのような会社かを簡単に紹介したいと思います。

PREVENTとは?

PREVENTは一病息災の健康づくり支援モデルを社会にという事業ミッションを掲げる名古屋大学医学部発のデジタルヘルススタートアップの一社です。 主に二つのプロダクトを軸に、生活習慣病の重症化を予防することによって医療費の削減、適正化を目指しています。

プロダクトについて

Myscope

健康保険組合保有する健康診断およびレセプトから独自アルゴリズム生活習慣病などの疾病発生を予測し発症リスクを算出、誰がどの程度発症の危険性があるかリスト層別化したデータを作成、ハイリスク者をターゲットに対象者の抽出を行う医療データ解析事業です。

Mystar

登録された利用者様がモニタリング機器を用いながらアプリに情報を登録し、社内のメンターと呼ばれる医療資格を持った専門スタッフがその情報を元に健康づくりのための個別指導を電話やチャット等のオンラインで提供するオンライン完結型での重症化予防⽀援事業です。

かなりざっくりとした説明ですので、もっと詳しく知りたいという方は以下の記事をご覧いただけたらと思います!

最後に

今後ともさまざまな情報発信をしていきたいと考えております!どうぞよろしくお願いします。

PREVENT