疫学専門家このブログのモットーは『研究ライフをほんのり豊かに』。/こんにちは、すきとほる疫学徒です。【初心者のためのRで医療ビックデータ解析】シリーズは、「これまでデータの解析を行ったことがない人」を対象にして、Rで医療ビックデータを解析する方法をわかりやすく解説していきます。全てのシリーズを受講し終えた時点で、「診療報酬データやレジストリーといった医療大規模データを、自立して解析できる」状態になることを目指しております。全研究者、Rユーザー化計画、ここに始動す。こちらの記事はパート5になりますので、まずそれ以前のパートをお読み頂いてから、この先に進んで頂けますと、より一層Rの勉強が楽しめるかと思われます。すきとほる疫学徒からのお願い変数作成におけるTipsこの章では、Rを使って解析に必要な変数を作成する方法を学んでいきます。その上で押さえておくべきTipsがあるので、最初にさらっていきましょう。変数名は全て英語、かつ記号は_のみ以前の記事でお伝えした通り、Rでは日本語がうまく作動しません。新たに変数を作成する際には必ず英語を使いましょう。同じ理由でほとんどの記号が作動せず、使えるのは”_”のみです。変数名は上書きしない例えば、連続変数であるageを加工して、カテゴリー変数のageを作るとしましょう。この際、作成する変数名は元のageという変数名とは異なる変数名にしなければなりません。一つ目は以下で紹介した通り、コードエラーのダブルチェックをするためです。【遵守できてる?】医療大規模データベース解析で絶対に守るべき5つの心得Codeを書いてageという変数を加工しても、本当にあなたが望む通りに加工できているかはしっかりと確認しなければわかりません。変数作成後には必ず、元の変数と新しい変数を比較し、想定した通りの加工が行われているかをチェックしましょう。このために、元の変数を残しておく必要があります。二つ目は、修正をしやすくしておくためです。「そもそもカテゴリー変数ではなく、連続変数として解析に投入したい」と修正が必要な状況になったとしましょう。この時、元の変数を残しておけば、少しコードをいじるだけですぐに修正を反映できます。一方で、元の変数が完全に消えてしまっている場合は、ひどい時にはデータ全体を再度読み込みなおなねばならないことがあり、データの容量が大きい場合には手間になります。これら二つの理由から、変数を加工する時にも、必ず元の変数は残しておくようにしましょう。そのような変数がいつまでもデータセットに残り続けているのも解析に誤った変数を投入してしまうリスクをあげますので、私はいつも解析の直前に不要な変数を全て落とし、解析に必要な変数だけを含んだデータフレームを作成するようにしています。変数名に規則性をもたせるというわけで、Rで変数を加工していくと、続々と新しい変数がデータフレームに追加されていくことになります。「この変数は、こういった加工を施した変数!」ということを、変数名を見ただけで一瞬で識別できるような、自分だけの規則を作るようにしましょう。何度もRを使って解析していると、「あー、この名前だと混乱しやすいな、ああしてみよう」というように、自分でお気に入りの名付け方が見えてくると思うので、試行錯誤してみてください。これは変数名ではなく、作成したデータフレームや、解析結果にも言えることです(Rでは、ロジスティック回帰などの解析結果にも名前を与えて、保存します)。最新の変数がわかるように、変数名の後にナンバリングするというような感じです。ageに対し、3度ほど加工し、最終的にカテゴリー変数になった場合には、age3_cといった名前になるということですね。内容がわかるワードを追加するというような感じです。3つの包含基準、2つの除外基準を適用させて、df5となり、そこで解析対象がFixであれば、dfxとします。数が10を超えてくると、「誤ったデータフレーム名を書いてしまった」なんてことも全然起こりうるので、データフレームを名づける時には、一眼見て識別できる名前をつけるように心がけましょう。次に対象集団そのまた次に主たる曝露(バリエーションがあれば)最後にアウトカム(バリエーションがあれば)としています。主たる曝露が薬剤Aで、アウトカムが在院日数、だとすると、"glm_agelow_drugA_LOS"というふうに名づけています。増えてくると、どの解析結果がどの解析に対応しているのか、本当に混乱しますので、一眼見て識別できる名称をつけてあげましょう。カテゴリー変数はカテゴライズの方法がわかるようにするたとえば、deathという変数があり、カテゴリーが1/0だったとしましょう。良いでしょう、ではこちらは?sexカテゴリーは同様に1/0です。さぁ、どっちが女性でどっちが男性でしょうか?「いや、でも自分でコーディングしてるんだから、作った時にどっちを1でどっちを0にしたかなんて覚えてるよ」と思うかもしれません。安心してください、絶対に忘れます。医療大規模データを解析するCodeを書く上では、自分を信用してはいけません。仮に「死亡=1、非死亡=0」だと思っていたものが、本当は真逆だとしたら?当然、解析の結果も真逆になりますよね?しかし、当の解析者本人はそのことに気づかず、「薬剤Aの内服が、死亡を抑制する効果があることを示唆している!!️」などと声高に叫んでしまうかもしれません(本当は抑制どころか、死亡を誘発しているのに)。以前も説明した通り、医療大規模データ解析においては、本当に些細なコーディングエラーが致命的なミスを引き起こします。いうわけで、カテゴリー変数を作る際には、必ず変数名からカテゴライズの法則がわかるようにしておきましょう。deathという変数であれば、1/0ではなくyes/noとコーディングしておく、sexという変数であれば、female/maleにする、もしくは変数名自体をfemaleにしてyes/noとしておく、などの工夫が可能です。変数を加工してみようでは、上に述べた法則に則って、変数を加工していきましょう。ここからは、変数の加工に必要な関数を紹介してきます。mutate()mutate()は、新たに変数を追加する際に使用する関数です。連続変数であるageとアウトカムのdeathとの間に非線形の関係が観察されたため、解析にageの二乗項を入れるとしましょう。head()mutate()では、まず新たに作りたい変数名を左側に書き、=で繋いだ右側にその条件を書きます。mutate()とするだけでは、瞬間的にage_2という変数を作成するだけで、age_2という変数を持ったデータフレーム自体が作成しないからです。mutate()という指示を出しているわけですね。ちなみにここでは、変数を追加しているだけで、包含・除外条件の適用のように対象集団自体が変わるような加工を行っていないために、df1のように新たな名称のデータフレームは作成していません。weight/height^2)でBMIを計算したりします。そんなmutate()ですが、これから紹介するいくつかの関数と組み合わせることで、さらに複雑な変数を作成することができます。case_when()case_when()は、とてもとてもとてもとてもとてもよく使用します。ageをカテゴリー変数にしたいとすると、こんな感じ。head()mutate()で作成したい変数名を書き、=の右にその条件を書いています。case_when()は、左側に条件を書き、~の右側にその条件を満たすカテゴリー名を書きます。事前に「Rでは記号は”_”しか使えない「と述べていましたが、文字列のカテゴリー名を作成する際にはその他の記号やスペースも使用することができます。head()ちなみに、Rで等式を使う際には、上のように”=”ではなく”==”と書く必要があります。Bのように条件づけしたければ、”|”で繋いでやればOKです。case_when()の中身は連続変数だけでなく、カテゴリー変数をとることもできます。その場合は、等式・不等式の右側にカテゴリー名を記載することになります。連続変数であるADLを、以下のようなカテゴリー変数にしてみましょう。ADLいかがでしょうか?はい、コードにするとこうですね。head()繰り返しになりますが、変数作成後には必ずオリジナルの変数と見比べて、求めていたカテゴリーが作成できているかを確認しましょう。sexという変数をfemaleにして、女性ならYes、男性ならnoとするにはどうしたらいいでしょうか?こうですね。"No"))if_else()さて、case_whenと同じような関数にif_else()というものがあります。case_whenは複数通りの条件を設定できたのに対し、if_else()は2通りまでの条件設定を行います。先ほどcase_when()で作成したfemaleという変数をif_else()で作成すると、こうです。“1”)、その次にその条件を満たした際に返す値を書き(”Yes”)、最後にそ例外の時に返す値を書きます(”No”)。このように、「AならばX、それいがいはY」という形で条件付けを行いますので、if_else()と呼ばれているわけですね。それぞれの条件に対して文字列でなく数値を書くこともできます。欠損の取り扱いさて、上記で紹介したcase_when()とif_else()ですが、変数によっては欠損を何らかの値に置き換えたい、もしくは何らかの値を欠損に置き換えたいという状況があるかもしれません。オリジナルのデータで欠損が9999という数値で記載されている時などですね。このような時も、mutate()、if_else()で対応することができます。連続値のADLに対して、0を欠損にしてやりたいとしましょう。0を考慮しない場合のコードは以下でしたね。NA_character_,という行が追加されています。余談ですが、Rには変数の方があるとお伝えした通り、欠損を表すNAにも方があります。NA_integer_NA_real_Na_character_NA_complex_です。上から順にそれぞれ、integer、double、character、complexに対応しています。ADL”など)、作成される変数がcharacter型となります。そのため、欠損もcharacter型である必要があるので、NA_character_を指定したわけですね。ADL"))こんな感じでエラーが出ます。他のカテゴリーを数値にした場合には、NA_real_を入れてやれば、解析が回ります。3))NAの型はうっかりしていると結構な頻度で間違えてエラーが返ってきますので、気をつけましょう。私は作成後の変数の方を確認するのが面倒なので、エラーが返ってきた時にはとりあえずその他のNA_****の方を入れて、回ったものを使うようにしています。across()これはRに慣れてくれば使ってみると良いと思いますが、across()という非常に便利な関数があります。複数の変数に対して0/1を”No”/”Yes”に変換するような作業をするとしましょう。そんな時に、変数ごとにこのようなコードを書くのは非常に面倒ですよね。"No"))across()は、対象に選択した複数の変数に対して、同時に指示を飛ばすことができます。"No")))他にも、以下のように一括でfactor型の変数を指定することもできます。"No")))ただ、このような一括選択だと、思いもよらぬ変数まで指定されてしまう可能性があるので、私は面倒でも上記のように一つ一つ変数名を書くようにしています。変数の指定方法は他にも様々ですので、ぜひネットで検索してみてください。ちなみに、上のようなCodeだけだと、オリジナルの変数がそのまま加工された変数に置き換わってしまい、作成前後での比較ができません。そんな時は、以下のように”.names=”を使ってやりましょう。"{.col}2"))“”の中に新たに名付けたい変数名を書き、今回は2を付け加えています。すると、このようにacross()で選択した変数名の後ろに2が追加されていることがわかります。2でなくとも{.col}_100とか、Anyname_{.col}_9999とか、好きなような名前をつけてあげることができます。relevel()多変量回帰などの回帰分析にカテゴリー変数を投入する際には、各変数ごとにrefereneとなるカテゴリーを定めます。データの記述統計量を算出する際にも、カテゴリーの並び方に従って結果が返ってきます。Highという並び順でカテゴリーを配置し、さらにreferenceにはLowを設定したいのではないでしょうか?そんな時、もしmutate()でageをカテゴリー変数化した際に、Midがreferenceになっていたらどうするか。そこで登場するのが、ordered()とrelevel()関数です。ordered()は、以下のようにその変数のカテゴリーの並び順を全て指定します。smoker"))すると、df$smoking_cと打ち込むと、以下のようにカテゴリーの並び順を示すLevelsという行が追加されるようになります。Rは賢いので、連続変数をカテゴリー変数にした際には、小さい数字に対応するカテゴリーから準備levelを決めてくれるのですが、私は念の為、カテゴリー変数を作成した際には必ずlevelを再定義してやるようにしています。relevel()も似たような関数ですが、こちらはreferenceとなるカテゴリーのみを指定します。"referenceにしたいカテゴリー名")で設定できます。group_by()解析をしていると、グループ別(たとえば居住エリアとか)に要約した何らかの変数を作成したいというモチベーションが生まれることがあります。volumeなどですね。volumeは患者の予後を予測する重要な因子であることが明らかになっておりますので、何らかのオペを受ける患者をコホートとして因果推論を行う場合には、交絡因子として解析に投入した方が良いでしょう。ここで新たに各患者がopeを受けたかどうかを表すope変数、および入院年を表すyearを追加しますので、以下のCodeを走らせてください。volumeを作成しましょう。Codeにすると、こうです。ungroup()group_by()で病院を示すhosp_idごとに解析をするように指示を出し、mutate()でope_countという変数を作成、さらにその方法として、opeという変数の合計値をカウントするようにsum()で指示を出しています(オペは0/1の整数型の変数ですので、足し算ができます)。TでNAがある患者を無視して合計値を出すように指定しました。volumeが各患者に割り振られます。volumeは年ごとで変化するため、病院別だけではなく年別に算出してやる方がよく、その場合は以下のように書きます。ungroup()このように、group_by()の中に複数の変数を入れてやれば、複数のサブグループで解析を行うことができます。volumeを作成するのが目的だったため、sum()を使いましたが、group_by()では他にもmean()n()mix()など様々な関数を組み合わせることができます。他にも知っておくと便利な関数があるので、紹介します。cut_number()は、連続変数を各群の対象者数が等しくなるように分割します。“グループ名3”))という感じで使います。cun_interval()は、連続変数を各群の幅が等しくなるように分割します。rename()は変数名を変更します。select()は特定の変数のみを抽出します。雑多に作成した変数たちから、最終解析に必要な変数のみを残したい時などに使います。select(-変数名)とすれば、その変数を除外してくれます。remove()はEnvironmentからデータフレームを削除します。他にも便利な関数は色々あるので、いじりながら覚えていくと良いかなと思います。終わりに今日はちょっとボリューミーになっちゃいましたね。これで解析に必要な変数の作り方を知ることができました!医療大規模データ解析の中でも、特に時間がかかるフェーズです。この次は作成した変数に基づき、対象者の包含・除外を行う方法を学びます。それが終わったらいよいよ解析!!初心者のRで医療ビッグデータ解析も、ようやく折り返し地点となりました。ここからは解析結果が見れて、「おお!」と感動するフェーズが多くなりますので、もっともっと楽しく学んで頂けるようになると思います。Want方式を採用しています。教育に投資できる方だけがさらに知識を身につけ、そうでない方との格差が開いていくという状況は、容認されるべきではないと考えているからです(そもそも私程度の記事によって知識の格差が広がると考えていることが、勘違いかもしれませんが)。私自身も高校卒業後は大学・大学院の学費、生活費と自分で工面する中で、親の支援を得られる友人たちがバイトをせずに学習に集中したり、海外留学や旅行などの経験を積んだりする様子を見て、非常に悔しい想いをしたことを思い出します。読者の皆様におかれましては、「勉強になった!」、「次も読みたい!」と本ブログに価値を感じてくださった場合のみ、ご本人の状況が許す限りにおいて、以下のボタンからご自身が感じた価値に見合うだけの寄付を頂戴できますと幸いです。価値を感じなかった方、また学生さんなど金銭的に厳しい状況にある方からのご寄付は一切不要です。疫学専門家このブログのモットーは『研究ライフをほんのり豊かに』。疫学専門家このブログのモットーは『研究ライフをほんのり豊かに』。〜研究生活をほんのり豊かに〜.ホームシェアメニューTwitterTOPへ。