niszetの日記

アナログCMOS系雑用エンジニアが頑張る備忘録系日記

(R) R-wakalangで質問してみた。あるいはパッケージ内の関数の一覧を得る方法について

初の投稿...ども...

来週のTokyoRにてyutannihilationさんがwakalangについて発表すると聞き、そういえば僕はちゃんとここで質問したことがなかったなぁ…と思って、気になっていたことを質問してみました1

様子

こんな感じです。

f:id:niszet:20180223215752p:plain

めちゃくちゃリプライが早い…!(わずか3分…。)

国内のトップRユーザの方々からこんなに簡単にコメントいただけるなんて…すごい場所ですね…。

ワタシも結構しり込みしていたのでわかるのですが、習うより慣れよですね。とはいえ、どういう感じに質問すればよいの…?みたいなものはありますよね…

わからないことを呟いてみよう。

そんなわけで、yutannihilationさんがRワカラングのわからないことを募集?中です。ask.fm(下記の記事をさかのぼるとリンクがあるはず)や、タグをつけて呟いてみましょう!

私は、

  • 寿司をつける方法がわからなかった
  • コードを添付するには??
  • 文中のコードハイライトは…?

みたいなことが良く分かりませんでしたね…。それぞれ、なんかslackポチポチ触ってたらそれらしきものが見つかったりしたので少しだけわかりましたが…。

質問の答えについて

hoxo_mさんに教えていただいたのはこのやり方。

ls(envir = asNamespace("package_name"))

この場合はそのパッケージ内に含まれる、エクスポートされていない関数も含めて一覧が得られます。なお、パッケージ名を囲う""は必須です(文字列で渡す)。

# 実行例
> head(ls(envir = asNamespace("fs")))
[1] "!.fs_perms" "%||%"       "&.fs_perms" "[.fs_bytes" "[.fs_path" 
[6] "[.fs_perms"

それとは別経路で(というかtwitterで)kazutanさんに教えていただいたのはこのやり方。

library(fs)
ls("package:fs")
# 以下は実行結果
 [1] "as_fs_bytes"      "as_fs_path"       "as_fs_perms"      "dir_copy"        
 [5] "dir_create"       "dir_delete"       "dir_exists"       "dir_info"        
 [9] "dir_ls"           "dir_map"          "dir_walk"         "file_access"     
[13] "file_chmod"       "file_chown"       "file_copy"        "file_create"     
[17] "file_delete"      "file_exists"      "file_info"        "file_move"       
[21] "file_show"        "file_temp"        "file_temp_pop"    "file_temp_push"  
[25] "fs_bytes"         "fs_path"          "fs_perms"         "group_ids"       
[29] "is_absolute_path" "is_dir"           "is_file"          "is_link"         
[33] "link_copy"        "link_create"      "link_delete"      "link_exists"     
[37] "link_path"        "path"             "path_abs"         "path_common"     
[41] "path_dir"         "path_expand"      "path_ext"         "path_ext_remove" 
[45] "path_ext_set"     "path_ext<-"       "path_file"        "path_filter"     
[49] "path_home"        "path_join"        "path_norm"        "path_real"       
[53] "path_rel"         "path_sanitize"    "path_split"       "path_temp"       
[57] "path_tidy"        "user_ids"        

この場合はエクスポートされている関数のみが得られます。用途に応じて使い分けましょう。どちらも文字列のベクトルとして得ることが出来ます。

conflictsはコード追っかけ中…。これも何かわかったらまとめておこう… github.com

ということで、わからないことはRワカラングで質問してみようというお話でした!

Enjoy!!


  1. あらためて見直してみると私の考えていた方法の回りくどさよ…。ls()はbaseの関数なので、これも若者(じゃなくておじさんだけど)のbase離れってやつなのか…。

(R) skimrの表示をカスタマイズしたい 2回目

histをもっと幅広く表示させたい気持ちが起点。

さて前回、skimrパッケージのskim_with()関数にてskim()関数の表示のさせ方を変えてみました。

niszet.hatenablog.com

しかし、skim()のhistは他の関数と違って少し独特なのでこれをもう少し使いこなしたい気持ちになります。

ひとまずヒストグラムだけを表示させてみます。これはinline_hist()で出来ます。引数にはdata.frameは渡せず、vectorを与える必要があります。

