uribo / zipangu

Japanese utility functions and data
https://uribo.github.io/zipangu
Other
56 stars 7 forks source link

Refactor convert_jyear and convert_jdate #49

Closed paithiov909 closed 2 years ago

paithiov909 commented 2 years ago

こんにちは

調べ物をしていて発見したのですが、現在のzipanguの独自実装からstringi::stri_datetime_parseを使うように変えるとすごく速くなりそうです。また、「元年」や漢数字表記も、最近のICUだととくに変換しなくてもパースできるようです。

手もとで試してみているかぎりだと、現在の関数から置き換えてしまっても「文久3年」のテスト以外は通るかと思います(ICUだと明治より前の元号も変換できてしまうため。どうやら奈良時代以後の元号に対応しているらしい)。

この感じでも意図しない結果に変わってしまう値がなさそうなら、書き換えてしまうのもよさそうかなと思います。どうでしょうか?

require(magrittr)
#> Loading required package: magrittr

convert_jyear <- function(jyear) {

    jyear <- stringi::stri_trim(jyear) %>%
        stringi::stri_trans_nfkc()

    ifelse(
        stringi::stri_detect_regex(jyear, "[:number:]{3,}"), ## 和暦の年月日は実際上は3桁以上にならないと思われるため
        { ## 西暦と思われる場合
            stringi::stri_datetime_parse(
                jyear,
                format = "yy\u5e74"
            ) %>%
                lubridate::year()
        },
        { ## 和暦と思われる場合
            jyear <-
                stringi::stri_trans_tolower(jyear) %>%
                stringi::stri_replace_all_regex(
                    jyear_sets$pat_roman,
                    jyear_sets$rep_roman,
                    vectorise_all = FALSE
                ) %>%
                stringi::stri_replace_all_regex(
                    jyear_sets$pat,
                    jyear_sets$rep,
                    vectorise_all = FALSE
                )

            stringi::stri_datetime_parse(
                jyear,
                format = "Gy\u5e74",
                locale = "ja-JP-u-ca-japanese"
            ) %>%
                lubridate::year()
        }
    )
}

convert_jdate <- function(date) {

    jdate <- stringi::stri_trim(date) %>%
        stringi::stri_trans_nfkc()

    jdate <-
        stringi::stri_trim(jdate) %>%
        stringi::stri_trans_tolower() %>%
        stringi::stri_replace_all_regex(
            jyear_sets$pat_roman,
            jyear_sets$rep_roman,
            vectorise_all = FALSE
        ) %>%
        stringi::stri_replace_all_regex(
            jyear_sets$pat,
            jyear_sets$rep,
            vectorise_all = FALSE
        )

    ## 「Gy年M月d日」表記に揃える。現在は年月日ぜんぶないとエラーになるが、これだとエラーにはならない
    sp <- stringi::stri_split_regex(
        jdate,
        "(\u5e74|\u6708|\u65e5)|(\\.)|(\\-)|(\\/)",
    ) %>%
        purrr::map_chr(~ paste0(.[1], "\u5e74", .[2], "\u6708", .[3], "\u65e5"))

    stringi::stri_datetime_parse(
        sp,
        format = "Gy\u5e74M\u6708d\u65e5",
        locale = "ja-JP-u-ca-japanese"
    ) %>%
        lubridate::as_date()
}

jyear_sets <-
    list(
        pat_roman = c("meiji", "taisyo|taisho|taisyou", "syouwa|showa", "heisei", "rewiwa"),
        rep_roman = c("m", "t", "s", "h", "r"),
        pat = c("m|\u660e(?!\u6cbb)", "t|\u5927(?!\u6b63)", "s|\u662d(?!\u548c)", "h|\u5e73(?!\u6210)", "r|\u4ee4(?!\u548c)"),
        rep = c("\u660e\u6cbb", "\u5927\u6b63", "\u662d\u548c", "\u5e73\u6210", "\u4ee4\u548c")
    )

### テスト ###

years <- sample(c("令和2年", "平成5年", "明治元年", "1967年", NA), 100, replace = T)
dates <- sample(c("令和元年5月21日", "昭和26年8月31日", "平成4年2月16日", NA), 100, replace = T)

microbenchmark::microbenchmark(
    zipangu::convert_jyear(years),
    convert_jyear(years),
    times = 50L,
    check = "equivalent"
)
#> Unit: milliseconds
#>                           expr     min      lq      mean  median      uq
#>  zipangu::convert_jyear(years) 58.1918 60.5191 68.157338 66.6875 73.3156
#>           convert_jyear(years)  5.8456  6.1167  7.096138  6.4809  7.1068
#>      max neval
#>  88.9227    50
#>  19.7221    50

microbenchmark::microbenchmark(
    zipangu::convert_jdate(dates),
    convert_jdate(dates),
    times = 50L,
    check = "equivalent"
)
#> Unit: milliseconds
#>                           expr      min       lq      mean   median       uq
#>  zipangu::convert_jdate(dates) 261.9986 279.6587 362.52175 314.4953 420.7269
#>           convert_jdate(dates)   8.3647   8.8897  12.57395   9.8263  14.6133
#>       max neval
#>  816.9172    50
#>   45.1825    50

Created on 2022-05-17 by the reprex package (v2.0.1)

uribo commented 2 years ago

@paithiov909 ありがとうございます。stringi::stri_datetime_parse()の利用、勉強になります。 高速化についても有難いです。お手数でなければPRをいただけますでしょうか。

paithiov909 commented 2 years ago

わかりました。あとでPRを出してみます