44 関数の作成
44.1 準備
パッケージの読み込み
以下のコードは、分析に必要なパッケージの読み込みを行います。このハンドブックでは、パッケージを読み込むために、pacman パッケージの p_load()
を主に使用しています。p_load()
は、必要に応じてパッケージをインストールし、現在の R セッションで使用するためにパッケージを読み込む関数です。また、すでにインストールされたパッケージは、R の基本パッケージである base (以下、base R)の library()
を使用して読み込むこともできます。R のパッケージに関する詳細は R の基礎の章をご覧ください。
データのインポート
エボラ出血熱の流行をシミュレートしたデータセットをインポートします。データをダウンロードし同じように行いたい場合、ハンドブックとデータのダウンロードの章をご覧ください。データは rio パッケージの import() を利用してインポートしましょう。データをインポートする様々な方法については インポートとエクスポートの章をご覧ください。
また、この章の最後では、2013年のH7N9インフルエンザのデータを使用します。
44.2 関数
関数はコードを理解しやすく、短く、エラーを起こしにくくすることができるため、プログラミングにおいて役立ちます(関数自体にエラーがない場合)。
このハンドブックをここまで読んでくださった方は、無数の関数に出会ったことになります。というのも、R ではすべての演算子が関数呼び出しになるからです。
+, for, if, [, $, { …
. 例えば、x + y
は '+'(x, y)
と同じです。
R は、複数の関数を共に扱う可能性が最も高い言語であり、また、ユーザが簡単に関数を書けるように十分なツールが提供されている言語の 1 つです。私たちはプログラムの繋がりを最初から最後まで考える必要はなく、R では複数の関数をベクトルのように使用したり、他の関数やリストの中で使用することもできます。
関数型プログラミングに関する非常に高度な資料は数多く存在しますが、ここでは短い実用的な例を用いて、関数型プログラミングを始めるためのヒントを提供するにとどめます。その後、参考資料のリンクを参照して、さらに詳しい情報を得ることをお勧めします。
44.3 なぜ関数を使うのか?
見出しの質問に答える前に、次の点が重要です。このハンドブックの ループと反復処理・リストの操作の章に、最初の R 関数を書くためのヒントがすでにあります。実際、if/else や loop の使用は、関数の中で多くの機能の中核です。なぜなら、複数の条件分岐によって、記述したコードが様々な場面に適用できたり、ループ文によってコードを繰り返し実行するのに役立ったりするからです。
別々の変数やデータに、同じコードを複数回繰り返し適用するか?
繰り返しの適用を取り除くことで、コード全体が大幅に短縮され、実行速度が速くなるか?
記述したコードが他の箇所で再度使用されているが、再度使用されたコードの複数箇所で異なる値が使用される可能性はあるか?
前述の質問の答えが YES であれば、おそらく関数を書く必要があるでしょう。
44.4 R でどのように関数を作成するか?
R の関数は主に 3 つの要素で構成されています:
そして、
-
environment()
、関数の変数の位置を特定するのに役立ち、関数が値を見つける方法を決定する
関数を作成したら、関連する関数を呼び出すことで、これらの各構成要素を検証することができます。
44.5 基本的な構文と構造
関数には適切な名前を付ける必要があり、名前を読んだだけでその内容が容易に理解できるようにしなければなりません。実際、Rの基本的な関数の大部分ですでに当てはまります。
mean()
、print()
、summary()
のような関数は、非常にわかりやすい名前となっています関数は、引数を必要とします。例えば、処理するデータや静的な値、その他のオプションオブジェクトなどです
そして最後に、関数はその中核となるタスクと与えられた引数に基づいて出力を行います。通常、出力を得るためには、
print()
やreturn()
などの組み込み関数を使用します。ロジカル値、数値、文字、データフレームなど、要するにあらゆる種類の R オブジェクトを出力できます。
基本的に下記が関数の構成です:
function_name <- function(argument_1, argument_2, argument_3){
function_task
return(output)
}
contain_covid19()
という名前の関数を最初に作ります。
contain_covid19 <- function(barrier_gest, wear_mask, get_vaccine){
if(barrier_gest == "yes" & wear_mask == "yes" & get_vaccine == "yes" )
return("success")
else("please make sure all are yes, this pandemic has to end!")
}
新しく作成した関数の要素を検証します。
formals(contain_covid19)
## $barrier_gest
##
##
## $wear_mask
##
##
## $get_vaccine
body(contain_covid19)
## {
## if (barrier_gest == "yes" & wear_mask == "yes" & get_vaccine ==
## "yes")
## return("success")
## else ("please make sure all are yes, this pandemic has to end!")
## }
environment(contain_covid19)
## <environment: R_GlobalEnv>
では、作成した関数をテストしてみましょう。作成した関数を呼び出すには、他の R 関数と同様に、関数名を記述し、必要な引数を追加します。
contain_covid19(barrier_gest = "yes", wear_mask = "yes", get_vaccine = "yes")
## [1] "success"
明示的に各引数の名前をあらためて指定できます。しかし、R は各引数の定義順序を記憶しているので、あらためて指定しなくても、上記のコードは動作するはずです。つまり、引数の値を正しい順序で書く限り、関数を呼び出すときに引数の名前を省略できるのです。
contain_covid19("yes", "yes", "yes")
## [1] "success"
次に、片方の値が "no"
または not "yes"
の場合はどうなるかを見てみましょう。
contain_covid19(barrier_gest = "yes", wear_mask = "yes", get_vaccine = "no")
## [1] "please make sure all are yes, this pandemic has to end!"
関数定義に定義されていない引数を与えると、エラーが発生します:
contain_covid19(barrier_gest = "sometimes", wear_mask = "yes", get_vaccine = "no")
Error in contain_covid19(barrier_gest = "sometimes", wear_mask = "yes", : could not find function "contain_covid19"
備考: 一部の関数(多くは非常に短くわかりやすい関数です)には、関数名を必要としないものもあり、コード内で直接使用したり、他の関数内で使用したりして、素早い実装ができます。 これらの関数は 無名関数 と呼ばれています。
例えば、以下は、データセットの文字型変数のみを保持する無名関数です。
linelist %>%
dplyr::slice_head(n=10) %>% #base R パッケージにある "head" 関数に相当し、データセットの最初の n 個の観測データを返す
select(function(x) is.character(x))
次は、観測データを 2 行ごと選択する関数です(例えば、患者ごとに多くのレコードを持つ縦持ちデータがある場合、日付や訪問で順番に並べた後などに適切なことがあります)。
この例では、dplyr 処理外に記述する適切な関数は、すべての行番号を含むベクトルに適用する function (x) (x%%2 == 0)
となります。
linelist %>%
slice_head(n=20) %>%
tibble::rownames_to_column() %>% # 最終的な抽出行を明示するために、各観測行のインデックスを rowname として追加する
filter(row_number() %%2 == 0)
base R を利用すると以下のように書くことができます:
linelist_firstobs <- head(linelist, 20)
linelist_firstobs[base::Filter(function(x) (x%%2 == 0), seq(nrow(linelist_firstobs))),]
注意: 関数を使うことがコード実装に役立つのは事実です。しかしながら、複数の関数を記述することに時間を浪費したり、あるいは、十分に考えられておらず、また、適切に書かれていない、つまり、結果としてエラーを返す関数の修正に時間を浪費する可能性があります。そのため、まず R のコードを書き、そのコードが意図した動作をすることを確認してから、上記のような 3 つの主要な要素を持つ関数にすることを推奨します。
44.6 例
それぞれの列の割合を返す
確かに、多くのパッケージには、情報を非常に簡単かつ良い方法で要約することができる素晴らしい関数がすでにあります。しかし、関数を書くことに慣れるための最初のステップとして自分で作ってみることにします。
下記の例では、シンプルな関数を書くことで、同じコードを何度もコピーペーストする必要がないことを示します。
proptab_multiple <- function(my_data, var_to_tab){
#表組みする前に対象となる各変数名を表示する
print(var_to_tab)
with(my_data,
rbind( #次の 2 つの関数の結果を行ごとに結合する
#対象となる変数を表にする: 数値のみ
table(my_data[[var_to_tab]], useNA = "no"),
#対象となる各変数ごとに割合を計算し、その値を小数第 2 位に丸める
round(prop.table(table(my_data[[var_to_tab]]))*100,2)
)
)
}
proptab_multiple(linelist, "gender")
## [1] "gender"
## f m
## [1,] 2807.00 2803.00
## [2,] 50.04 49.96
proptab_multiple(linelist, "age_cat")
## [1] "age_cat"
## 0-4 5-9 10-14 15-19 20-29 30-49 50-69 70+
## [1,] 1095.00 1095.00 941.00 743.00 1073.00 754 95.00 6.0
## [2,] 18.87 18.87 16.22 12.81 18.49 13 1.64 0.1
proptab_multiple(linelist, "outcome")
## [1] "outcome"
## Death Recover
## [1,] 2582.00 1983.00
## [2,] 56.56 43.44
ヒント: 上記のように、一般的なプログラミングと同様に、関数にコメントを付けることが非常に重要です。関数作成の目的は、コードを読みやすく、短く、効率的にすることであることを覚えておいてください。関数の名前を読んだだけで、その関数が何をするのか理解できるようにし、コメントを読むことでより詳細な情報を得られるようにします。
もう一つの方法は、ループ内でこの関数を使用し、一度に処理を行うことです。:
for(var_to_tab in c("gender","age_cat", "outcome")){
print(proptab_multiple(linelist, var_to_tab))
}
## [1] "gender"
## f m
## [1,] 2807.00 2803.00
## [2,] 50.04 49.96
## [1] "age_cat"
## 0-4 5-9 10-14 15-19 20-29 30-49 50-69 70+
## [1,] 1095.00 1095.00 941.00 743.00 1073.00 754 95.00 6.0
## [2,] 18.87 18.87 16.22 12.81 18.49 13 1.64 0.1
## [1] "outcome"
## Death Recover
## [1,] 2582.00 1983.00
## [2,] 56.56 43.44
よりシンプルな方法としては、“for loop” の代わりに base R の “apply” を使用することで、以下のように表現できます:
ヒント: R は関数型プログラミング言語として定義されており、ほとんどの場合、コードを実行する際には組み込み関数を使用します。関数の書き方に慣れるための良い習慣は、普段使用している基本的な関数がどのように作られているか内部動作を確認することです。そのための RStudio のショートカットは、関数名を選択してから Ctrl+F2
または fn+F2
またはCmd+F2
(お使いのコンピュータによって異なります)を押します。
44.7 purrr の使用: 繰り返し利用可能な関数の作成
データセット内の複数のカラムのデータ型を変更する
例えば、分析やプロットのために、元の linelist
データに含まれる多くの文字型変数を「因子型」に変換する必要があるとします。この変換ステップを何度も繰り返し実行する代わりに、lapply()
を使えば、1 行のコードですべての文字型変数の変換を行うことができます
注意: lapply()
はリストを返すので、使用の際には変換の最終ステップとして追加の修正が必要になるかもしれません。
同じことは purrr パッケージの map_if()
を使って行うことができます。
linelist_factor2 <- linelist %>%
purrr::map_if(is.character, as.factor)
linelist_factor2 %>%
glimpse()
## List of 30
## $ case_id : Factor w/ 5888 levels "00031d","00086d",..: 2134 3022 396 4203 3084 4347 179 1241 5594 430 ...
## $ generation : num [1:5888] 4 4 2 3 3 3 4 4 4 4 ...
## $ date_infection : Date[1:5888], format: "2014-05-08" NA ...
## $ date_onset : Date[1:5888], format: "2014-05-13" "2014-05-13" ...
## $ date_hospitalisation: Date[1:5888], format: "2014-05-15" "2014-05-14" ...
## $ date_outcome : Date[1:5888], format: NA "2014-05-18" ...
## $ outcome : Factor w/ 2 levels "Death","Recover": NA 2 2 NA 2 2 2 1 2 1 ...
## $ gender : Factor w/ 2 levels "f","m": 2 1 2 1 2 1 1 1 2 1 ...
## $ age : num [1:5888] 2 3 56 18 3 16 16 0 61 27 ...
## $ age_unit : Factor w/ 2 levels "months","years": 2 2 2 2 2 2 2 2 2 2 ...
## $ age_years : num [1:5888] 2 3 56 18 3 16 16 0 61 27 ...
## $ age_cat : Factor w/ 8 levels "0-4","5-9","10-14",..: 1 1 7 4 1 4 4 1 7 5 ...
## $ age_cat5 : Factor w/ 18 levels "0-4","5-9","10-14",..: 1 1 12 4 1 4 4 1 13 6 ...
## $ hospital : Factor w/ 6 levels "Central Hospital",..: 4 3 6 5 2 5 3 3 3 3 ...
## $ lon : num [1:5888] -13.2 -13.2 -13.2 -13.2 -13.2 ...
## $ lat : num [1:5888] 8.47 8.45 8.46 8.48 8.46 ...
## $ infector : Factor w/ 2697 levels "00031d","002e6c",..: 2594 NA NA 2635 180 1799 1407 195 NA NA ...
## $ source : Factor w/ 2 levels "funeral","other": 2 NA NA 2 2 2 2 2 NA NA ...
## $ wt_kg : num [1:5888] 27 25 91 41 36 56 47 0 86 69 ...
## $ ht_cm : num [1:5888] 48 59 238 135 71 116 87 11 226 174 ...
## $ ct_blood : num [1:5888] 22 22 21 23 23 21 21 22 22 22 ...
## $ fever : Factor w/ 2 levels "no","yes": 1 NA NA 1 1 1 NA 1 1 1 ...
## $ chills : Factor w/ 2 levels "no","yes": 1 NA NA 1 1 1 NA 1 1 1 ...
## $ cough : Factor w/ 2 levels "no","yes": 2 NA NA 1 2 2 NA 2 2 2 ...
## $ aches : Factor w/ 2 levels "no","yes": 1 NA NA 1 1 1 NA 1 1 1 ...
## $ vomit : Factor w/ 2 levels "no","yes": 2 NA NA 1 2 2 NA 2 2 1 ...
## $ temp : num [1:5888] 36.8 36.9 36.9 36.8 36.9 37.6 37.3 37 36.4 35.9 ...
## $ time_admission : Factor w/ 1072 levels "00:10","00:29",..: NA 308 746 415 514 589 609 297 409 387 ...
## $ bmi : num [1:5888] 117.2 71.8 16.1 22.5 71.4 ...
## $ days_onset_hosp : num [1:5888] 2 1 2 2 1 1 2 1 1 2 ...
異なる変数で繰り返しグラフを作成する
H7N9 発生時の患者の転帰の分布を、中国各省ごとに見ていくための円グラフを作成します。各省それぞれにコードを繰り返すのではなく、以下に作成する関数を適用するだけです。
#highchart カラーテーマを使用するためのオプションの設定
options(highcharter.theme = highcharter::hc_theme_smpl(tooltip = list(valueDecimals = 2)))
#"chart_outcome_province" という関数を作成する。この関数はデータセットと、結果の分布をプロットする州の名前を引数として取る。
chart_outcome_province <- function(data_used, prov){
tab_prov <- data_used %>%
filter(province == prov,
!is.na(outcome))%>%
group_by(outcome) %>%
count() %>%
adorn_totals(where = "row") %>%
adorn_percentages(denominator = "col", )%>%
mutate(
perc_outcome= round(n*100,2))
tab_prov %>%
filter(outcome != "Total") %>%
highcharter::hchart(
"pie", hcaes(x = outcome, y = perc_outcome),
name = paste0("Distibution of the outcome in:", prov)
)
}
chart_outcome_province(flu_china, "Shanghai")
chart_outcome_province(flu_china,"Zhejiang")
chart_outcome_province(flu_china,"Jiangsu")
異なる変数で繰り返し表を作成する
3 つの指標を作成して表にまとめ、各州ごとに作成します。指標は、発症から入院までの期間、回復の割合、症例の年齢の中央値です。
indic_1 <- flu_china %>%
group_by(province) %>%
mutate(
date_hosp= strptime(date_of_hospitalisation, format = "%m/%d/%Y"),
date_ons= strptime(date_of_onset, format = "%m/%d/%Y"),
delay_onset_hosp= as.numeric(date_hosp - date_ons)/86400,
mean_delay_onset_hosp = round(mean(delay_onset_hosp, na.rm=TRUE ), 0)) %>%
select(province, mean_delay_onset_hosp) %>%
distinct()
indic_2 <- flu_china %>%
filter(!is.na(outcome)) %>%
group_by(province, outcome) %>%
count() %>%
pivot_wider(names_from = outcome, values_from = n) %>%
adorn_totals(where = "col") %>%
mutate(
perc_recovery= round((Recover/Total)*100,2))%>%
select(province, perc_recovery)
indic_3 <- flu_china %>%
group_by(province) %>%
mutate(
median_age_cases = median(as.numeric(age), na.rm = TRUE)
) %>%
select(province, median_age_cases) %>%
distinct()
## Warning in median(as.numeric(age), na.rm = TRUE): NAs introduced by coercion
#3 つの指標データセットの結合
table_indic_all <- indic_1 %>%
dplyr::left_join(indic_2, by = "province") %>%
left_join(indic_3, by = "province")
#指標を flextable で表示する
print_indic_prov <- function(table_used, prov){
#まず、表示しやすいようにデータフレームを少し変換する
indic_prov <- table_used %>%
filter(province==prov) %>%
pivot_longer(names_to = "Indicateurs", cols = 2:4) %>%
mutate( indic_label = factor(Indicateurs,
levels= c("mean_delay_onset_hosp","perc_recovery","median_age_cases"),
labels=c("Mean delay onset-hosp","Percentage of recovery", "Median age of the cases"))
) %>%
ungroup(province) %>%
select(indic_label, value)
tab_print <- flextable(indic_prov) %>%
theme_vanilla() %>%
flextable::fontsize(part = "body", size = 10)
tab_print <- tab_print %>%
autofit() %>%
set_header_labels(
indic_label= "Indicateurs", value= "Estimation") %>%
flextable::bg( bg = "darkblue", part = "header") %>%
flextable::bold(part = "header") %>%
flextable::color(color = "white", part = "header") %>%
add_header_lines(values = paste0("Indicateurs pour la province de: ", prov)) %>%
bold(part = "header")
tab_print <- set_formatter_type(tab_print,
fmt_double = "%.2f",
na_str = "-")
tab_print
}
print_indic_prov(table_indic_all, "Shanghai")
Indicateurs pour la province de: Shanghai | |
---|---|
Indicateurs |
Estimation |
Mean delay onset-hosp |
4.0 |
Percentage of recovery |
46.7 |
Median age of the cases |
67.0 |
print_indic_prov(table_indic_all, "Jiangsu")
Indicateurs pour la province de: Jiangsu | |
---|---|
Indicateurs |
Estimation |
Mean delay onset-hosp |
6.0 |
Percentage of recovery |
71.4 |
Median age of the cases |
55.0 |
44.8 関数をよりよく使うためのヒントとベストプラクティス
関数型プログラミングは、コードを簡単にし、その読み取りを容易にするためのものです。また、逆も成り立ちます。以下のヒントは、きれいなコードと読みやすいコードの作成に役立つでしょう。
命名と構文
環境に存在する他の関数と、容易に重複してしまう可能性のある名前の使用は避けてください
関数名は短く、他の方が理解しやすいようにすることをお勧めします
関数名には動詞を使い、引数名には名詞を使うのが好ましいです。
カラム名と tidy evaluation
コードに引数として与えられた列名を参照する方法を知りたい場合は、tidyverse programming guidance を参照ください。トピックの中には、tidy evaluationと包括演算子 {{ }}
(二重括弧)の利用方法が含まれています。
前述した tidyverse チュートリアルページにある、テンプレートコード例です:
テストとエラー処理
関数のタスクが複雑であればあるほど、エラーが発生する可能性は高くなります。そのため、エラーの原因がどこにあるのかを素早く理解し、エラーの修正方法を見つけるために、関数内に何らかの検証工程を加えることが必要な場合があります。
-
missing(引数)
を用いて引数の欠落を確認することが推奨されます。この簡単な確認は “TRUE” もしくは “FALSE” を返します。
contain_covid19_missing <- function(barrier_gest, wear_mask, get_vaccine){
if (missing(barrier_gest)) (print("please provide arg1"))
if (missing(wear_mask)) print("please provide arg2")
if (missing(get_vaccine)) print("please provide arg3")
if (!barrier_gest == "yes" | wear_mask =="yes" | get_vaccine == "yes" )
return ("you can do better")
else("please make sure all are yes, this pandemic has to end!")
}
contain_covid19_missing(get_vaccine = "yes")
## [1] "please provide arg1"
## [1] "please provide arg2"
## Error in contain_covid19_missing(get_vaccine = "yes"): argument "barrier_gest" is missing, with no default
- より検出しやすいエラーには、
stop()
を使用します。
contain_covid19_stop <- function(barrier_gest, wear_mask, get_vaccine){
if(!is.character(barrier_gest)) (stop("arg1 should be a character, please enter the value with `yes`, `no` or `sometimes"))
if (barrier_gest == "yes" & wear_mask =="yes" & get_vaccine == "yes" )
return ("success")
else("please make sure all are yes, this pandemic has to end!")
}
contain_covid19_stop(barrier_gest=1, wear_mask="yes", get_vaccine = "no")
## Error in contain_covid19_stop(barrier_gest = 1, wear_mask = "yes", get_vaccine = "no"): arg1 should be a character, please enter the value with `yes`, `no` or `sometimes
ほとんどの組み込み関数は実行時に、特定の条件でポップアップするメッセージや警告があります。関数
message()
やwarning()
を使って、これらのメッセージを自作の関数に組み込むことができます。引数として関数を受取り、安全な方法で実行する
safely()
を使うことで、エラーを処理することもできます。実際、この関数は、エラーが発生しても停止することなく実行されます。safely()
は出力として、関数の結果とスキップしたエラーの2つのオブジェクトを持つリストを返します。
下記コードでは、linelise 各行に対し mean()
を実行し、次に safely()
を実行することで結果とエラーを検証できます。
map(linelist, mean)
## $case_id
## [1] NA
##
## $generation
## [1] 16.56165
##
## $date_infection
## [1] NA
##
## $date_onset
## [1] NA
##
## $date_hospitalisation
## [1] "2014-11-03"
##
## $date_outcome
## [1] NA
##
## $outcome
## [1] NA
##
## $gender
## [1] NA
##
## $age
## [1] NA
##
## $age_unit
## [1] NA
##
## $age_years
## [1] NA
##
## $age_cat
## [1] NA
##
## $age_cat5
## [1] NA
##
## $hospital
## [1] NA
##
## $lon
## [1] -13.23381
##
## $lat
## [1] 8.469638
##
## $infector
## [1] NA
##
## $source
## [1] NA
##
## $wt_kg
## [1] 52.64487
##
## $ht_cm
## [1] 124.9633
##
## $ct_blood
## [1] 21.20686
##
## $fever
## [1] NA
##
## $chills
## [1] NA
##
## $cough
## [1] NA
##
## $aches
## [1] NA
##
## $vomit
## [1] NA
##
## $temp
## [1] NA
##
## $time_admission
## [1] NA
##
## $bmi
## [1] 46.89023
##
## $days_onset_hosp
## [1] NA
## $case_id
## $case_id$result
## [1] NA
##
## $case_id$error
## NULL
##
##
## $generation
## $generation$result
## [1] 16.56165
##
## $generation$error
## NULL
##
##
## $date_infection
## $date_infection$result
## [1] NA
##
## $date_infection$error
## NULL
##
##
## $date_onset
## $date_onset$result
## [1] NA
##
## $date_onset$error
## NULL
##
##
## $date_hospitalisation
## $date_hospitalisation$result
## [1] "2014-11-03"
##
## $date_hospitalisation$error
## NULL
##
##
## $date_outcome
## $date_outcome$result
## [1] NA
##
## $date_outcome$error
## NULL
##
##
## $outcome
## $outcome$result
## [1] NA
##
## $outcome$error
## NULL
##
##
## $gender
## $gender$result
## [1] NA
##
## $gender$error
## NULL
##
##
## $age
## $age$result
## [1] NA
##
## $age$error
## NULL
##
##
## $age_unit
## $age_unit$result
## [1] NA
##
## $age_unit$error
## NULL
##
##
## $age_years
## $age_years$result
## [1] NA
##
## $age_years$error
## NULL
##
##
## $age_cat
## $age_cat$result
## [1] NA
##
## $age_cat$error
## NULL
##
##
## $age_cat5
## $age_cat5$result
## [1] NA
##
## $age_cat5$error
## NULL
##
##
## $hospital
## $hospital$result
## [1] NA
##
## $hospital$error
## NULL
##
##
## $lon
## $lon$result
## [1] -13.23381
##
## $lon$error
## NULL
##
##
## $lat
## $lat$result
## [1] 8.469638
##
## $lat$error
## NULL
##
##
## $infector
## $infector$result
## [1] NA
##
## $infector$error
## NULL
##
##
## $source
## $source$result
## [1] NA
##
## $source$error
## NULL
##
##
## $wt_kg
## $wt_kg$result
## [1] 52.64487
##
## $wt_kg$error
## NULL
##
##
## $ht_cm
## $ht_cm$result
## [1] 124.9633
##
## $ht_cm$error
## NULL
##
##
## $ct_blood
## $ct_blood$result
## [1] 21.20686
##
## $ct_blood$error
## NULL
##
##
## $fever
## $fever$result
## [1] NA
##
## $fever$error
## NULL
##
##
## $chills
## $chills$result
## [1] NA
##
## $chills$error
## NULL
##
##
## $cough
## $cough$result
## [1] NA
##
## $cough$error
## NULL
##
##
## $aches
## $aches$result
## [1] NA
##
## $aches$error
## NULL
##
##
## $vomit
## $vomit$result
## [1] NA
##
## $vomit$error
## NULL
##
##
## $temp
## $temp$result
## [1] NA
##
## $temp$error
## NULL
##
##
## $time_admission
## $time_admission$result
## [1] NA
##
## $time_admission$error
## NULL
##
##
## $bmi
## $bmi$result
## [1] 46.89023
##
## $bmi$error
## NULL
##
##
## $days_onset_hosp
## $days_onset_hosp$result
## [1] NA
##
## $days_onset_hosp$error
## NULL
以前述べたように、コードにコメントをつけることは、作業内容を明示するための良い方法です。