> skimr::inline_hist(iris$Sepal.Length)
▂▇▅▇▆▅▂▂

なお、この関数は先に表示したskimmersの中にある関数と同じ、つまりskim()で表示するときに使用される関数と等しいわけですね。

# 以下で確認。
identical(skimr::get_skimmers()[["numeric"]][["hist"]], skimr::inline_hist)
#> [1] TRUE

さて、中身を見てみます。

View(inline_hist)

# 以下はView()での表示の結果を張り付けたもの
function (x) 
{
  if (length(x) < 1 || all(is.na(x))) 
    return(structure(" ", class = c("spark", "character")))
  if (all(x == 0)) 
    x <- x + 1
  hist_dt <- table(cut(x, options$formats$character$width))
  hist_dt <- hist_dt/max(hist_dt)
  structure(spark_bar(hist_dt), class = c("spark", "character"))
}

ここで、下から3行目で幅を制御しているらしいことが読み取れますが、skimr:::options内の環境の値を引き抜いているため、この部分を変えることが出来ません1。 そこで、この関数をコピーして編集、引数で表示幅を変えることが出来るようにしたものを作ってみます。

こんな感じ。

my_hist <- skimr::inline_hist
my_hist <- edit(my_hist)

edit()で対象の関数をエディタで書き換えることが出来ます。修正内容は改めて代入しないといけません(2行目) edit()で修正したあとのmy_hist() の中身はこんな感じです。引数にwidを加え、デフォルト値として8を与えておきます。これはskimrのデフォルトの値でした。

function (x, wid=8) 
{
  if (length(x) < 1 || all(is.na(x))) 
    return(structure(" ", class = c("spark", "character")))
  if (all(x == 0)) 
    x <- x + 1
  hist_dt <- table(cut(x, wid))
  hist_dt <- hist_dt/max(hist_dt)
  structure(skimr:::spark_bar(hist_dt), class = c("spark", "character"))
}

関数内部については差異を見てもらえればわかると思いますが、options$formats$character$widthを関数の引数widに置き換えただけです。

もともと、histはskimr::inline_hist()関数と同じものが使われていて、その実行結果はコンソール上にそのまま出力されるました。つまりここで作成した関数単体で使用すれば同じようにコンソール上に表示されるわけですね。やってみます。

> my_hist(iris$Sepal.Length, 20)
▂▂▃▇▆▁▆▇▅▆▂▇▃▆▂▁▂▁▂▁

こんな感じ。うーむ、irisだといまいち便利なのかどうなのか良く分かりませんな…。ひょっとしたら役に立つ場面があるのではと思いますが。 この自作histをskim()の仲間に加える、skim_with()の使い方については前回の記事を参照してください。

おわりに

ということで、skimrパッケージで表示をカスタマイズするというお話でした。

なお、skimは任意の型に対して関数を定義すれば表示をカスタマイズできますし、skim自体も総称関数です。
もう一歩踏み込んだ内容としては、vignette

vignette("Supporting_additional_objects")

で見れます。まぁ、今回の話に限らずですがvignette充実しているのでそちらを読めば大体わかってしまうような。。。

skim()は現時点で実装されているものはskimr:::skim.data.frame()skimr:::skim.default()skimr:::skim.grouped_df()だけのようですね。そのため、listを与えるとうまく表示してくれません。必要であれば自分で定義するとかですかね。うーむ、あまり必要はない?

ということで、skimrパッケージのinline_hist()のような関数を自分でカスタマイズして使ってみるお話でした。

Enjoy!!


  1. 多分…。パッケージ内のName spaceにある環境オブジェクトの値って変更出来ますかね…?多分出来ないはず…。

(R) skimrの表示をカスタマイズしたい 1回目

そのまま使っても便利ですが、カスタマイズすることで自分好みに設定できます

skimrって何?という方はまずは下記の記事をご覧ください。

niszet.hatenablog.com

なお、現時点のCRAN版skimrは1.0.1で、ここに書く内容はvignette: Using_skimrgithub上のREADME.mdに書かれていることがほとんどです。そちらを読んだ方が早いかもしれませんね。

vignette("Using_skimr")

本題

さて、強化版summary()であるskimrパッケージの関数skim()には、同パッケージのskim_with()関数によって、data.frameの各列の型に対応して表示のさせ方を変えることが出来ます。

