info
More than 3 years have passed since last update.
- R
- dplyr
- across
- tidyverse
Last updated at Posted at 2020-06-17
前回に引き続き、dplyrの新機能を紹介していきます。
本記事では、列の操作についてまとめたいと思います。
前回の記事はこちら
dplyr Version 1.0.0 新機能 1: https://qiita.com/shunido113/items/fd312700f2ede2235b71
※本記事では、dplyr Version 1.0.0を新バージョン、dplyr Version 1.0.0より前のdplyrを旧バージョンとしています。
本家の公式サイトです。
英語ができるならこちらのほうがいいかもです笑
まずは、tidyverseを以下のコードでインストールしましょう。
※tidyverseは、データ処理を簡単にしてくれるパッケージ群の総称でその中の一つがdplyrです。
install.packages("tidyverse")library(tidyverse)
本記事で使用するデータは、前回に引き続き、diamondsです。
diamonds# A tibble: 53,940 x 10 carat cut color clarity depth table price x y z <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl> 1 0.23 Ideal E SI2 61.5 55 326 3.95 3.98 2.43 2 0.21 Premium E SI1 59.8 61 326 3.89 3.84 2.31 3 0.23 Good E VS1 56.9 65 327 4.05 4.07 2.31 4 0.290 Premium I VS2 62.4 58 334 4.2 4.23 2.63 5 0.31 Good J SI2 63.3 58 335 4.34 4.35 2.75 6 0.24 Very Good J VVS2 62.8 57 336 3.94 3.96 2.48 7 0.24 Very Good I VVS1 62.3 57 336 3.95 3.98 2.47 8 0.26 Very Good H SI1 61.9 55 337 4.07 4.11 2.53 9 0.22 Fair E VS2 65.1 61 337 3.87 3.78 2.4910 0.23 Very Good H VS1 59.4 61 338 4 4.05 2.39# ... with 53,930 more rows
acrossは、新バージョンの新しい関数です!
これは、列に対して、同じ処理を実施するときに便利です。
まずは、よく使用するsummarizeに対してacrossを使用した場合をどうぞ!。
summarize
旧バージョンでは、違う列に同じ処理を実施する際、いちいち列ごとに処理を記載する必要がありました。
旧バージョン
# depth, table, priceの平均diamonds %>% group_by(color) %>% summarise(depth = mean(depth), table = mean(table), price = mean(price))`summarise()` ungrouping output (override with `.groups` argument)# A tibble: 7 x 4 color depth table price <ord> <dbl> <dbl> <dbl>1 D 61.7 57.4 3170.2 E 61.7 57.5 3077.3 F 61.7 57.4 3725.4 G 61.8 57.3 3999.5 H 61.8 57.5 4487.6 I 61.8 57.6 5092.7 J 61.9 57.8 5324.
新バージョンでは、acrossを使用して、こんな感じで書けます!
acrossの第一引数で列を指定し、第二引数で処理内容を記述します。
新バージョン
# depth, table, priceの平均diamonds %>% group_by(color) %>% summarise(across(depth:price, mean))`summarise()` ungrouping output (override with `.groups` argument)# A tibble: 7 x 4 color depth table price <ord> <dbl> <dbl> <dbl>1 D 61.7 57.4 3170.2 E 61.7 57.5 3077.3 F 61.7 57.4 3725.4 G 61.8 57.3 3999.5 H 61.8 57.5 4487.6 I 61.8 57.6 5092.7 J 61.9 57.8 5324.
acrossの第一引数は、selectと同じ要領で列を選択できます。
# numeric型の平均diamonds %>% group_by(color) %>% summarise(across(where(is.numeric), mean))`summarise()` ungrouping output (override with `.groups` argument)# A tibble: 7 x 8 color carat depth table price x y z <ord> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>1 D 0.658 61.7 57.4 3170. 5.42 5.42 3.342 E 0.658 61.7 57.5 3077. 5.41 5.42 3.343 F 0.737 61.7 57.4 3725. 5.61 5.62 3.464 G 0.771 61.8 57.3 3999. 5.68 5.68 3.515 H 0.912 61.8 57.5 4487. 5.98 5.98 3.706 I 1.03 61.8 57.6 5092. 6.22 6.22 3.857 J 1.16 61.9 57.8 5324. 6.52 6.52 4.03
acrossの第二引数は、Rのbase関数だけでなく、自分で処理内容を書くことも可能です。
# ~の後に処理内容を記載。.xは、指定した列を表している。# numeric型の平均を標準偏差で割った値diamonds %>% group_by(color) %>% summarise(across(where(is.numeric), ~ mean(.x) / sd(.x) ) )`summarise()` ungrouping output (override with `.groups` argument)# A tibble: 7 x 8 color carat depth table price x y z <ord> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>1 D 1.83 43.7 26.0 0.944 5.77 5.79 5.782 E 1.78 42.7 25.6 0.920 5.63 5.46 5.073 F 1.85 42.9 25.4 0.984 5.57 5.62 5.544 G 1.75 45.1 26.7 0.987 5.24 5.28 5.205 H 1.75 42.8 25.7 1.06 5.00 4.54 4.976 I 1.77 42.4 25.0 1.08 4.96 5.00 4.997 J 1.95 39.9 25.0 1.20 5.42 5.45 5.44
処理内容を外だしにすることもできます。
mean_sd <- list( mean = ~mean(.x, na.rm = TRUE), sd = ~sd(.x, na.rm = TRUE))# numeric型の平均と標準偏差diamonds %>% group_by(color) %>% summarize(across(where(is.numeric), mean_sd))`summarise()` ungrouping output (override with `.groups` argument)# A tibble: 7 x 15 color carat_mean carat_sd depth_mean depth_sd table_mean table_sd price_mean price_sd x_mean x_sd y_mean y_sd z_mean z_sd <ord> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>1 D 0.658 0.360 61.7 1.41 57.4 2.21 3170. 3357. 5.42 0.939 5.42 0.936 3.34 0.5792 E 0.658 0.369 61.7 1.44 57.5 2.24 3077. 3344. 5.41 0.961 5.42 0.993 3.34 0.6593 F 0.737 0.398 61.7 1.44 57.4 2.26 3725. 3785. 5.61 1.01 5.62 0.999 3.46 0.6264 G 0.771 0.441 61.8 1.37 57.3 2.15 3999. 4051. 5.68 1.08 5.68 1.08 3.51 0.6745 H 0.912 0.521 61.8 1.44 57.5 2.24 4487. 4216. 5.98 1.20 5.98 1.32 3.70 0.7446 I 1.03 0.579 61.8 1.46 57.6 2.30 5092. 4722. 6.22 1.25 6.22 1.24 3.85 0.7707 J 1.16 0.596 61.9 1.55 57.8 2.31 5324. 4438. 6.52 1.20 6.52 1.20 4.03 0.741
acrossの第三引数で列名を指定することもできます。
mean_sd <- list( mean = ~mean(.x, na.rm = TRUE), sd = ~sd(.x, na.rm = TRUE))# numeric型の平均と標準偏差# {fn}が関数名、{col}が指定した列名diamonds %>% group_by(color) %>% summarize(across(where(is.numeric), mean_sd, .names = "{fn}.{col}"))`summarise()` ungrouping output (override with `.groups` argument)# A tibble: 7 x 15 color mean.carat sd.carat mean.depth sd.depth mean.table sd.table mean.price sd.price mean.x sd.x mean.y sd.y mean.z sd.z <ord> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>1 D 0.658 0.360 61.7 1.41 57.4 2.21 3170. 3357. 5.42 0.939 5.42 0.936 3.34 0.5792 E 0.658 0.369 61.7 1.44 57.5 2.24 3077. 3344. 5.41 0.961 5.42 0.993 3.34 0.6593 F 0.737 0.398 61.7 1.44 57.4 2.26 3725. 3785. 5.61 1.01 5.62 0.999 3.46 0.6264 G 0.771 0.441 61.8 1.37 57.3 2.15 3999. 4051. 5.68 1.08 5.68 1.08 3.51 0.6745 H 0.912 0.521 61.8 1.44 57.5 2.24 4487. 4216. 5.98 1.20 5.98 1.32 3.70 0.7446 I 1.03 0.579 61.8 1.46 57.6 2.30 5092. 4722. 6.22 1.25 6.22 1.24 3.85 0.7707 J 1.16 0.596 61.9 1.55 57.8 2.31 5324. 4438. 6.52 1.20 6.52 1.20 4.03 0.741
summarize以外
今まではsummarizeに対するacrossを取り扱ってきましたが、acrossは他の関数でも使用できます。
#ordered型の組み合わせdiamonds %>% distinct(across(where(is.ordered)))# A tibble: 276 x 3 cut color clarity <ord> <ord> <ord> 1 Ideal E SI2 2 Premium E SI1 3 Good E VS1 4 Premium I VS2 5 Good J SI2 6 Very Good J VVS2 7 Very Good I VVS1 8 Very Good H SI1 9 Fair E VS2 10 Very Good H VS1 # ... with 266 more rows
#ordered型の組み合わせの個数 降順にソートdiamonds %>% count(across(where(is.ordered)), sort = T)# A tibble: 276 x 4 cut color clarity n <ord> <ord> <ord> <int> 1 Ideal E VS2 1136 2 Ideal G VS1 953 3 Ideal D VS2 920 4 Ideal G VS2 910 5 Ideal F VS2 879 6 Ideal G VVS2 774 7 Ideal E SI1 766 8 Ideal H SI1 763 9 Ideal D SI1 73810 Premium G VS2 721# ... with 266 more rows
_if, _at, _allについて
旧バージョンでも、_if, _at, _allを使用することで複数の列に関数を適用することができました。
旧バージョン
# numeric型を正規化diamonds %>% mutate_if( is.numeric, ~ (.x - mean(.x)) / sd(.x) )# A tibble: 53,940 x 10 carat cut color clarity depth table price x y z <dbl> <ord> <ord> <ord> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> 1 -1.20 Ideal E SI2 -0.174 -1.10 -0.904 -1.59 -1.54 -1.57 2 -1.24 Premium E SI1 -1.36 1.59 -0.904 -1.64 -1.66 -1.74 3 -1.20 Good E VS1 -3.38 3.38 -0.904 -1.50 -1.46 -1.74 4 -1.07 Premium I VS2 0.454 0.243 -0.902 -1.36 -1.32 -1.29 5 -1.03 Good J SI2 1.08 0.243 -0.902 -1.24 -1.21 -1.12 6 -1.18 Very Good J VVS2 0.733 -0.205 -0.902 -1.60 -1.55 -1.50 7 -1.18 Very Good I VVS1 0.384 -0.205 -0.902 -1.59 -1.54 -1.51 8 -1.13 Very Good H SI1 0.105 -1.10 -0.901 -1.48 -1.42 -1.43 9 -1.22 Fair E VS2 2.34 1.59 -0.901 -1.66 -1.71 -1.4910 -1.20 Very Good H VS1 -1.64 1.59 -0.901 -1.54 -1.47 -1.63# ... with 53,930 more rows
旧バージョン
# 列名にeが含まれている列を正規化diamonds %>% mutate_at( vars(contains("e")), ~ (.x - mean(.x)) / sd(.x) )# A tibble: 53,940 x 10 carat cut color clarity depth table price x y z <dbl> <ord> <ord> <ord> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> 1 0.23 Ideal E SI2 -0.174 -1.10 -0.904 3.95 3.98 2.43 2 0.21 Premium E SI1 -1.36 1.59 -0.904 3.89 3.84 2.31 3 0.23 Good E VS1 -3.38 3.38 -0.904 4.05 4.07 2.31 4 0.290 Premium I VS2 0.454 0.243 -0.902 4.2 4.23 2.63 5 0.31 Good J SI2 1.08 0.243 -0.902 4.34 4.35 2.75 6 0.24 Very Good J VVS2 0.733 -0.205 -0.902 3.94 3.96 2.48 7 0.24 Very Good I VVS1 0.384 -0.205 -0.902 3.95 3.98 2.47 8 0.26 Very Good H SI1 0.105 -1.10 -0.901 4.07 4.11 2.53 9 0.22 Fair E VS2 2.34 1.59 -0.901 3.87 3.78 2.4910 0.23 Very Good H VS1 -1.64 1.59 -0.901 4 4.05 2.39# ... with 53,930 more rows
旧バージョン
# すべての列を正規化diamonds %>% select(where(is.numeric)) %>% mutate_all( ~ (.x - mean(.x)) / sd(.x) )# A tibble: 53,940 x 7 carat depth table price x y z <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> 1 -1.20 -0.174 -1.10 -0.904 -1.59 -1.54 -1.57 2 -1.24 -1.36 1.59 -0.904 -1.64 -1.66 -1.74 3 -1.20 -3.38 3.38 -0.904 -1.50 -1.46 -1.74 4 -1.07 0.454 0.243 -0.902 -1.36 -1.32 -1.29 5 -1.03 1.08 0.243 -0.902 -1.24 -1.21 -1.12 6 -1.18 0.733 -0.205 -0.902 -1.60 -1.55 -1.50 7 -1.18 0.384 -0.205 -0.902 -1.59 -1.54 -1.51 8 -1.13 0.105 -1.10 -0.901 -1.48 -1.42 -1.43 9 -1.22 2.34 1.59 -0.901 -1.66 -1.71 -1.4910 -1.20 -1.64 1.59 -0.901 -1.54 -1.47 -1.63# ... with 53,930 more rows
新バージョンではacrossを使用することで、これらを以下のように修正できます。
一つの書き方を覚えればいいので、こちらのほうが便利ですね!
新バージョン
# numeric型を正規化diamonds %>% mutate( across(where(is.numeric), ~ (.x - mean(.x)) / sd(.x) ) )# A tibble: 53,940 x 10 carat cut color clarity depth table price x y z <dbl> <ord> <ord> <ord> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> 1 -1.20 Ideal E SI2 -0.174 -1.10 -0.904 -1.59 -1.54 -1.57 2 -1.24 Premium E SI1 -1.36 1.59 -0.904 -1.64 -1.66 -1.74 3 -1.20 Good E VS1 -3.38 3.38 -0.904 -1.50 -1.46 -1.74 4 -1.07 Premium I VS2 0.454 0.243 -0.902 -1.36 -1.32 -1.29 5 -1.03 Good J SI2 1.08 0.243 -0.902 -1.24 -1.21 -1.12 6 -1.18 Very Good J VVS2 0.733 -0.205 -0.902 -1.60 -1.55 -1.50 7 -1.18 Very Good I VVS1 0.384 -0.205 -0.902 -1.59 -1.54 -1.51 8 -1.13 Very Good H SI1 0.105 -1.10 -0.901 -1.48 -1.42 -1.43 9 -1.22 Fair E VS2 2.34 1.59 -0.901 -1.66 -1.71 -1.4910 -1.20 Very Good H VS1 -1.64 1.59 -0.901 -1.54 -1.47 -1.63# ... with 53,930 more rows
新バージョン
# 列名にeが含まれている列を正規化diamonds %>% mutate( across(contains("e"), ~ (.x - mean(.x)) / sd(.x) ) )# A tibble: 53,940 x 10 carat cut color clarity depth table price x y z <dbl> <ord> <ord> <ord> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> 1 0.23 Ideal E SI2 -0.174 -1.10 -0.904 3.95 3.98 2.43 2 0.21 Premium E SI1 -1.36 1.59 -0.904 3.89 3.84 2.31 3 0.23 Good E VS1 -3.38 3.38 -0.904 4.05 4.07 2.31 4 0.290 Premium I VS2 0.454 0.243 -0.902 4.2 4.23 2.63 5 0.31 Good J SI2 1.08 0.243 -0.902 4.34 4.35 2.75 6 0.24 Very Good J VVS2 0.733 -0.205 -0.902 3.94 3.96 2.48 7 0.24 Very Good I VVS1 0.384 -0.205 -0.902 3.95 3.98 2.47 8 0.26 Very Good H SI1 0.105 -1.10 -0.901 4.07 4.11 2.53 9 0.22 Fair E VS2 2.34 1.59 -0.901 3.87 3.78 2.4910 0.23 Very Good H VS1 -1.64 1.59 -0.901 4 4.05 2.39# ... with 53,930 more rows
新バージョン
# すべての列を正規化diamonds %>% select(where(is.numeric)) %>% mutate( across(everything(), ~ (.x - mean(.x)) / sd(.x) ) )# A tibble: 53,940 x 7 carat depth table price x y z <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> 1 -1.20 -0.174 -1.10 -0.904 -1.59 -1.54 -1.57 2 -1.24 -1.36 1.59 -0.904 -1.64 -1.66 -1.74 3 -1.20 -3.38 3.38 -0.904 -1.50 -1.46 -1.74 4 -1.07 0.454 0.243 -0.902 -1.36 -1.32 -1.29 5 -1.03 1.08 0.243 -0.902 -1.24 -1.21 -1.12 6 -1.18 0.733 -0.205 -0.902 -1.60 -1.55 -1.50 7 -1.18 0.384 -0.205 -0.902 -1.59 -1.54 -1.51 8 -1.13 0.105 -1.10 -0.901 -1.48 -1.42 -1.43 9 -1.22 2.34 1.59 -0.901 -1.66 -1.71 -1.4910 -1.20 -1.64 1.59 -0.901 -1.54 -1.47 -1.63# ... with 53,930 more rows
旧バージョンと比較して、列操作が柔軟になりました!
ぜひとも使いこなしたいですね!
devtools::session_info()- Session info -------------------------------------------------------------------------------------------------------------------- setting value version R version 3.6.3 (2020-02-29) os Windows >= 8 x64 system x86_64, mingw32 ui RStudio language (EN) collate Japanese_Japan.932 ctype Japanese_Japan.932 tz Asia/Tokyo date 2020-06-17 - Packages ------------------------------------------------------------------------------------------------------------------------ package * version date lib source assertthat 0.2.1 2019-03-21 [1] CRAN (R 3.6.3) backports 1.1.7 2020-05-13 [1] CRAN (R 3.6.3) blob 1.2.1 2020-01-20 [1] CRAN (R 3.6.3) broom 0.5.6 2020-04-20 [1] CRAN (R 3.6.3) callr 3.4.3 2020-03-28 [1] CRAN (R 3.6.3) cellranger 1.1.0 2016-07-27 [1] CRAN (R 3.6.3) cli 2.0.2 2020-02-28 [1] CRAN (R 3.6.3) colorspace 1.4-1 2019-03-18 [1] CRAN (R 3.6.3) crayon 1.3.4 2017-09-16 [1] CRAN (R 3.6.3) DBI 1.1.0 2019-12-15 [1] CRAN (R 3.6.3) dbplyr 1.4.4 2020-05-27 [1] CRAN (R 3.6.3) desc 1.2.0 2018-05-01 [1] CRAN (R 3.6.3) devtools 2.3.0 2020-04-10 [1] CRAN (R 3.6.3) digest 0.6.25 2020-02-23 [1] CRAN (R 3.6.3) dplyr * 1.0.0 2020-05-29 [1] CRAN (R 3.6.3) ellipsis 0.3.1 2020-05-15 [1] CRAN (R 3.6.3) evaluate 0.14 2019-05-28 [1] CRAN (R 3.6.3) fansi 0.4.1 2020-01-08 [1] CRAN (R 3.6.3) forcats * 0.5.0 2020-03-01 [1] CRAN (R 3.6.3) fs 1.4.1 2020-04-04 [1] CRAN (R 3.6.3) generics 0.0.2 2018-11-29 [1] CRAN (R 3.6.3) ggplot2 * 3.3.1 2020-05-28 [1] CRAN (R 3.6.3) glue 1.4.1 2020-05-13 [1] CRAN (R 3.6.3) gtable 0.3.0 2019-03-25 [1] CRAN (R 3.6.3) haven 2.3.1 2020-06-01 [1] CRAN (R 3.6.3) hms 0.5.3 2020-01-08 [1] CRAN (R 3.6.3) htmltools 0.4.0 2019-10-04 [1] CRAN (R 3.6.3) httr 1.4.1 2019-08-05 [1] CRAN (R 3.6.3) jsonlite 1.6.1 2020-02-02 [1] CRAN (R 3.6.3) knitr 1.28 2020-02-06 [1] CRAN (R 3.6.3) lattice 0.20-38 2018-11-04 [2] CRAN (R 3.6.3) lifecycle 0.2.0 2020-03-06 [1] CRAN (R 3.6.3) lubridate 1.7.9 2020-06-08 [1] CRAN (R 3.6.3) magrittr 1.5 2014-11-22 [1] CRAN (R 3.6.3) memoise 1.1.0 2017-04-21 [1] CRAN (R 3.6.3) modelr 0.1.8 2020-05-19 [1] CRAN (R 3.6.3) munsell 0.5.0 2018-06-12 [1] CRAN (R 3.6.3) nlme 3.1-144 2020-02-06 [2] CRAN (R 3.6.3) pillar 1.4.4 2020-05-05 [1] CRAN (R 3.6.3) pkgbuild 1.0.8 2020-05-07 [1] CRAN (R 3.6.3) pkgconfig 2.0.3 2019-09-22 [1] CRAN (R 3.6.3) pkgload 1.1.0 2020-05-29 [1] CRAN (R 3.6.3) prettyunits 1.1.1 2020-01-24 [1] CRAN (R 3.6.3) processx 3.4.2 2020-02-09 [1] CRAN (R 3.6.3) ps 1.3.3 2020-05-08 [1] CRAN (R 3.6.3) purrr * 0.3.4 2020-04-17 [1] CRAN (R 3.6.3) R6 2.4.1 2019-11-12 [1] CRAN (R 3.6.3) Rcpp 1.0.4.6 2020-04-09 [1] CRAN (R 3.6.3) readr * 1.3.1 2018-12-21 [1] CRAN (R 3.6.3) readxl 1.3.1 2019-03-13 [1] CRAN (R 3.6.3) remotes 2.1.1 2020-02-15 [1] CRAN (R 3.6.3) renv 0.10.0 2020-05-06 [1] CRAN (R 3.6.3) reprex 0.3.0 2019-05-16 [1] CRAN (R 3.6.3) rlang 0.4.6 2020-05-02 [1] CRAN (R 3.6.3) rmarkdown 2.1 2020-01-20 [1] CRAN (R 3.6.3) rprojroot 1.3-2 2018-01-03 [1] CRAN (R 3.6.3) rstudioapi 0.11 2020-02-07 [1] CRAN (R 3.6.3) rvest 0.3.5 2019-11-08 [1] CRAN (R 3.6.3) scales 1.1.1 2020-05-11 [1] CRAN (R 3.6.3) sessioninfo 1.1.1 2018-11-05 [1] CRAN (R 3.6.3) stringi 1.4.6 2020-02-17 [1] CRAN (R 3.6.2) stringr * 1.4.0 2019-02-10 [1] CRAN (R 3.6.3) testthat 2.3.2 2020-03-02 [1] CRAN (R 3.6.3) tibble * 3.0.1 2020-04-20 [1] CRAN (R 3.6.3) tidyr * 1.1.0 2020-05-20 [1] CRAN (R 3.6.3) tidyselect 1.1.0 2020-05-11 [1] CRAN (R 3.6.3) tidyverse * 1.3.0 2019-11-21 [1] CRAN (R 3.6.3) usethis 1.6.1 2020-04-29 [1] CRAN (R 3.6.3) utf8 1.1.4 2018-05-24 [1] CRAN (R 3.6.3) vctrs 0.3.1 2020-06-05 [1] CRAN (R 3.6.3) withr 2.2.0 2020-04-20 [1] CRAN (R 3.6.3) xfun 0.13 2020-04-13 [1] CRAN (R 3.6.3) xml2 1.3.2 2020-04-23 [1] CRAN (R 3.6.3) yaml 2.2.1 2020-02-01 [1] CRAN (R 3.6.3)
15
Go to list of users who liked
12
comment0
Go to list of comments
Register as a new user and use Qiita more conveniently
- You get articles that match your needs
- You can efficiently read back useful information
- You can use dark theme
What you can do with signing up
Sign upLogin