![見出し画像](https://assets.st-note.com/production/uploads/images/105146875/rectangle_large_type_2_9c81510932193f1399c30218abba0548.png?width=1200)
Snowflakeで「場合の数」の計算してみた
分析屋の中田(ナカタ)です。
Snowflakeで階乗・順列・組合せの計算をしてみました。
作りたいもの
階乗、順列、組合せを計算する関数を作ります。
高校数学の「場合の数」で登場するやつです。
紹介順
階乗の計算
順列の計算
組合せの計算
Pythonによる応用
環境
エディション:スタンダード版(トライアル期間)
ウェアハウス:Medium 1台
SnowflakeのワークシートでSQL文を実行していきます。
1.階乗
階乗についてはSnowflake標準のfactorial関数が用意されています。
factorial(6)は
=6!
=6*5*4*3*2*1
=720
になるはずです。
-- 6!
select factorial(6);
実行してみると720と表示されます。
![](https://assets.st-note.com/img/1683627369591-h2oWW1f8h0.png)
2.順列の計算
nPr:異なるn個からr個取り出して並べる並べ方
こちらは標準の関数がないため、自作する必要があります。
nPr = n! / (n-r)!
という公式の通り、先程のfactorial関数を用いて実験してみます。
5P2
=5! / (5-2)!
=5! / 3!
=5 * 4
=20
上記を例にしてみます。
-- 5P2
select factorial(5)/factorial(5-2);
たしかに20になっています。
![](https://assets.st-note.com/img/1683627408630-lIlhyuM0Qs.png)
3.組合せの計算
nCr:異なるn個からr個取り出す取り出し方
こちらも標準の関数がないため、自作する必要があります。
nCr = n! / r!(n-r)!
という公式の通り、factorial関数を用いて実験してみます。
5C2
=5! / 2!(5-2)!
=5! / 2!3!
=5 * 4 / 2
=10
上記を例にしてみます。
-- 5C2
select factorial(5)/(factorial(2)*factorial(5-2));
想定通り、10が表示されました。
![](https://assets.st-note.com/img/1683627457285-dDG2J9dc6p.png)
4.Pythonによる応用
さて、ここまでの内容を元に自作関数を作れば良さそうですが
いろいろな数を入れてみると不都合があることに気づきます。
まず、factorial関数の引数は最大33という制約があります。
factorial(34) つまり34!を計算しようとすると
整数のデータ型の最大(NUMERIC(38,0))を超えるためエラーが出てしまいます。
![](https://assets.st-note.com/img/1683627491568-x2RcshVJa0.png?width=1200)
ということは、factorial関数をもとにして計算する順列や組合せも
nPr や nCr の、 n と r は33以下でないと計算できないことになります。
試しに40P2を計算してみます。
-- 40P2
select factorial(40)/factorial(40-2);
やはりだめでした。
![](https://assets.st-note.com/img/1683627519374-GidNFPDvIk.png?width=1200)
そういう仕様だと諦めるには、引数の制限が厳しすぎる・・・。
この解決方法は通常、自己結合やら再帰やら配列やらを用いて解消するのですが
Snowflakeの場合はPythonで関数を記述すればシンプルになります。
-- 順列の関数作成
create or replace function perm(n int,r int)
returns int
language python
runtime_version = '3.8'
handler = 'nPr'
as
$$
import math
def nPr(n,r):
return math.perm(n,r)
$$;
標準モジュールのmathをimportして
perm関数を呼び出しています。
試しに、先程エラーになった40P2を計算してみます。
40P2
=40*39
=1560
になるはずです。
-- 40P2
select perm(40,2);
エラーなく計算できました。
![](https://assets.st-note.com/img/1683627561576-VRzRNF1xiI.png)
続いて組合せも、同じように関数を作成しておきます。
mathモジュールのcomb関数を使用しています。
-- 組合せの関数作成
create or replace function comb(n int,r int)
returns int
language python
runtime_version = '3.8'
handler = 'nCr'
as
$$
import math
def nCr(n,r):
return math.comb(n,r)
$$;
試しに40C2で計算してみます。
40C2
=40*39 / 2
=780
になるはずです。
-- 40C2
select comb(40,2);
問題なく計算できました。
![](https://assets.st-note.com/img/1683627591376-mAHGZy21Bn.png)
まとめ
Pythonのモジュールを使う自作関数(UDF)は、他製品への移植性を考えるとBADかもしれませんが
可読性や実装の手軽さは優れていると思います。
ここまでお読みいただき、ありがとうございました!
この記事が少しでも参考になりましたら「スキ」を押していただけると幸いです!
株式会社分析屋について
ホームページはこちら。
noteでの会社紹介記事はこちら。
【データ分析で日本を豊かに】
分析屋はシステム分野・ライフサイエンス分野・マーケティング分野の知見を生かし、多種多様な分野の企業様のデータ分析のご支援をさせていただいております。 「あなたの問題解決をする」をモットーに、お客様の抱える課題にあわせた解析・分析手法を用いて、問題解決へのお手伝いをいたします!
【マーケティング】
マーケティング戦略上の目的に向けて、各種のデータ統合及び加工ならびにPDCAサイクル運用全般を支援や高度なデータ分析技術により複雑な課題解決に向けての分析サービスを提供いたします。
【システム】
アプリケーション開発やデータベース構築、WEBサイト構築、運用保守業務などお客様の問題やご要望に沿ってご支援いたします。
【ライフサイエンス】
機械学習や各種アルゴリズムなどの解析アルゴリズム開発サービスを提供いたします。過去には医療系のバイタルデータを扱った解析が主でしたが、今後はそれらで培った経験・技術を工業など他の分野の企業様の問題解決にも役立てていく方針です。
【SES】
SESサービスも行っております。