魂の生命の領域

AWS とか Python とか本読んだ感想とか哲学とか書きます

nヶ月間保管されるデータの月額保存料金から当月の増加分に想いを馳せる

設定

例えば直近3ヶ月間のデータを保管するストレージがあったとします。

3ヶ月よりも前のデータは勝手に削除されるとします。

そして保管されたデータ量に比例した課金(以降はストレージ料金と呼ぶことにします)がなされるとします。

システムが3ヶ月以上で稼働しているとすると、ある月のストレージ料金は当然直近3ヶ月分のデータ容量に単価を掛けた金額になります。

ここで、月当たりのデータ量、つまり月当たりの増分を知りたい場合どうすればよいでしょうか?

単純に前月と今月の差を計算するのではダメそうです。

なぜなら、今が10月としてこの10月分だけを知りたいとした時、当月と前月のストレージ料金の差分を取ると

  • 当月:10月・9月・8月
  • 前月:9月・8月・7月

となって 当月 - 前月 = 10月 - 7月 のようにオマケの項「7月分」がついてくるからです。

これでは10月分のみを抽出することはできません。

そこで、今回はいくつかの仮定の下「10月分」だけを抽出する方法を考えてみたいと思います。

前提

ストレージ容量(例えばGB単位)とストレージ料金(例えばUSD)は定数倍の違いしかないとし、しばしば同一視します。

単純に文章量を減らすためです。

パターン1. 増分が毎月同じ

最初はほぼ自明なパターンを考えます。

毎月同じ量が増えるだけであれば、簡単です。

3ヶ月分保存するとして、当月の増分を s とすれば、当月のストレージ料金 SS = 3 * s となります。

したがって、s を求めるには、当月のストレージ料金 S を3で割れば良いことになります。

一般化して n ヶ月保存する場合は、当月のストレージ料金を n で割れば良いわけです。

簡単ですね。

適用できそうなケース

毎月のストレージ量を見て、ずっと一定であればこの方法が使えそうです。

パターン2. 増分が常に前月の定数シフト

次は、増分が毎月一定の数だけ増えているような状況を考えます。

システムの規模が徐々に大きくなっていく様子を表していると思えば、まぁ自然なパターンの一つだろうと思います。

具体的には、当月の増分が s であればその前月の増分は s-t 、さらにその前月は s-2t のようになるとします。

この時、3ヶ月分保存するとすれば当月のストレージ量 SS = s + (s - t) + (s - 2t) つまり S = 3s -3t となります。

前月のストレージ量を S' とすると S' = (s - t) + (s - 2t) + (s - 3) = 3s - 6sですから、

\displaystyle{
S - S' = (3s - 3t) - (3s - 6t) = 3t
}

が成り立ちます。したがって、当月の増分 s を考えると、

