PythonでExcel


およそPCでなんかをする時に、Excelの使用は避けて通れない。イマドキ、「Microsoft嫌いなんで」とか言って、Lotus 1-2-3を使うヒトも居らんでしょう。なんかの測定データ等はExcelのシート上に保存されている。となったら、Excelファイルからデータを読み出すくらいはできた方がいい。

# CSVではイカンのか

Excelでファイルを開いて、CSVとかタブ区切りテキスト形式とかで保存するその一手間をかける余裕がある時は、もちろんそれでいい。
でも、たまにあるんだよ。30日間の実験結果が30ファイルになっているとか。その場合は、それぞれのファイルを1個ずつ開いてはCSVに保存し直すという操作を繰り返すか、その操作を自動でやってくれるExcel VBAを書くか、うーんソレもいいな、ExcelのことはExcelで。

そうも言ってられないので、condaで提供されているExcelファイルの読み書きができそうなパッケージを探す。こういう時はググるしかない。xlrdというパッケージがあるらしい。

```
% anaconda search -t conda xlrd
Using Anaconda API: https://api.anaconda.org/
Run 'anaconda show <USER/PACKAGE>' to get more details:
Packages:
     Name                      |  Version | Package Types   | Platforms
     ------------------------- |   ------ | --------------- | ---------------
     RMG/xlrd                  |    0.9.4 | conda           | linux-64, win-32, win-64, linux-32, osx-64
     RahulJain/xlrd            |    1.0.0 | conda           | win-64
     aetrial/xlrd              |          | conda           | linux-64, osx-64
     anaconda/xlrd             |    1.0.0 | conda           | linux-64, win-32, win-64, linux-32, osx-64
     auto/xlrd                 |    0.8.0 | conda           | linux-64
                                          : http://www.python-excel.org/
     jetztcast/xlrd            |    0.9.3 | conda           | linux-64, osx-64
                                          : Library for developers to extract data from Microsoft Excel (tm) spreadsheet files
Found 6 packages
% anaconda show anaconda/xlrd
Using Anaconda API: https://api.anaconda.org/
Name:    xlrd
Summary:
Access:  public
Package Types:  conda
Versions:
   + 0.9.2
   + 0.9.4
   + 0.9.3
   + 0.9.0
   + 0.9.1
   + 1.0.0

To install this package with conda run:
     conda install --channel https://conda.anaconda.org/anaconda xlrd
```

# Excelのシートからデータを読み込む

単身赴任で京都に住んでた頃に「京都は暑いでしょう」ってよく言われていたので、検証のために2016年7月の東京と京都の日毎の最高気温のデータを気象庁からダウンロードしてExcelにまとめてみた。