そもそもあの関数は一体何をどう計算し表示しているのだろうか…?ということから始めて、上記のvignetteを追いかけながら自分好みにカスタマイズする方法を調べていきます。

まずはデフォルトの設定での表示について把握する

まずはデフォルトの表示について改めて確認してみます。とりあえずお手頃irisさんで、どうぞ1

> skimr::skim(iris)
Skim summary statistics
 n obs: 150 
 n variables: 5 

Variable type: factor 
 variable missing complete   n n_unique                       top_counts ordered
  Species       0      150 150        3 set: 50, ver: 50, vir: 50, NA: 0   FALSE

Variable type: numeric 
     variable missing complete   n mean   sd  p0 p25 median p75 p100     hist
 Petal.Length       0      150 150 3.76 1.77 1   1.6   4.35 5.1  6.9 ▇▁▁▂▅▅▃▁
  Petal.Width       0      150 150 1.2  0.76 0.1 0.3   1.3  1.8  2.5 ▇▁▁▅▃▃▂▂
 Sepal.Length       0      150 150 5.84 0.83 4.3 5.1   5.8  6.4  7.9 ▂▇▅▇▆▅▂▂
  Sepal.Width       0      150 150 3.06 0.44 2   2.8   3    3.3  4.4 ▁▂▅▇▃▂▁▁

最初にirisのデータフレームが150行5列のデータであることを表示した後に、factorとnumericそれぞれについて表示していますね。そして、それぞれのデータ型によって表示させる内容が異なることがわかります。

さてこの表示させる内容がどう設定されているのかを調べるには、skimr::get_skimmers()でデータ型毎に一覧を得ることが出来ます。
しかし、これをそのまま実行するとlistのlistが返ってきてコンソール上にだらっと表示されてしまい、非常に見づらいのでView()の出番です2。 というわけで、ほいっと。

View(skimr::get_skimmers())

で、こうです。

f:id:niszet:20180217104723p:plain

ここではnumericの項目を一つ掘って展開・表示していますが、このlistの要素の並びのmissing, complete, n ... と先のskim()の結果の表示の各列に対応していることがわかります。これらの関数が適用されてskimr::skim()にて表示されるのですね。さらにこの各関数についても見れますが、ちょっと話が発散してしまうので詳細は割愛。深堀するならR言語徹底解説かなぁ。functionの構成がわかると理解が深まると思いますが、とりあえずこのお話の中ではあまり関係ないので…。

さて他の型、例えばfactorについても同様の構成となっていて各型に対してどの関数たちを使用して処理・表示するかを定義している形になっています。

このskimr::get_skimmers()での表示は現在設定されている関数群を表示するので、このあとで使用するskim_with()関数で内容を更新した後も、現在のskim()で表示される内容(関数)が見れます。

実際にskim_with()を使用してみる。

前置きが長くなってしまいましたが、実際にskim_with()を使用してskim()の表示のさせ方が変わるところを見てみます。 vignetteの例の通りですが、skim()で表示させたい項目をlistでまとめる形で作ります。ここで、=の左はskim()で表示させたときの列名になります。右側が関数の名前(呼び出しではない)という形になりますね。purrr::partialは第一引数の関数の引数の一部に値を指定しているのですね。

funs <- list(iqr = IQR,
quantile = purrr::partial(quantile, probs = .99))

partialで躓いたときはこちらのid:yutannnihilationさんの記事が参考になるかなと思います。 notchained.hatenablog.com

さて、先の変数funsをskim_with()に与えます。これはnumeric型に対して適用したいので、下記のように。第二引数のappend = TRUEは元の関数たちを残すかどうかです。残す場合はこのように

skim_with(numeric = funs, append = TRUE)

このとき、関数群は

View(skimr::get_skimmers())

で見てみると、末尾に2つ追加されていることがわかります。

f:id:niszet:20180217220215p:plain

そして、skim()の表示結果はこのようになりますね

> skimr::skim(iris)
Skim summary statistics
 n obs: 150 
 n variables: 5 

Variable type: factor 
 variable missing complete   n n_unique                       top_counts ordered
  Species       0      150 150        3 set: 50, ver: 50, vir: 50, NA: 0   FALSE

