グラフラプラシアンとPCAと固有値分解
- 点集合の座標が行列Xとして与えられているとき、そのペアワイズ内積行列は対称行列であり、それを固有値分解し
- 回転行列Vと非負固有値を対角成分とする対角行列とを使って
- と分解できる
- これは、点をVで回転して となるようななる、新しい座標を点に与え、その配置が、分散の観点で整然とした状態になるようにすること、と説明される。
- 一方、単純無向グラフには、ラプラシアン行列Lなるものがさだまる
- Lはその対角成分がグラフ頂点の次数であるような行列Dと、グラフの隣接行列Aとを使ってとして与えられる
- Lも対称行列であり、固有値分解すると、回転行列と固有値を対角成分とする対角行列の積に分解できて、行列Xの場合と同様に、グラフの各頂点に座標を持たせたとみなすことができる
- いわゆるPCAでは、大きな固有値に対する固有ベクトルが与える座標軸は、点の存在状態をおおまかにとらえる力が大きい
- 他方、グラフラプラシアンの場合には、小さな固有値に対する固有ベクトルが与える座標軸が、グラフをおおまかに分ける力が大きい
- ちなみに、連結グラフのラプラシアンの固有値の1つは0で、それ以外はすべて正であることが知られている
- PCAの固有値の働きとグラフラプラシアンの固有値の働きが、大小に関して逆転していることを解消することにする。それによりグラフにとっても何かしらの対称行列があり、その固有値分解が、頂点に座標のようなものを与え、値の大きい固有値に対応する軸がそのグラフ頂点のばらつきを大まかに説明するような、そんな構成にしたい
- グラフラプラシアンを離れて、正定値対称正方行列 Q を考える
- Qには逆行列が存在するとして、それをとする
- 今、Qを固有値分解すると、となるとする。ここでVは回転行列であり、は対角行列ですべての対角成分が正である
- Vは回転行列であるからである
- 実は、となる。ただし、Vは回転行列でQを固有値分解したものと同じであり、は対角行列であり、その値はすべて正で、かつ、の大きい順にi番目の固有値と、の小さい順にi番目の固有値との積は、i=1,2,....のすべてのiについて1になる
# 適当に正定値対称行列を作る library(GPArotation) n <- 5 # 回転行列 V <- Random.Start(n) # 正固有値となるように正成分の対角行列 Sigma <- diag(runif(n)*5) # 正定値対称行列 Q <- V %*% Sigma %*% t(V) # その逆行列 Qinv <- solve(Q) # 固有値分解する eout.Q <- eigen(Q) eout.Qinv <- eigen(Qinv) # 固有値のセットを昇順・降順を入れ替えて掛け合わせると、すべて1 eout.Q[[1]] * eout.Qinv[[1]][n:1] # 固有値ベクトルは、符号の入れ替えが起きるので、すべての固有ベクトルが、一致しているか、符号違いで一致しているかを以下の式で確かめる # 全成分がゼロになるので、固有値ベクトルが同じになっていることがわかる (eout.Q[[2]] - eout.Qinv[[2]][,n:1]) * (eout.Q[[2]] + eout.Qinv[[2]][,n:1])
- つまり、正定値対称行列の固有ベクトルと、その行列の逆行列の固有ベクトルは等しいことがわかる
- ただし、片方で大きい固有値に対応する固有ベクトルが、逆行列では小さい固有値に対応する固有ベクトルである、という対応関係にある
- したがって、ラプラシアンの0でない最小固有値に対する固有ベクトルは、ラプラシアンの逆行列の、2番目に大きな固有値に対応する固有ベクトルに一致する
- ちなみに、連結グラフのラプラシアンは1個の固有値を持つ。それに対応する「ラプラシアンの逆行列」の固有値は無限大となる
- このことから、実際には、ラプラシアンの逆行列を計算することはできないが、ラプラシアンの逆行列の大きな固有値に対応する固有ベクトルを求める代わりに、ラプラシアンの小さな固有値に対応する固有ベクトルを求め、その固有ベクトル軸が重要である、と言っている
- さらにちなみに、ラプラシアンの固有値ゼロに対応する固有ベクトルというのは、すべての成分の値が等しいベクトルのことである。逆に言うと、ラプラシアンの逆行列が取り扱えるとして、最大固有値に対応する固有ベクトルも、すべての成分の値が等しいベクトルになる、と言っている
- 今、PCAでは点をうまくばらつかせることを目指しており、ラプラシアンの固有値分解で得る固有ベクトルにもその役割を持たせようとしているわけなので、すべての頂点の座標が同じになるような固有値に興味はないから、ラプラシアンの逆行列の2番目に大きな固有値=ラプラシアンの2番目に小さな固有値が、頂点座標を決めるうえで最もおおまかな情報を持っていることになる
- グラフラプラシアンの逆行列は「無限大の固有値」を持たせる必要があるので、作れないが、「十分大きな固有値」を持たせることで近似することにすれば、以下のようになる
# 適当に単純無向グラフを作り library(igraph) n <- 7 A <- matrix(sample(0:1,n^2,replace=TRUE,prob=c(0.7,0.3)),n,n) A <- A + t(A) diag(A) <- 0 A <- sign(A) g <- graph.adjacency(A,mode="undirected") plot(g) # ラプラシアン行列を作る L <- diag(degree(g)) - A # ラプラシアン行列を固有値分解する eout <- eigen(L) # 固有値ベクトルの束の行列と固有値を対角成分とする対角行列とでラプラシアン行列を再計算してみる eout[[2]] %*% diag(eout[[1]]) %*% t(eout[[2]]) - L # essentially zero # ラプラシアン行列の逆行列は0なる固有値があるのでうまく行かない #Linv <- solve(L) # 0の固有値に対応させて大きな正の値を、非0の固有値に対応させて、その逆数を固有値とし # 固有値ベクトルはラプラシアンのそれをそのまま用いて # ラプラシアンの逆行列の近似行列を作る Linv. <- (eout[[2]]) %*% diag(c(1/eout[[1]][1:(n-1)],10^8)) %*% t(eout[[2]]) # ラプラシアンの逆行列を固有値分解してやる einvout <- eigen(Linv.) # ラプラシアンの固有値と # ラプラシアンの逆行列の固有値とは相互に逆数になっている eout[[1]] * einvout[[1]][n:1] # ラプラシアンの固有値ベクトルと # ラプラシアンの逆行列の固有値ベクトルとは # 符号の入れ替わりはあるが # それ以外は同一であることを確認する eout[[2]] - einvout[[2]][,n:1] eout[[2]] + einvout[[2]][,n:1] (eout[[2]] - einvout[[2]][,n:1]) * (eout[[2]] + einvout[[2]][,n:1])
パラパラめくる『統計学を哲学する』
- 価格: 3520 円
- 楽天で詳細を見る
- データを取って、手法を適用して、その結果を使う(検定する、推定する、予測する、論文に根拠として書く)とき、統計学・データサイエンスは、何をしてくれているのだろうか、と言うことを、いわゆる帰無仮説検定・ベイズ推定・モデル選択・過学習防止・深層学習/AI、因果推論に渡って、どれにも重きを置かずに(置かないように気を遣ってあることが強く感じられる書き方で)書かれた本でした
- データを手法でいじるけど、結局、何を自分は言いたいの・・・と言うことに疑問を持っているときに読むと、色々な視点から、未解決問題やその例も含めて、理解が進むと思います
- 目次
- 序章 統計学を哲学する?(3本柱としての、存在論・意味論・認識論)
- 第1章 現代統計学のパラダイム
- 記述統計(データと記述統計、経験主義、実証主義)
- 推測統計(確率モデル、統計モデル)
- 第2章 ベイズ統計
- 第3章 古典統計
- 頻度主義の意味論
- 検定
- 古典統計の哲学的側面(帰納行動、外在主義的認識論、認識論としての古典統計)
- 第4章 モデル選択と深層学習
- 第5章 因果推論
- 規則説と回帰分析
- 反事実条件アプローチ
- 構造的因果モデル
- 統計的因果推論の哲学的含意
- 終章 統計学の存在論・意味論・認識論(統計学の扱う対象としては何が「存在」し、それは、現実世界・利用現場では何を「意味」し、データへの統計学・データサイエンス手法の適用から、何を知るのか、「認識」するのか
- 用語集
- 存在論・意味論・認識論
- 統計量、標本、多変量統計量
- 実証主義、理解できるような法則としてまとめる、思考の経済、記述統計、恒常的連結(因果の直接的発生源ではなく)
- 経験主義、実証主義、帰納、自然の斉一性
- 推測統計、確率モデル、確率論、母集団、標本空間、事象、確率・条件月確率、独立・従属、全確率・周辺化、ベイズ定理、確率変数・確率分布、同時確率分布、周辺確率分布、確率密度・確率密度関数、期待値・母平均・母分散、IID (independent and identically distributed)、大数の法則、中心極限定理、推定量、確率収束、統計モデル、パラメトリック統計・分布族、「確率種」
- ベイズ統計と主観・信念の度合い、尤度・事前確率・事後確率、仮説の確証と反証、パラメータ推定、予測、事後予測分布、機能論理、正当化された真なる信念、認識論的内在主義、真理促進的・遡行問題、基準率の誤謬、基礎付け主義、無差別の原理・無情報事前分布、経験ベイズ、主要原理、参照クラス、モデルチェック、仮説演繹法、デュエム・クワインテーゼ、認識論的全体論
- 頻度主義、蓋然的仮説の反証、反証主義、帰無仮説・対立仮説、帰無仮説、第1種過誤・第2種過誤、有意水準・サイズ・検出力・p値、検定と帰納行動、外在主義的認識論、信頼性主義、ゲティア問題、ノージックの追跡理論、信頼性主義的正当化、反事実的、可能世界意味論、p値問題、再現性の危機、多重検定、p-hacking、停止規則問題、一般性問題
- 最尤法、最尤推定量、対数尤度、モデル適合、学習、適合モデル、最小二乗法
- 回帰、説明変数、目的変数、モデル選択、過適合・過学習、赤池情報量基準、プラグマティズム、統計的一致性
- 深層学習、多層ニューラルネトワーク、誤差函数、誤差逆伝搬法、勾配消失問題、正則化
- プラグマティズム認識論、真理から予測へ
- 自然選択と試行錯誤による最適化、敵対的生成ネットワーク(GAN)、徳認識論(能力に基づいて得られる認識に対する尊重、の、ようなもの)、敵対的事例、動物的知識・反省的知識、説明可能な人工知能、表現学習・転移学習、翻訳の不確定性
- 統計的因果推論、規則説、交絡要因、条件付き独立、共変量、反事実条件説、仮説検定と因果推論、仮想結果、無作為化、因果推論の根本問題、潜在結果、平均処置効果、無作為化比較試験、強く無視できる割り当て条件、傾向スコア、反実仮想モデル、構造的因果モデル、因果グラフ、有向分離、因果的マルコフ条件、構造方程式、介入、バックドア基準、因果探索、忠実的条件、被覆法則モデル、三元論的な存在論、ベイズネット、因果種
Let’s read the document "sklearn.tree.DecisionTreeClassifier"
- Click the [https://github.com/scikit-learn/scikit-learn/blob/42aff4e2e/sklearn/tree/_classes.py#L607:title=\[source\]] and check that the information in the website is provided in the source. ソースコードを見てみよう
- What to know about 知っておくとよいこと
- "Parameters" パラメタ(引数)
- Parameters determine the conditions of "learning procedure" of the object you make.
- パラメタは学習をするために作成したオブジェクトに、学習をするときの条件を与える
- "Attributes" 属性
- The python object to perform "learning" should have various information it needs to run and it generates during the run and information you want to know or to take out.
- 属性は、学習を実行する際に必要な情報や、学習をさせた後で保持しておくべき、情報としてオブジェクトに付属してストックされる。属性は呼び出せる
- "Methods" メソッド・関数
- Methods are functions you can use with the object.
- 学習用に作成したオブジェクトから使える関数のこと
- The functions to perform the "learning" procedure itself are included.
- 学習を実施するには、入力を取っていろいろなことをしないいけないが、そのするべきことが関数として指定されている。その関数が含まれる
- Also the functions useful to process the inputs and outputs so that the users feel comfortable to use the object.
- その他に、学習の入出をいじったり加工したりできると便利なので、便利関数がオブジェクトから呼び出せるようになっている
- "Parameters" パラメタ(引数)
- Python commands
- Show parameters and attributes (splitter is a parameter. max_features_ is an attribute)
- パラメタと属性を表示させてみる
clf.splitter
clf.max_features_
-
- Another way to get the value of parameters/attributes
getattr(clf,"max_features_") getattr(clf,"splitter")
-
- Use a function in Methods. メソッド登録されている関数を使ってみる
- Learn and generate a model
- Use a function in Methods. メソッド登録されている関数を使ってみる
clf.fit(X,y)
-
-
- Use the generated model
-
clf.predict(X)
- ipynb
Decision Tree & Graphviz、pip, conda を使う
- Visit this site for the original codes.
- Start your jupyter notebook ジュピターノートブックを開始する
- (1) Start your "Anaconda navigator" then select jupyter notebook. アナコンダ・ナビゲータを立ち上げて、そのメニューからジュピターノートブックを立ち上げてもよい
- (2) Or start "jupyter notebook" directly. You can type "jupyter notebook" in your terminal for this. ジュピターノートブックを直接立ち上げてもよい。ターミナルに"jupyter notebook"と打ち込んで立ち上げることもできる
- Open a new jupyter notebook with "python3" kernel in your browser. 新しいジュピターノートブック(カーネルはpython3)をブラウザで開く
- Write (or copy-and-paste) the following python commands 以下のパイソンコマンドをノートブックに書きます(コピーペーストします)
- Each section should be filled in each chunk. 一区切りごとに1チャンクに書き込みます
- We will encounter various errors, but let's solve them one by one. エラーが続出すると思いますが、一つずつ解決していきます
# The following codes are borrowed from https://qiita.com/Hawaii/items/53efe3e96b1171ebc7db # pandas for Data structure "dataframe" # numpy for matrix-like data structure # sklearn for machine learning import pandas as pd import numpy as np from sklearn.tree import DecisionTreeClassifier, export_graphviz
# To make an image of "decision-tree" and display # Non-python application "Graphviz" is required # this python package "graphviz" connects NON-python application "Graphviz" into python environment import graphviz # python package to assist Graphviz functionality import pydotplus # something to show the image in jupyter notebook from IPython.display import Image # something to show the image in jupyter notebook (environment dependency is likely) from sklearn.externals.six import StringIO # If you get an error from the above line, try # from io import StringIO
data = pd.DataFrame({ "buy(y)":[True,True,True,True,True,True,True,False,False,False,False,False,False], "high":[4, 5, 3, 1, 6, 3, 4, 1, 2, 1, 1,1,3], "size":[30, 45, 32, 20, 35, 40, 38, 20, 18, 20, 22,24,25], "autolock":[1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0,1,0] })
y = data.loc[:,["buy(y)"]] X = data.loc[:,["high", "size","autolock"]]
clf = DecisionTreeClassifier() clf = clf.fit(X, y)
# Mac dot_data = StringIO() # "dot-format" information for "tree-graph" will be stocked export_graphviz(clf, out_file=dot_data, feature_names=["high", "size","autolock"], class_names=["False","True"], filled=True, rounded=True, special_characters=True) graph = pydotplus.graph_from_dot_data(dot_data.getvalue()) #graph.progs = {'dot': u"C:\\tools\\Anaconda3\\Library\\bin\\dot.bat"} # 追加部分 Image(graph.create_png())
# Windows dot_data = StringIO() # "dot-format" information for "tree-graph" will be stocked export_graphviz(clf, out_file=dot_data, feature_names=["high", "size","autolock"], class_names=["False","True"], filled=True, rounded=True, special_characters=True) graph = pydotplus.graph_from_dot_data(dot_data.getvalue()) graph.progs = {'dot': u"C:\\tools\\Anaconda3\\Library\\bin\\dot.bat"} # Windows #C:\tools\Anaconda3\Library\bin\dot.bat # graph.progs = {'dot': u"C:\\Users\\ryamada\\Anaconda3\\Library\\bin\\dot.bat"} # worked in another Windows environment. Image(graph.create_png())
print(graph.to_string())
- pip
- Open the regular terminal
pip install --upgrade pip
-
- Install the packages if you get errors @ import xxxx
pip install xxxx
-
- Graphviz can be installed in your local PC, either Mac or Windows... ダウンロードしてMac/WindowsのローカルPC上でも使えます
- In my environment, python3 on jupyter notebook was able to call the installed Graphviz without further settings.
- In my environment, python3 on jupyter notebook failed to call the installed Graphviz (probably "path-problem"). Therefore, a python code line was added to specify the location of installed Graphviz's "dot"-functionality command file "dot.bat", based on an instruction here
conda install graphviz
-
-
- It installed "Graphviz" under the Anaconda folder in my windows PC: "C:\\tools\\Anaconda3\\Library\\bin\\dot.bat" WindowsではそのコマンドによりAnaconda関連の一式を納めた領域にGraphvizがインストールされます。
- As far as searched the websites, various errors/troubles around Graphviz and python connection. Graphvizをpythonで使うためにはいろいろな方法でGraphvizをインストールすることができるようです(難航した人が結構、存在する、ということの裏返し)
-
- If no solution, print out "dot-formatted string" and copy-and-paste the contents to the Graphviz-online. もしpythonからのGraphviz呼び出しに成功しなかったり、そもそもGraphvizがローカルPCで動かない場合には、pythonでGraphvizが受け付ける「グラフを描くための文字列」を作って、それを「Graphvizをウェブサイト上で動かすサイト」に持っていくという手もあります
print(graph.to_string())
digraph Tree { node [color="black", fontname=helvetica, shape=box, style="filled, rounded"]; edge [fontname=helvetica]; 0 [fillcolor="#399de524", label=<size ≤ 27.5<br/>gini = 0.497<br/>samples = 13<br/>value = [6, 7]<br/>class = True>]; 1 [fillcolor="#e58139d4", label=<autolock ≤ 0.5<br/>gini = 0.245<br/>samples = 7<br/>value = [6, 1]<br/>class = False>]; 0 -> 1 [headlabel="True", labelangle=45, labeldistance="2.5"]; 2 [fillcolor="#e58139ff", label=<gini = 0.0<br/>samples = 5<br/>value = [5, 0]<br/>class = False>]; 1 -> 2; 3 [fillcolor="#e5813900", label=<size ≤ 22.0<br/>gini = 0.5<br/>samples = 2<br/>value = [1, 1]<br/>class = False>]; 1 -> 3; 4 [fillcolor="#399de5ff", label=<gini = 0.0<br/>samples = 1<br/>value = [0, 1]<br/>class = True>]; 3 -> 4; 5 [fillcolor="#e58139ff", label=<gini = 0.0<br/>samples = 1<br/>value = [1, 0]<br/>class = False>]; 3 -> 5; 6 [fillcolor="#399de5ff", label=<gini = 0.0<br/>samples = 6<br/>value = [0, 6]<br/>class = True>]; 0 -> 6 [headlabel="False", labelangle="-45", labeldistance="2.5"]; }
- Regular terminal & Anaconda terminal
- You can get the jupyter notebook file here: 以上のpythonコマンドをjupyter notebook形式で保存したものは、以下から取れます
Add library/package ライブラリ/パッケージの追加 pip, conda
- Library > Package > Module
- Different terms... but, simply speaking, something you can get and use for your study.
- 名前が色々あるけれど、簡単に言えば、「取ってきて使うもの」
- PyPI : Py-thon P-ackage I-ndex
-
- python's libraries and packages are registered.
- パイソンのライブラリ/パッケージが登録してある
- Use pip command to install libraries/packages you want to use from the registry.
- pip コマンドを使って、使いたいライブラリ/パッケージを取って来る
- The command "pip" itself should be updated so that you can get the latest libraries/packages.
- コマンド "pip"自体を最新にして、最新のレジストリからライブラリ/パッケージを取って来る
pip install --upgrade pip
pip install hoge
- "conda"
- The command "conda" is to get something you use in your Anaconda-based environment.
- "conda"コマンドはアナコンダを使った作業環境に使用したいものを取って来るコマンド
- It gets python libraries/packages as well as other tools.
- pythonのライブラリ/パッケージも取って来るが、それ以外のツールも取って来る
- It brings them into your Anaconda-environment.
- 取ってきたものは、アナコンダが管理した環境で使えるようになる
- The command pip and the command conda can be used together.... This makes the beginners confused further.
- pip コマンドとconda コマンドとは併用もできるので、さらに混乱しますが…
- The famous libraries/packages are well maintained by both pip-system and conda-system and you might not find big trouble by the choice of pip vs. conda.
- 有名どころのライブラリ/パッケージはよくメンテナンスされているので、pipを使うかcondaを使うかで問題に巻き込まれることは少ないかもしれません。
- Environment to use python パイソンの使用環境
- You can make your computer do your tasks with python commands. The tasks are achieved with the communicating network of "python" itself and python's libraries/packages you downloaded with or without non-python applications.
- パイソンのコマンドを発行することで、コンピュータに仕事をやらせているとき、"python"の本体と、ダウンロードしてきたパイソンのライブラリ/パッケージと、場合によってはパイソンに属さないアプリとを連携したネットワークを使っている
- Python you installed without Anaconda, python already installed when you bought your PC, python you installed with Anaconda..., they behave differently.
- Anacondaを使わずにインストールしたパイソンと、PCを買ったときにすでに入っているパイソンと、アナコンダを使ってインストールしたパイソン.... これらの挙動は違います
- To control these differences, you should pay attention to the different terminals you can use.
- これらの違いをコントロールするために、使える「ターミナル」の違いに注意する必要があります
- It is not wise to learn all the backgrounds of this topic before enjoy the data analysis, but this knowledge will give you hints for the troubles you will face in future. I hope your net-surfing skills to solve the troubles become adequate before you face the first trouble of this kind.
- ここで言うトピックの背景について勉強を終えてからデータサイエンスをするのは得策ではないですが、このことを少しでも聞いておくと、いざ、トラブルに見舞われたときのとっかかりになるので書いておきます。いざ、この手のトラブルに見舞われたとき、コンピュータスキルが上がっていて、自力でネットサーフするなどして問題解決できるようになっていることを祈ります
Install Anaconda, Anacondaのインストール
- Let's use Anaconda。Anacondaを使う
-
- Why? どうして? (1)
- It provides basic libraries/packages for data science (numpy, scipy, pandas).
- データサイエンス用の基本ライブラリ・パッケージが入っているから (numpy, scipy, pandas)
- numpy: matrix, linear algebra 行列と線形代数
- scipy: mathematical functions 数学の関数
- pandas: data stocking structures and analysis functions for statistical analysis 統計解析用のデータ格納構造と解析関数
- Why? どうして? (2)
- It provides Jupyter-notebook, useful to make your skills better and to record your activities.
- Jupyter-notebookという、スキルアップと記録保存に便利なツールがついているから
- Why? どうして? (1)
- How to install Anaconda in English
-
- Win
-
- Win
numpy.ndarray と Rのapply()
- Rの行列で、各行の和を出そうと思ったら
M <- matrix(rnorm(100),10,10) apply(M,1,sum)
- だろう
- 同じことをPythonでやるのはどうするのかな、と思った
- Pythonで行列を扱うならnumpyがよいのでそうすることにしたとして
- 値のセットの和を出すsum()関数を、軸方向に指定して計算することもできて
M = np.array(np.random.randint(5,18000,100)).reshape(10,10) np.sum(M,axis=1)
- とするらしい。Rのapply(M,1,sum)と同じ構成
- それとは別に:
- numpyのndarrayにはuniversal functionsというのがある。名前は「大層」だが、全要素に同じ処理をして、同じサイズのndarrayを作る関数のこと(種類がたくさんある)
- このuniversal functionを繰り返し使って、答えをたたんでいくという処理をしろ、という指示である、reduceという「高階関数」と組み合わせるらしい
M = np.array(np.random.randint(5,18000,100)).reshape(10,10) np.add.reduce(M,axis=1)
- ちなみに、universal functionsのリストはここにある
- また、recude以外にも、「高階関数的ndarray処理」として、以下のようなものがあるらしい。どういううまみがあるのかまだわからない
- ufunc.reduce(a[, axis, dtype, out, …])
- Reduces a’s dimension by one, by applying ufunc along one axis.
- ufunc.accumulate(array[, axis, dtype, out])
- Accumulate the result of applying the operator to all elements.
- ufunc.reduceat(a, indices[, axis, dtype, out])
- Performs a (local) reduce with specified slices over a single axis.
- ufunc.outer(A, B, **kwargs)
- Apply the ufunc op to all pairs (a, b) with a in A and b in B.
- ufunc.at(a, indices[, b])
- Performs unbuffered in place operation on operand ‘a’ for elements specified by ‘indices’.
- ufunc.reduce(a[, axis, dtype, out, …])
- reduceのほかに、基本となる「高階関数」についてはこちらなどで。