![20160831001.jpg](https://qiita-image-store.s3.amazonaws.com/0/15553/302c78f3-35d2-4b60-a5d8-189e8530e772.jpeg "20160831001.jpg")

これ、見るだけで京都の方が暑いな。Pythonで解析するまでもないわ。でも、気を取り直して、両都市の平均気温を計算してみる。

```python
import xlrd
import os.path
import numpy as np
xlfile = "test.xlsx"
if os.path.exists(xlfile):
    xls = xlrd.open_workbook(xlfile)
    sheet1 = xls.sheet_by_index(0)
    nrows = sheet1.nrows-1
    ncols = sheet1.ncols 
    data = np.zeros(ncols*nrows).reshape((nrows, ncols))
    for r in range(1, nrows+1):
        for c in range(0, ncols):
            data[r-1,c] = sheet1.cell(r,c).value
    tokyo = data[:,1].mean()
    kyoto = data[:,2].mean()
    msg = "Tokyo(mean): %.2f\nKyoto(mean): %.2f" % (tokyo, kyoto)
    print(msg)
```

np.zeros()で中身0の配列を作って、reshape()で2次元配列に変形する。Excelの1行目はヘッダなので、sheet1.nrowsの値から1引いとく。numpyのarrayなので、平均を求めたかったらmean()するだけで良い。結果を見ると、やっぱり京都の方が暑いっスね。

## 検定
ところで、平均値の比較だけで本当に京都が暑いと決めても良いだろうか？ここはやっぱり統計的に有意な差があるかどうかを検定した方がいい。

平均値の差の検定は、scipyのstatsを使うと簡単にできる。

```python
import xlrd
import os.path
import numpy as np
from scipy import stats
xlfile = "test.xlsx"
if os.path.exists(xlfile):
    xls = xlrd.open_workbook(xlfile)
    sheet1 = xls.sheet_by_index(0)
    nrows = sheet1.nrows-1
    ncols = sheet1.ncols
    data = np.zeros(ncols*nrows).reshape((nrows, ncols))
    for r in range(1, nrows):
        for c in range(0, ncols):
            data[r-1,c] = sheet1.cell(r,c).value
    tokyo = data[:,1]
    kyoto = data[:,2]
    t,p = stats.ttest_ind(tokyo, kyoto, equal_var=False))
    msg = "p-value: %.5f" % p
    print(msg)
```

なお、東京と京都の気温では、「東京の方が低い」という仮説を検定するときは、片側検定になるんだけれど、片側検定であることを指定するoptionがstats.ttest_ind()メソッドには存在しないようだ。
なので、今回の場合は、t値が負の値でp-value が0.025以下になることを示すことでその代替とする。

で、実際にやってみると、以下のようになった。

	t: -4.09874
	p-value: 0.00014


## グラフ描画

Excelシートからデータを読み込んだので、グラフにしてみる。
Rならばggplot2を使う場面だけれど、Anaconda環境のPythonならばmatplotlibでできる。

```python
import xlrd
import os.path
import pandas as pd
import numpy as np
from scipy import stats
from matplotlib import pyplot as plt
%matplotlib inline 

xlfile = "test.xlsx"
if os.path.exists(xlfile):
    xls = xlrd.open_workbook(xlfile)
    sheet1 = xls.sheet_by_index(0)
    nrows = sheet1.nrows - 1
    ncols = sheet1.ncols
    data = np.zeros(ncols*nrows).reshape((nrows, ncols))
    date = []
    for r in range(1, nrows+1):
        for c in range(0, ncols):
            if c==0:
                d =  xlrd.xldate.xldate_as_datetime(sheet1.cell(r,c).value, xls.datemode)
                date.append(d)
            else:
                data[r-1,c] = sheet1.cell(r,c).value

    tokyo = data[:,1]
    kyoto = data[:,2]
    
    plt.plot(date, tokyo, label="Tokyo")
    plt.plot(date, kyoto, label="Kyoto")
    plt.legend()
    plt.show()
```

折れ線グラフを描くにあたって、X軸はExcelから読み込んだ日付を使いたい。Excelのファイル上で2016/07/01っていう日付が表示されている時は、データとしては”41090”という数値になっている。コレを見て7/1とは思えないので、変換する。それが、以下の行。

```python
d =  xlrd.xldate.xldate_as_datetime(sheet1.cell(r,c).value, xls.datemode)
```
これで、datetime型に変換され、”41090”は”2016-07-01 00:00:00”になる。なので、date=[]して初期化しておいたリストに、逐一date.append(d)しておく。

ところで、変数dをprint()するときは、d.strftime(“%m/%d”) とかすれば、7/1って、月/日だけ表示するようにもできる。できるんだけれど、そうやって変換した文字列をリストdateにappendすると、plt.plot()時にエラーが出ちゃうので、どうしたら良いんでしょうね。

というワケで、描けたグラフはこんな感じ。やっぱりX軸が読みづらい。なんとかしたいな。このグラフを見ると、検定するまでもなく京都の方が暑いことは分かる(すなわち、データの可視化は大事)。

![20160831003.png](https://qiita-image-store.s3.amazonaws.com/0/15553/402308b6-29f9-7db0-7d9e-27a6149b0777.png "20160831003.png")

## 今回のコードとデータ

- https://github.com/fukuit/Python_SelfLearning/blob/master/read_excel.py
- https://github.com/fukuit/Python_SelfLearning/blob/master/temperature.xlsx