Variable type: numeric 
     variable missing complete   n mean   sd  p0 p25 median p75 p100     hist iqr quantile
 Petal.Length       0      150 150 3.76 1.77 1   1.6   4.35 5.1  6.9 ▇▁▁▂▅▅▃▁ 3.5     6.7 
  Petal.Width       0      150 150 1.2  0.76 0.1 0.3   1.3  1.8  2.5 ▇▁▁▅▃▃▂▂ 1.5     2.5 
 Sepal.Length       0      150 150 5.84 0.83 4.3 5.1   5.8  6.4  7.9 ▂▇▅▇▆▅▂▂ 1.3     7.7 
  Sepal.Width       0      150 150 3.06 0.44 2   2.8   3    3.3  4.4 ▁▂▅▇▃▂▁▁ 0.5     4.15

次。第二引数をFALSEにした場合は、

skim_with(numeric = funs, append = FALSE)

として、関数たちを見てみると、

View(skimr::get_skimmers())

f:id:niszet:20180217220241p:plain

となりました。

skim()の実行結果は、

> skimr::skim(iris)
Skim summary statistics
 n obs: 150 
 n variables: 5 

Variable type: factor 
 variable missing complete   n n_unique                       top_counts ordered
  Species       0      150 150        3 set: 50, ver: 50, vir: 50, NA: 0   FALSE

Variable type: numeric 
     variable iqr quantile
 Petal.Length 3.5     6.7 
  Petal.Width 1.5     2.5 
 Sepal.Length 1.3     7.7 
  Sepal.Width 0.5     4.15

で、自分で追加した部分だけが表示されました。

元に戻すときは?

skim_with_defaults() を使用すると、元の(デフォルトの)設定に戻ります。困ったらこのコマンドを実行しましょう。

順序を入れ替えるときは?

表示順序を入れ替えたい時などはエクスポートされていない要素ですがskimr:::.defaultを使って関数を持ってくるのがいいのかな…あまり良い方法ではないのですが、エクスポートされている関数でデフォルトで設定されている関数を取り出してくる方法が見つからなかったので…。

p0の項目だけを持ってくるだけならば例えばこんな感じです。

skim_with(numeric=list(p0=skimr:::.default[["numeric"]][["p0"]]), append=FALSE)

