Pythonで0からディシジョンツリーを作って理解する　（3. データ分析ライブラリPandas編）

**Pythonで0からディシジョンツリーを作って理解する**
[1.概要編](https://qiita.com/toyohisa/items/ab60d3eab11730f156da) - [2. Pythonプログラム基礎編](https://qiita.com/toyohisa/items/087ac1b03a187be2292f) - 3. データ分析ライブラリPandas編 - [4.データ構造編](https://qiita.com/toyohisa/items/de59b5f01b34f69e596d) - [5.情報エントロピー編](https://qiita.com/toyohisa/items/eb5bfd2e08e580d99690) - [6.ツリー生成編](https://qiita.com/toyohisa/items/cf38e4f815f4a7a03e09) - [(番外編) 離散化](https://qiita.com/toyohisa/items/4b8e6baf8a8a88783254)

ディシジョンツリーを作るためのPandasライブラリの使い方について説明いたします。

### 3.1 ライブラリのインポート
```python
# pamdasをインポートし、プログラム内では、pdという名前で使用すると宣言する。
import pandas as pd
```

### 3.2 DataFrame, Series
pandasでは、データフレーム(DataFrame)とシリーズ(Series)を使用します。次の図のようにExcelのテーブルのようにデータを行は1つのデータ、列はデータの項目（属性）としたとき、DataFrameはテーブル全体を表し、Seriesは1行分を表すことになります。

<img width="480" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275020/06ee06ca-f700-f001-46d9-fe712e55e7a7.png" />


### 3.3 DataFrameの生成

Excelファイルを読み込む。[read_excel](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_excel.html) [ExcelWriter](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.ExcelWriter.html)

```python
# Excelファイルは、このipynbファイルと同じ場所にアップロードしておく。
df0 = pd.read_excel("data_golf.xlsx")

# DataFrameをHTMLのtableとして表示する。
from IPython.display import HTML
html = "<div style='font-family:\"メイリオ\";'>"+df0.to_html()+"</div>"
HTML(html)


# Excelファイルへの保存 (withは、f.closeの処理を自動的に実行してくれるもの)
with pd.ExcelWriter("data_golf2.xlsx") as f:
    df0.to_excel(f)
```

辞書型(連想配列)から生成する方法：辞書型（連想配列）は、列でデータをまとめます。[DataFrame](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html)

```python
# 辞書型から生成：列でデータをまとめる。
d = {
    "天気":["晴","晴","曇","雨","雨","雨","曇","晴","晴","雨","晴","曇","曇","雨"],
    "温度":["暑","暑","暑","暖","涼","涼","涼","暖","涼","暖","暖","暖","暑","暖"],
    "湿度":["高","高","高","高","普通","普通","普通","高","普通","普通","普通","高","普通","高"],
    "風":["無","有","無","無","無","有","有","無","無","無","有","有","無","有"],
    "ゴルフ":["×","×","○","○","○","×","○","×","○","○","○","○","○","×"],
}
df0 = pd.DataFrame(d)
```

配列から生成する方法：行でデータをまとめます。[DataFrame](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html)

```python
# 配列から生成：行でデータをまとめる。
d = [["晴","暑","高","無","×"],
     ["晴","暑","高","有","×"],
     ["曇","暑","高","無","○"],
     ["雨","暖","高","無","○"],
     ["雨","涼","普通","無","○"],
     ["雨","涼","普通","有","×"],
     ["曇","涼","普通","有","○"],
     ["晴","暖","高","無","×"],
     ["晴","涼","普通","無","○"],
     ["雨","暖","普通","無","○"],
     ["晴","暖","普通","有","○"],
     ["曇","暖","高","有","○"],
     ["曇","暑","普通","無","○"],
     ["雨","暖","高","有","×"],
    ]
# 列名、行名をcolumns, index で指定できる。省略した場合には、通し番号が付く。
df0 = pd.DataFrame(d,columns=["天気","温度","湿度","風","ゴルフ"],index=range(len(d)))
```

### 3.4 テーブルの情報(行、列の名前、数)を取得
```python
# テーブルの情報(行、列の名前、数)を取得

# 行、列の数
print(df0.shape) # 出力 (14, 5)

# 行数の取得
print(df0.shape[0]) #出力 14

# 列名の取得
print(df0.columns) # 出力 Index(['天気', '温度', '湿度', '風', 'ゴルフ'], dtype='object')

# 行名の取得（df0の行名は、自動で割り振られたインデックスになっている）
print(df0.index) # 出力 RangeIndex(start=0, stop=14, step=1)
```

### 3.5 値の取得 [loc](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.loc.html#pandas.DataFrame.loc) [iloc](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.iloc.html#pandas.DataFrame.iloc) [values](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.values.html#pandas.DataFrame.values)
```python
# 値の取得

# 行と列を指定して値を取得する。
# 行番号1 (2個目のデータ), の湿度を取得する。
print(df0.loc[1,"湿度"]) # 出力 高

#　行と列を配列で複数指定して、値を取得する。
# 行番号1,2,4 の 天気とゴルフの値をまとめて取得、取得したデータもDataFrame型となる。
df = df0.loc[[1,2,4],["天気","ゴルフ"]]
print(df)
# 出力
#   天気 ゴルフ
# 1  晴   ×
# 2  曇   ○
# 4  雨   ○
print(type(df)) # 出力 <class 'pandas.core.frame.DataFrame'>

# 行と列の配列での指定には、スライス（配列を抜き出す処理）を利用することもできる。
# 1～4の行の、すべての列のデータを取得する。locは名前を指定するので、1:4とすると4を含みます。
df = df0.loc[1:4,:]
print(df)
# 出力
#   天気 温度  湿度  風 ゴルフ
# 1  晴  暑   高  有   ×
# 2  曇  暑   高  無   ○
# 3  雨  暖   高  無   ○
# 4  雨  涼  普通  無   ○

# iloc を使用すると、行、列をインデックスで指定できる。インデックスは、0から順に数える。
# 1～3の行の、最後の列（ゴルフ）以外のデータを取得する。ilocはインデックスを指定するので、1:4とすると4を含みません。
df = df0.iloc[1:4,:-1]
print(df)
# 出力
#   天気 温度 湿度  風
# 1  晴  暑  高  有
# 2  曇  暑  高  無
# 3  雨  暖  高  無

# 1行分 (Series) からの値の取得
# 最初の行のデータを取得する。sは、Series型
s = df0.iloc[0,:]
# 辞書型と同じように、s["列名"]で値を取得できる。
print(s["天気"]) # 出力 晴

# すべての値を配列(numpy.ndarray)の形式で取得する。
print(df0.values)
```

### 3.6 データのループ、順次データを見ていく [iterrows](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.iterrows.html) [iteritems](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.iteritems.html)

```python
# データのループ、順次データを見ていく。

# 行でループする。1行ごとデータを見ていく。
for i,row in df0.iterrows():
    # i は行名称（行のインデックス）、rowはSeries
    print(i,row)
    pass
    
# 列でループする。1列ごと、縦にデータを見ていく。
for i,col in df0.iteritems():
    # iは列の名称、colはSeries
    print(i,col)
    pass
```

### 3.7 度数 [value_counts](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.value_counts.html#pandas.Series.value_counts)
度数とは、例えば「晴、雨、雨、曇、晴」のデータにおける晴2、曇1、雨2といった各項目のデータがいくつあるかを示すものです。
```python
# 度数(データの出現個数)

# 天気の列の全データを取得する。sは、Series
s = df0.loc[:,"天気"]

# なんのデータが何個あるか、を取得する。
print(s.value_counts())
# 出力
# 晴    5
# 雨    5
# 曇    4
# Name: 天気, dtype: int64

# 例えば、晴の個数を取得する。
print(s.value_counts()["晴"]) # 出力 5
```

### 3.8 特定のデータの抽出 [query](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.query.html#pandas.DataFrame.query)
pythonの条件文のような文字列を与えてデータを抽出することもできます。
```python
# 特定データの抽出

# 天気が晴のデータの取得
print(df0.query("天気=='晴'"))
# 出力
#    天気 温度  湿度  風 ゴルフ
# 0   晴  暑   高  無   ×
# 1   晴  暑   高  有   ×
# 7   晴  暖   高  無   ×
# 8   晴  涼  普通  無   ○
# 10  晴  暖  普通  有   ○

# 天気が晴でゴルフに行くデータの取得
print(df0.query("天気=='晴' and ゴルフ=='○'"))
# 出力
#    天気 温度  湿度  風 ゴルフ
# 8   晴  涼  普通  無   ○
# 10  晴  暖  普通  有   ○

# 天気が晴、または、ゴルフに行くデータの取得
print(df0.query("天気=='晴' or ゴルフ=='○'"))
# 出力
#    天気 温度  湿度  風 ゴルフ
# 0   晴  暑   高  無   ×
# 1   晴  暑   高  有   ×
# 2   曇  暑   高  無   ○
# 3   雨  暖   高  無   ○
# 4   雨  涼  普通  無   ○
# 6   曇  涼  普通  有   ○
# 7   晴  暖   高  無   ×
# 8   晴  涼  普通  無   ○
# 9   雨  暖  普通  無   ○
# 10  晴  暖  普通  有   ○
# 11  曇  暖   高  有   ○
# 12  曇  暑  普通  無   ○

# lenによる抽出したデータの個数の取得
print(len(df0.query("天気=='晴' or ゴルフ=='○'")))
# 出力 12
```