NumPyとPandasの標準偏差の違い

よく忘れるのでメモしておく。

NumPyは母標準偏差、Pandasは標本標準偏差

標準偏差の計算をするとき、NumPyではstd()関数、Pandasでもstd()関数を使う。だが、同じstd()関数でもデフォルトの設定の場合、NumPyは母標準偏差を、Pandasは標本標準偏差を計算する。

母標準偏差と標本標準偏差の違いは以下の通りである。

\[ 母標準偏差 = \sqrt{\frac {1} {n} \sum_{i=1}^{n} (x_i - \overline{x})^{2}}\] \[ 標本標準偏差 = \sqrt{\frac {1} {n - 1} \sum_{i=1}^{n} (x_i - \overline{x})^{2}}\]

式を見れば分かるように、nが十分に大きければ、差はほとんど無い。移動ウィンドウで計算する場合はnが小さいときがある。こういうときは標本標準偏差のほうがいいのかなと思う。

名称の整理

ところで、標準偏差は呼び方が紛らわしい。そこで簡単に整理する。

母標準偏差の別の呼び方

  • 標本標準偏差(えっ?)

標本標準偏差の別の呼び方

  • 不偏標準偏差
  • 標本不偏標準偏差
(2017/02/14更新)

Pandasデータフレームのインデックス名の変更

Pandasデータフレームのインデックス名を変更したい場合は例えば以下のようにする。

○以下のコマンドをSpyderの「IPython console」にコピー&ペーストして「Enter」キーを2回押す。

import pandas as pd

df = pd.DataFrame(index=['1', '2', '3'], columns=['A', 'B', 'C'])
print(df)
print('\n')
df.index.name = 'index name'
print(df)
print('\n')
df.index.name = None
print(df)

出力

     A    B    C
1  NaN  NaN  NaN
2  NaN  NaN  NaN
3  NaN  NaN  NaN


              A    B    C
index name               
1           NaN  NaN  NaN
2           NaN  NaN  NaN
3           NaN  NaN  NaN


     A    B    C
1  NaN  NaN  NaN
2  NaN  NaN  NaN
3  NaN  NaN  NaN
(2017/02/06更新)

MarkdownをHTMLに変換

Markdownで書かれたファイルをhtmlに変換して別ファイルで保存するプログラムを作る。このプログラムはエスケープ処理も行っている。

markdownのインストール

これから作成するプログラムを実行するには、あらかじめ「markdown」ライブラリをインストールしておく必要がある。

①以下のコマンドを端末にコピー&ペーストして「Enter」キーを押す。

conda install markdown

②「Proceed ([y]/n)?」で「Enter」キーを押す。

プログラムの作成

○下のコードを「~/py」フォルダーに「markdown2html.py」ファイルとして保存する。

# coding: utf-8

import sys
import markdown

def markdown2html(md_file):
    '''markdownで書かれたファイルをhtmlに変換し、別ファイルとして作成する。
        Args:
            md_file: mdファイル名。
    '''

    # ファイルを読み込む。
    input_file = markdown.codecs.open(md_file, mode='r', encoding='utf-8')
    text = input_file.read()

    # htmlに変換する。
    html = markdown.markdown(text)

    # 書き込み用のファイルを作成する。
    html_file = md_file.replace('.md', '.html')
    output_file = markdown.codecs.open(html_file, 'w', encoding='utf-8',
                                       errors='xmlcharrefreplace')

    # ファイルを書き込む。
    output_file.write(html)

if __name__ == '__main__':
    # 設定を読み込む。
    argv = sys.argv
    md_file = argv[1]

    # markdownで書かれたファイルをhtmlに変換し、別ファイルとして作成する。
    markdown2html(md_file)

プログラムの実行

「~/ドキュメント/blog/00」フォルダーにMarkdownで書かれた「00.md」ファイルがあるとして説明する。

○以下のコマンドをSpyderの「IPython console」にコピー&ペーストして「Enter」キーを押す。

