panda大学習帳外伝

勝利の方程式の解き方。

メインページ | panda大学習帳 | 第三倉庫(仮) | 用語集📒 | 本サイトについて | プライバシーポリシー


if文を使わないで旬を求める。

最終更新日: Thu Oct 7 08:34:56 2021 +0900

はじめに

2021年は「令和三年東京オリンピック競技大会・東京パラリンピック競技大会特別措置法」の第32条の規定により祝日が変更されました。

しかし、この法律案が成立したのが一般的な2021年のカレンダーが販売開始された後(2020年11月27日)であったため…

View this post on Instagram

pandanote.info(@pandanote_info)がシェアした投稿

のような、通常の年であれば何の変哲も問題もない(はずの)カレンダーの写真でも…

というような注意喚起が必要になったりします。

ところで、月を上旬、中旬または下旬に3分割する場合、

人間なら例えば、

「15日は上旬、中旬、下旬のうちどの旬に属しますか?」

という質問に比較的瞬時に「中旬である。」答えることができます。

しかし、コンピュータに上記の問題を解かせるにはどのようにしたら良いでしょうか?

if文を使う手もなくはないですが、人間は上記の質問の答えを考えるにあたって、if文またはif文的なものを思い浮かべつつ考えるということはなさそうですので、もう少し賢く解く手がありそうです。

そこで、この記事では日付からif文を使わずに対応する旬を求める方法を考えることにします。

スポンサーリンク

やりたいこと

そんなわけで、日付からif文を使わずに対応する旬を求めるために、

それぞれ出力として与える関数$f(x)$が作れないか考えてみます。



関数を作ります。

なんとなく適当な実数$a$を考え、$f(x)=\displaystyle\frac{x}{a}$と(とりあえず)置いてみます。

前節の条件を満たすためには、

\begin{align} 10/a&\lt 1, 11/a \ge 1 \label{eq:conditionone} \cr 20/a&\lt 2, 21/a \ge 2 \label{eq:conditiontwo} \cr 31/a&\lt 3 \label{eq:conditionthree} \end{align}

が成り立てば良さそうです。

条件式(\ref{eq:conditionone})から条件式(\ref{eq:conditionthree})に向かうに連れて条件が厳しくなり、$a$の取りうる値の範囲を少しずつ狭くしてくれます。

上記の条件をすべて満たす$a$の範囲は

\begin{align} 31/3 &\lt a \le 21/2 \label{eq:solution} \end{align}

になりますので、例えば $a = \displaystyle\frac{27}{5} (=10.4)$とおいて

\begin{align} f(x) &= \left\lfloor \displaystyle\frac{5}{27}x \right\rfloor \label{eq:function} \end{align}

という関数を考えると、$1 \le x \le 31$の範囲の整数$x$について$f(x)$が所望の値を出力してくれそうです。

試してみます。

何それおいしいの?

if文を使わないと何がありがたいのかというと、SQL文にそのまま入れることができたりします。

特に「SQL文を使いたいけど、種々の理由によりストアドプロシージャは作りたくない or あまり増やしたくない。」という場面で威力を発揮しそうです。

動作確認。

データの準備

まず、以下のようなSQL文(今回のテストにはSQLite3を使用しています。)でテスト用の日付を格納するテーブルを作ります。

sqlite> create table decade_test ( day integer );

次に、上記のテーブルにテスト用の日付をinsertします。

sqlite> insert into decade_test(day) values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15),(16),(17),(18),(19),(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),(30),(31);

ケース1

$a = 10.4$の場合です。上旬は0、中旬は1、下旬は2と正しく分類できていることが確認できます。

sqlite> select day,cast(day/10.4 as int) from decade_test;
1|0
2|0
3|0
4|0
5|0
6|0
7|0
8|0
9|0
10|0
11|1
12|1
13|1
14|1
15|1
16|1
17|1
18|1
19|1
20|1
21|2
22|2
23|2
24|2
25|2
26|2
27|2
28|2
29|2
30|2
31|2

ケース2

$a = 10.5$の場合です。このケースでも上旬は0、中旬は1、下旬は2と正しく分類できていることが確認できます。

sqlite> select day,cast(day/10.5 as int) from decade_test;
1|0
2|0
3|0
4|0
5|0
6|0
7|0
8|0
9|0
10|0
11|1
12|1
13|1
14|1
15|1
16|1
17|1
18|1
19|1
20|1
21|2
22|2
23|2
24|2
25|2
26|2
27|2
28|2
29|2
30|2
31|2

ケース3

$a = 10.2$の場合です。このケースは$a$の値が(\ref{eq:solution})式の範囲外になりますが、31日の分類に失敗していることがわかります。

sqlite> select day,cast(day/10.2 as int) from decade_test;
1|0
2|0
3|0
4|0
5|0
6|0
7|0
8|0
9|0
10|0
11|1
12|1
13|1
14|1
15|1
16|1
17|1
18|1
19|1
20|1
21|2
22|2
23|2
24|2
25|2
26|2
27|2
28|2
29|2
30|2
31|3

スポンサーリンク

まとめ

SQL文で任意の日付に対して上旬、中旬、下旬の区別ができるようになると、それらの日付に紐づいているレコードをgroup by句を用いてまとめることでおおよそ10日ごとの合計や平均値などを求めることができます。

そこで、「ある連続した日数を対象としたデータ列があったときに、そのデータ列についての統計を取りたいが、月ごとという括りは残しつつ、1ヵ月よりは短い連続した日数を1つの単位として区切り、その単位ごとの統計としたい。」という場合には上旬、中旬、下旬という「旬」を単位とすることができそうです。

リンク

メインページ | panda大学習帳 | 第三倉庫(仮) | 用語集📒 | 本サイトについて | プライバシーポリシー


スポンサーリンク