バックグラウンド
dplyr パイプラインの一部である別の関数内から呼び出される、計算コストの高い (およびSLOW ) 関数があります。
dat %>%
mutate_at(.vars = vars(dplyr::intersect(starts_with("locale"), ends_with("last_name"))),
.funs = funs(native_last_name_alpha(., Type))) %>%
{.} -> dat
Type
この関数は、変数(文字列) が「男性」または「女性」のどちらに一致するかによって、2 つのいずれかを実行します。一致する場合はnative_last_name_alpha
、計算コストが高く遅い関数が実行され、他の処理が実行されます。一致しない場合は、native_last_name_alpha
を返しNA
ます。現在、これはベクトル化されているため、何が起こるべきかを判断するためにif_else
andを使用しcase_when
ています。たとえば、次のようになります。
native_last_name_alpha <- function(locale, type) {
case_when(
type == "male" ~ stringi::stri_trans_toupper(
fake_single_alpha(locale = locale,
request = "last_name_male",
provider = "faker.providers.person")
),
type == "female" ~ stringi::stri_trans_toupper(
fake_single_alpha(locale = locale,
request = "last_name_female",
provider = "faker.providers.person")
),
TRUE ~ NA_character_
)
}
TRUE
問題は、条件がまたはに評価されるかどうかに関係なく、高価な関数が実行されるFALSE
ことです。これにより、スクリプトの実行が非常に遅くなります。
if_else、ifelse、および case_when を深く掘り下げる
ベクトル化された if/else ステートメントif_else
とifelse
(and case_when
) は、従来の if...else ステートメントのようには機能しないことを理解しています。ステートメントのすべての部分が評価され、次に条件を使用して、返される結果がつなぎ合わされます。たとえば、このコードは次の出力と警告を生成します。
v <- c(-100, -10, 10, 100)
ifelse(v > 0, log10(v), log10(-v))
[1] 2 1 1 2
警告メッセージ:
1: ifelse(v > 0, log10(v), log10(-v)) : 生成された NaN
2: ifelse(v > 0, log10(v), log10(-v)) の場合: NaN が生成される
条件が true の場合の戻り値と条件が false の場合の戻り値の両方が評価され、条件を使用して結果のベクトルが結合されます。
その結果、高価で遅い関数が実際に必要な回数よりも多く実行されています。
どうすればこれを回避できますか?
私が欲しいもの
私は、条件が true の場合に true の場合のみ結果を評価するif_else
andの代替のベクトル化された実装を探しています。case_when
これまでに試したこと
if_else
/の独自のベクトル化された実装を作成しようとしましifelse
たが、成功しませんでした。非標準評価も試しましたが、これを機能させるのに十分な知識がありません。if_else
評価されていない式を返すことができ、後で適切なタイミングで評価することができれば(フリーズドライ関数呼び出しのようなもの)、これが解決策の一部になる可能性があると推測しています。しかし、今のところ喜びはありません。
やりたいことを簡単にするために見逃したことはありますか?または、誰かが実装に関するヒントを提供できますか? ありがとう!