%run ~/py/markdown2html.py ~/ドキュメント/blog/00/00.md

「~/ドキュメント/blog/00」フォルダーにhtmlに変換された「00.html」ファイルが生成する。ちなみに、このブログの記事はこうやって作成している。

(2017/02/05更新)

「ValueError: Input contains NaN, infinity or a value too large for dtype('float64').」

Pythonで「scikit-learn」ライブラリを使用しているとき、「ValueError: Input contains NaN, infinity or a value too large for dtype('float64').」というエラーが発生することがある。データに「NaN」(非数値)、「inf」(無限大)、「-inf」(負の無限大)が含まれていると起こる。

エラーをなくすためには有効な数値に置き換える。ここでは例として「NaN」、「inf」、「-inf」を含むNumpy配列とPandasシリーズを作成し、これらを「0」で置き換えてみる。

○以下のサンプルプログラムをSpyderの「IPython console」にコピー&ペーストして「Enter」キーを2回押す

import numpy as np
import pandas as pd

a = np.array([float('nan'), float('inf'), float('-inf')])
s = pd.Series(np.array([float('nan'), float('inf'), float('-inf')]))

print(a)
a[(np.isnan(a)) | (a==float("inf")) | (a==float("-inf"))] = 0.0
print(a)

print('\n')

print(s)
s[(np.isnan(s)) | (s==float("inf")) | (s==float("-inf"))] = 0.0
print(s)

出力

[ nan  inf -inf]
[ 0.  0.  0.]

0    NaN
1    inf
2   -inf
dtype: float64
0    0.0
1    0.0
2    0.0
dtype: float64

たまたま気付いたことがある。Numpy配列を作成した後、これをPandasシリーズに変換して別の変数としたとする。Numpy配列のデータを何かに置き換えると、別の変数であるはずのPandasシリーズのデータも置き換えられてしまう。これは注意しないと予想外の問題を起こす可能性がある。

○以下のサンプルプログラムをSpyderの「IPython console」にコピー&ペーストして「Enter」キーを2回押す

import numpy as np
import pandas as pd

a = np.array([float('nan'), float('inf'), float('-inf')])
s = pd.Series(a)

print(s)
a[(np.isnan(a)) | (a==float("inf")) | (a==float("-inf"))] = 0.0
print(s)

出力

0    NaN
1    inf
2   -inf
dtype: float64
0    0.0
1    0.0
2    0.0
dtype: float64
(2017/02/04更新)

SciPyのlognorm()関数の引数指定について

SciPyのlognorm()関数を使おうと思ったのだが、引数をどうするのかが分からなくて苦労した。あれこれ試行錯誤してようやく分かったので、メモとして残す。

LibreOffice Calcで適当なセルに「=LOGNORMDIST(4,3.5,1.2,1)」と入力すると「0.0390835557」と返される。

「4」は調べたい数値(対数にする必要はなく、そのままでよい)、「3.5」はデータを対数に変換した後の平均、「1.2」はデータを対数に変換した後の標準偏差、「1」は戻り値として累積分布を指定、という意味である。

書式はExcelと同じである(Excelの場合は「LOGNORM.DIST」だが)。これと同じことをSciPyでやりたい。

この場合、

import numpy as np
from scipy.stats import lognorm
lognorm.cdf(x=4, s=1.2, loc=0, scale=np.exp(3.5))

とすればよい。

出力

0.039083555706800471

つまり、「x」には調べたい数値、「s」にはデータを対数に変換した後の標準偏差、「loc」には0、「scale」にはデータを対数に変換した後の平均を指数に変換(ややこしい)した数値を指定するのである。

非常に紛らわしいのだが、SciPyのnorm()関数で

norm.cdf(x=1.0, loc=0, scale=1)

とした場合、xは同じだが、「loc」は平均、「scale」は標準偏差を指定する。

これが頭にあったので、大混乱した。もう少し統一性を持たせてほしいものだが...。

(2016/10/07更新)