1項目でもlist()で囲うこと、列に表示する名前=関数名の形で書くこと、が注意点ですね。なお、[["numeric"]]とかはView(skimr:::.default)で表示させた状態で使いたい関数の右の方でマウスカーソルを置いて[ ⇐] `のようなアイコンをクリックしてコンソールに持って来ましょう。これも以前書いたViewの記事で紹介したとおりです。

> skimr::skim(iris)
Skim summary statistics
 n obs: 150 
 n variables: 5 

Variable type: factor 
 variable missing complete   n n_unique                       top_counts ordered
  Species       0      150 150        3 set: 50, ver: 50, vir: 50, NA: 0   FALSE

Variable type: numeric 
     variable  p0
 Petal.Length 1  
  Petal.Width 0.1
 Sepal.Length 4.3
  Sepal.Width 2  

ということで、skimrパッケージのskim関数の表示のさせ方を色々といじってみました。
長くなってしまったのでViewの時と同じように複数回に分けて書こうと思います。続きます。

Enjoy!!


  1. 最近は出来るだけreprexの書式にしようとしていますが、strみたいにコンソールに出力するタイプはその出力のままの方がわかりやすいという観点で書き方を変えています(コマンドの入力行に > がつく、要するにコンソールからコピペそのまま)

  2. RStudio IDE上での使用を想定しています。詳しくはこのシリーズを参考にしてください。(R) View関数に関して(1回目) - niszetの日記

(R) アラン分散を求めるには(メモ)

allanvarパッケージを使ってみる

今回はヘルプにある実行例をそのまま実行しただけですが…

高精度な発振器のジッタ計測などに使われる(らしい)アラン分散ですが、どうもあまり資料がなく。まぁ信号処理とか測定の方はRではあまり情報がないからなぁ… ジャイロ等で使用することが多いそうですが、ジャイロ良く知らないな…

アラン分散で検索すると、たとえばこちら

https://img.atwikiimg.com/www13.atwiki.jp/usonx/attach/40/79/%E3%82%A2%E3%83%A9%E3%83%B3%E5%88%86%E6%95%A3%E3%81%AB%E3%82%88%E3%82%8B%E8%A9%95%E4%BE%A1.pdf

やこちら

Allan variance(アラン分散) | 株式会社デプロ

などの資料が見つかりますね。

Rのパッケージにないのかなと探してみたところ、allanvarパッケージなるものがありました。

CRAN - Package allanvar

あまり更新されてないようですが、まぁシンプルなパッケージだし、あまり更新することもないかもしれない。もう一つ、gmwmパッケージというのもあるようですが、今回はallanvarパッケージの方を使ってみます。

gyrozデータセット

allanvarパッケージに含まれているデータですが、ヘルプで説明を読んでみるとこれは実測データではなく、Rで作成したダミーデータとのことです。
とりあえず見てみるです。

data(gyroz)
plot(gyroz)

…で、plotして見てみるとこんな感じです。

f:id:niszet:20180217170716p:plain

ノイズが大きく、トレンドらしきものが見えるような…見えないような…という感じのデータですね。

とりあえず実行してみよう。

library(allanvar)

# コピペ…
#Load data 
data(gyroz)

#Allan variance computation using avar
avgyroz <- avar(gyroz@.Data, frequency(gyroz))
plotav(avgyroz)
abline(1.0+log(avgyroz$time[1]), -1/2, col="green", lwd=4, lty=10)
abline(1.0+log(avgyroz$time[1]), 1/2, col="green", lwd=4, lty=10)
legend(0.11, 1e-03, c("Random Walk"))
legend(25, 1e-03, c("Rate Random Walk"))

で、結果は

f:id:niszet:20180217184148p:plain

のようになります。なんか字が見切れていますが…。縦軸も工夫して桁が見えるようにしないといけない気がする…。

一応、それっぽくは表示されていますが、もうちょっと工夫が必要だな~…。
表示された値それぞれにエラーバーがついていて、やはりτが大きい方が誤差が大きいようですね。1。 んー、これは自分で計測するかダミーデータ作って使ってみないといけませんな…

allanvarについての日本語の資料が全然ないのでとりあえずメモから残していきます。

Enjoy!?


  1. 測定期間が一定なら周期の短い方が多く観測できるので誤差は減っていくだろうという浅い理解です。が、多分そうなんだと思う。元になった論文とか読まないとかな…。

(R) ビニエット読む…が、どこにあるの…?

Rの難しさのその2、パッケージの使い方…

最近はパッケージ更新の度にちゃんとNEWSを読んだり、githubであればREADME.md読んだり。関数ならhelpを見たりはするんですが、vignetteって探しにくいなぁ…と思っていたらid:u_riboさんの記事が

qiita.com

browseVignettes()なる関数があるのですね。パッケージ名を指定すればそのパッケージのvignetteだけ、パッケージ名を指定しなければインストールしてるパッケージ全部出してくれるようだな。

browseVignettes("skimr")
vignette("Supporting_additional_objects")

後者の関数は知っていたものの、「vignette名絶対わからんじゃん…。知ってるならそれ多分読んだことあるじゃん…」って思っていたのでこの関数はパッケージ名だけわかればよいので非常に便利ですね。使っていきます。

そして上記記事のリンク先の、R_Linuxさんの記事、 qiita.com

packageDescription()関数を使うとパッケージの情報がlist形式で得られますね。なので、その要素を取ってくる。たとえばこんな使い方

browseURL(packageDescription("skimr")$URL)

…で、URLにgithubのアドレスが書かれていれば、この関数を使用すればskimrのREADME.mdが読めるので個人的には便利かも。(URLにgithubのパスが書かれていればだけど)

どちらもブラウザ開いてしまうものの、RStudioのコンソール上で作業できるのが楽…。色々知らないことが多いですね。

他にこんなものもあるよ!というのがあれば是非是非教えてくださいませ…

Enjoy!!

rstudio::conf2018の資料を読むと楽しい。RStudio v1.1の新機能の話。

緩いネタから。

先日の、rstudio::confの資料を半分くらいは読んだので(読んだだけ)しばらくは簡単に資料の紹介とかしていくと良いのかな~と思いまして。
資料やYoutubeの動画は下記の資料のリンク先(simecek/RStudioConf2018Slides)に行くとあります。Live Streamのリンク先がYoutube動画(全体)。個別のも関連動画で出てくるので探せるはずです。

niszet.hatenablog.com

そして、上記rstudio::confの発表の中に、RStudio v1.1の新機能についての資料がありました。

資料はこちらですね。
RStudio v1.1 – What’s New

今回はこの内容についてメモを残しておきます。といっても、実はあまり書くことがなかった…ということなのですが。

日本側で既にまとめられている資料

日本語の資料としてはkazutanさんの下記の資料にて、RStudio v1.1についての内容はほぼ触れられています(ただしv1.1が出た直後の状態です。今日時点の最新は1.1.423ですね)

kazutan.github.io

そして、個別の内容についても日本勢の記事がいくつかありましたので、参照できるように貼ってみます。

Terminalについては下記のAtsushi776さんの記事がありました。今目の前にあるRStudioがまさにTerminalが出ないマシン(Win機)だったのですが、別症状っぽいです。

qiita.com

Object Explorer については、

niszet.hatenablog.com

とか、関連してこれ

niszet.hatenablog.com

で書きました。

また、Data Connection機能についてはid:yutannihilationさんのこちらのスライドにまとまっていますね。

speakerdeck.com

Gitについてはid:u_riboさんのこちらの資料が2017年対応版(ブランチの記述もある!)です。これだけでRStudio + Git は怖くない感じです。

qiita.com

…ということで、主要な更新点についてはすでにほぼ網羅されているのでした。

残りの部分。

そんなわけで、rsrudioconfの方の資料には書かれているが、ここでは上記の資料に記載されていない内容について触れてみます。 odbcはちょっと私の手に負えないのでパス…

Terminal

Ctrl + Alt + Enter と Ctrl + Enter のショートカットキーが紹介されていますが、うまく使いこなせず…。これってコマンドを実行した上でConsole->Terminalへ移動(あるいはその逆)って動作な気がしていて、説明とちょっと違う気がする...(私の勘違い?

Misc

まぁ小ネタくらいしかなかったんですが、

  • Color in the Console crayonの力ですね(p.18)

  • Addins List なんか検索できるようになったらしい。知らなかった。(p.20)

  • Searchable Command History これ知らなかった(知ってました?)のですが、Ctrl + Rでコマンドヒストリが出ます。入力した文字でサーチしてくれるようですねこれは結構便利機能。(p.21)

  • Project Templates これも表示が増えたのは知っていましたが、v1.1から増えていたんですね。

ということで思ったほど書くことがありませんでした。というより、新しい情報が日本語で読めるって素晴らしいな、と。感謝しかない。 なんか凄い人に交じって自分の資料のリンクをしれっと入れておくスタイルになってもうた…(゚ε゚)キニシナイ!!

Enjoy!!

(R) View関数に関して(4回目)(追記あり)

前回で完結すると言ったな、あれは嘘だ。

此迄ノ荒筋

こんなに長く続けるつもりはなかったんだ…本当なんだ…

niszet.hatenablog.com

niszet.hatenablog.com

niszet.hatenablog.com

niszet.hatenablog.com

何が残ってる

View は関数をその名前を与えた状態で呼び出せば、その中身を見ることが出来ます。

# こんな感じで
View(stringr::str_replace)

こんな表示になる。 f:id:niszet:20180212204407p:plain

タブが👓のアイコンになりますね。右側を見ると(Read_only)となっていてホッとします(そう?)

そんなわけ(=編集不可能)で、この表示されたものに適宜改行を入れる等は出来ません。改変したいならedit()ですかね1。 Read_onlyの表示の反対側(左側)、`Function: str_replace (namespace: stringr) と表示されるので何を見ているのかがわかってよいですね。

あとは.Rのファイルと同様です。read modeで開いている以外は。

この関数自体のヘルプに行ければ良いのですが、関数の実態部分なので自身を呼び出す構造になっていない限りは残念ながら見れません。素直にコンソール側から?つけて呼び出しましょう。

今度こそ本当におわり。

Enjoy!!

追記

u_riboさんから追加情報でコメントいただきました。F1とF2キーでカーソル位置にある関数のヘルプと関数定義へのジャンプが出来るのですね。RStudio IDE上では魔法の杖のアイコンから行けるようです(そこにショートカットキー名が書かれていますね)

ツイートのリンク先の記事も是非~! uribo.hatenablog.com

(昔読んでいたのにすっかり忘れていたーッ!早速使ってみよう💪)


  1. 他に良いやり方ありますか?