\begin{align}
&S = 3s - 3t = 3s - (S - S') \\
&\therefore s= \frac{2}{3}S - \frac{1}{3}S' \\
\end{align}

となり、求まりました。

これを一般化して直近 n ヶ月分保管するとすると、当月のストレージ料金は

\begin{align}
S &= s + (s - t) + (s - 2t) + \cdots + (s - (n - 1)t) \\
   &= ns - \sum_{k=1}^n(k-1) \\
   &= ns - n\frac{n-1}{2}t
\end{align}

となります。

また、前月比とのストレージ料金の差は S - S' = nt ですから、当月の増分 s を求めることができて、

\begin{align}
S &= ns - n\frac{n-1}{2}t \\
   &= ns - n\frac{n-1}{2}\left(\frac{S - S'}{n}\right) \\
\therefore s &= \frac{n+1}{2n}S - \frac{n-1}{2n}S'
\end{align}

となります。

適用できそうなケース

毎月のストレージ量の差分を見た時、それがずっと一定であればこの方法が使えそうです。

パターン3. 増分が常に前月の定数倍

次も、毎月一定ずつ増えていくケースを考えますが、前月の増分 s' と当月の増分 s が以下の関係にあるとします。

\begin{align}
s / s' = r
\end{align}

要するに毎月の増分が一定の比率 r だけ増えていくようなケースです。

ちなみに、前月のストレージ料金 S' と当月のストレージ料金 S とすると、同じく3ヶ月分保管するとして

\begin{align}
&S  = s + sr^{-1} + sr^{-2}  \\
&S' = sr^{-1} + sr^{-2} + sr^{-3} \\
\therefore &S/S' = \frac{1 + r^{-1} + r^{-2}}{r^{-1} + r^{-2} + r^{-3}} = r \\
\end{align}

が成り立ちます。

この場合も当月の増分 s を求めましょう。

\begin{align}
&S  = s + sr^{-1} + sr^{-2} \\
\therefore s &= \frac{S}{1 + r^{-1} + r^{-2}} \\
  &= \frac{S}{1 + S'/S +(S'/S)^2} \\
\end{align}

当月と前月のストレージ料金を使って表せます。

ちなみに、

\begin{align}
s &= \frac{S}{1 + r^{-1} + r^{-2}} \\
  &= \frac{S}{1 + S'/S +S'/S * S'' / S'} \\
  &= \frac{S^2}{S + S' +S''} \\
\end{align}

のように、直近3ヶ月分のストレージ料金を使って表すこともできます。

実データを扱うときはこちらのようなより参照するデータ量が多い方が情報量の観点から好ましかったりするんでしょうかね?(無知)

また、これもデータ保持期間に対して一般化することができます。

nヶ月間データを保持する場合、ある月の増分は

\begin{align}
s &= \frac{今月}{1 + (\frac{前月}{今月}) + (\frac{前月}{今月})^2 + \cdots + (\frac{前月}{今月})^{n-1}} \\
\end{align}

のように表せます。

n ヶ月分のデータを使う場合は

\begin{align}
s &= \frac{今月^2}{今月 + 前月 + 前々月 + \cdots + (n-1)ヶ月前} \\
\end{align}

のように表せます。

適用できそうなケース

毎月のストレージ量の比を見た時、それがずっと一定であればこの方法が使えそうです。

パターン4. 一般形

ホモサピエンスの性(さが)として、もっと一般化できないか考えたくなってきます。

例えば何かしらのパラメータ a に依存する関数を仮定して、何パターンか考えても良いかもしれません。

\begin{align}
S &= S' + f(a) \\ 
S &= S' * \tilde{f}(a) \\
S &= g(S') \\
S &= h(S', a) 
\end{align}

最初の二つの式は微妙ですね、例えば1つ目についてはおそらく \displaystyle{S _ t = S _ {t-1} + f _ {t-1}(a)} みたいに、どの時点での総ストレージ量かも考えないといけない気がします。 だってこれだと \displaystyle{t = f(a)} に置き換わるだけなので…

…これは今後の課題とします。

補足とおそらく見えていないこと

今回やったことは、等差数列の和や等比数列の和から初項を求めることでした。

これって、稼働した初月の請求書を見ることができれば、初項も知ることができますね。

実際にこれをやると誤差が大きくなりそうですが…

そもそも統計的な手法をちゃんと知っている人が見たら噴飯物の議論をしている気がする。

参考

Python の bool 型でインチキ哲学を構成する

Python における bool 型は、int 型のサブクラスらしい。

ブール値 (bool)

真偽値の False と True を表します。False と True を表す 2 つのオブジェクトのみがブール値オブジェクトです。ブール型は整数型の派生型であり、ほとんどの状況でそれぞれ 0 と 1 のように振る舞いますが、例外として文字列に変換されたときはそれぞれ "False" および "True" という文字列が返されます。

docs.python.org

だから bool 型どうしで四則演算ができる。

>>> True + True
2
>>> True + False
1
>>> True - True
0
>>> True * False
0

bool 型と int 型でも計算できる。

>>> 1 + True
2
>>> 5 * True
5
>>> True * 5
5

だいぶ奇妙な感じになって来た。

割り算をするともはや int 型ですらなくなる。

>>> True /2
0.5

ここから == を使って遊びたいが、混乱するかもしれないので一つだけポイントを復習しておく。

普段 == は if 文のところで書く。

>>> if 3 % 2 == 1:
...     print("yeah")
...
yeah

左辺ないし右辺がそれ単体で True と等価なオブジェクトの場合は右辺(あるいは左辺)を省略することもある。

>>> if 3 % 2:
...     print("yeah")
...
yeah

str 型は、空でないものは全部 True と等価なのでこうなる。

>>> if "hoge":
...     print("yeah")
...
yeah

こうではない。

>>> if "hoge" == True:
...     print("yeah")
...
>>>

こう言うことでもない。

>>> if "hoge" is True:
...     print("yeah")
...
<stdin>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?

こうだったら良い。(ダサいので誰もやらないけど)

>>> if bool("hoge") == True:
...     print("yeah")
...
yeah

要するにこういうこと。

>>> "hoge" == True
False
>>> bool("hoge") == True
True

以上を踏まえた上で、 True や False を使って変な式を作り、だり〜(ダルい)考察勢みたいな不必要な解釈を加えたい。

真実について

1. 真実に嘘を付け加えても真実

>>> True + False == True
True

2. 真実から真実を取り去るともはや嘘

>>> True - True == False
True

3. 真実に真実を付け加えると、嘘。(真実はいつも一つ!?)

>>> True + True == True
False

4. 真実を半分にすると、嘘。

>>> True / 2 == True
False

5. 真実を嘘で分割すると世界が崩壊する

>>> True / False
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero

6. 真実の肩に嘘を乗っけても真実

>>> True ** False == True
True

7. 嘘の肩に嘘を乗っけてると、もはや真実

>>> False ** False == True
True

まとめ

つまんね〜〜〜〜〜〜〜〜