Pythonを改めてちゃんと学ぶメモ #6

# はじめに
ここは、Pythonを改めて学んでいるメモを都度書き出していきます。
※ 筆者のバックグラウンドは#1をご覧ください。

1. https://qiita.com/hideh_hash_845/items/58241f0ce0283e457a87
1. https://qiita.com/hideh_hash_845/items/56c7a2c5594261f380b2
1. https://qiita.com/hideh_hash_845/items/b5e2264fc650c3e9d4b6
1. https://qiita.com/hideh_hash_845/items/6ebfcbf1682dcc696b76
1. https://qiita.com/hideh_hash_845/items/7b4aeb514f9eb199e9c2
1. ここ
1. https://qiita.com/hideh_hash_845/items/dbd43ab90284b396364b

# pandas

- 行・列の形式のデータを効率的に処理する機能を収録したライブラリ
- pandasをインポートする時は、慣例として`pd`という名前にする
~~~
import pandas as pd
~~~

## Series（シリーズ）型

- 一次元の配列のオブジェクト
- リストやarrayと同じように､配列とそれに紐付くindexが付与される
- Seriesやこの後出てくるDataFrameでは、`values`プロパティでデータ配列を取り出せる
- `if (obj >= 5)`のようなフィルタリングができる
- 欠損値が自動的に補完される機能はない

~~~
# リストからSeriesインスタンスを生成
obj1 = pd.Series([3,7,10,13])

# arrayからSeriesインスタンスを生成
numpy_array = np.array([3,7,10,13]) # Numpy配列を作成
obj2 = pd.Series(numpy_array) # NumPy配列を引数にとり、Seriesを作成

# indexを指定して要素を抽出
print(obj1[1]) # 7
print(obj2[1]) # 7
~~~

## DataFrame
- 辞書型（いわゆるキー：バリュー）だが、辞書の各要素であるリストはすべて同じ長さである必要がある。

~~~
# DataFrameを定義
# バリューが同じ長さの配列となっている辞書を引数にとる
df = pd.DataFrame(
    {'名前': ['山田', '鈴木', '佐藤', '田中', '斉藤', '高橋'], # 長さ: 6
     '年齢': [20, 34, 50, 12, 62, 22], # 長さ: 6
     '性別':['男', '男', '女', '男', '女', '女'] # 長さ: 6
    }
)
~~~

### `head()`, `tail()`
- 引数に行数を指定するとその行数だけ表示 `df.head(3)`
- 指定がない場合は先頭5行を出力

### `iloc[]`
- 特定の行のみを抽出
- 単に角括弧だと`Series`型, DataFrame型のまま抽出したいときは2重括弧
~~~
df.iloc[2]
df.iloc[[2]]
~~~

### `loc[]`
- 列の抽出。
- ilocメソッドやlocメソッドで行と列の両方を指定すれば､ 特定の要素ひとつを抽出することも可能｡
~~~
df.loc[:,'年齢']   # Series型
df.loc[:,['年齢']] # DataFrame型

# どちらも「鈴木」
df.iloc[1,0]
df.loc[1,'名前']
~~~

### `concat()`
- 要素の追加。
- 行の追加は`axis=0`, 列の追加は`axis=1`
~~~
# 追加したいDataFrameを定義
row = pd.DataFrame({'名前': ['渡辺'],
                    '年齢': [45],
                    '性別': '男'})
df_2 = pd.concat([df,row], axis=0)

# このままだとindex番号がおかしいのでindexを振り直す
# np.agrangeで0～6の数字が並んだ配列を生成
df_2.index = np.arange(len(df_2))
~~~

### `drop()`
- 削除。`axis`は上と同じ。
~~~
df_3 = df_2.drop(2, axis=0)
~~~

### `columns()`
- 列名の変更。`axis`は上と同じ。
~~~
df_4.columns = ['name', 'age', 'residence']
~~~

## サンプルコード

~~~python:pandas_test.py
#!/usr/bin/env python
# coding: utf-8

import numpy as np
import pandas as pd

# リストからSeriesインスタンスを生成
obj1 = pd.Series([3,7,10,13])

# arrayからSeriesインスタンスを生成
numpy_array = np.array([3,7,10,13]) # Numpy配列を作成
obj2 = pd.Series(numpy_array) # NumPy配列を引数にとり、Seriesを作成

# indexを指定して要素を抽出
print(obj1[1]) # 7
print(obj2[1]) # 7

# フィルタリング
# 要素が奇数か？
ary = (obj1 %2 == 1)

print (ary)

print (ary[0])
print (ary[1])
print (ary[2])
print (ary[3])

# 条件を満たす要素のみを抽出した配列を生成
new_ary = obj2[obj2%2==1]

print (new_ary)

print (new_ary[0])
print (new_ary[1])
#print (new_ary[2])  # [2]が詰められるわけではない点に注意！
print (new_ary[3])

print ('--------------------')


# DataFrameを定義
# バリューが同じ長さの配列となっている辞書を引数にとる
df = pd.DataFrame(
    {'名前': ['山田', '鈴木', '佐藤', '田中', '斉藤', '高橋'], # 長さ: 6
     '年齢': [20, 34, 50, 12, 62, 22], # 長さ: 6
     '性別':['男', '男', '女', '男', '女', '女'] # 長さ: 6
    }
)

# 引数に行数を指定するとその行数だけ表示
# 指定がない場合は先頭5行を出力
print(df.head(3))
print(df.head())

# 最後の5行を出力も同じ
print(df.tail())

# indexを指定することで､特定の行のみを抽出
# ただし、単に角括弧だとSeries型に変換されてしまう
# DataFrame型のまま抽出したいときは､括弧を2重にする
print(df.iloc[2])
print(df.iloc[[2]])

# 列の抽出
print(df.loc[:,'年齢'])     # Series型
print(df.loc[:,['年齢']])   # DataFrame型

# ilocメソッドやlocメソッドで行と列の両方を指定すれば､ 特定の要素ひとつを抽出することも可能｡
# どちらも「鈴木」
print(df.iloc[1,0])
print(df.loc[1,'名前'])

# 追加： concat
# 行の追加は axis=0, 列の追加は axis=1）

# 追加したいDataFrameを定義
row = pd.DataFrame({'名前': ['渡辺'],
                    '年齢': [45],
                    '性別': '男'})
df_2 = pd.concat([df,row], axis=0)
print(df_2)

# indexを変更
# np.agrangeで0～6の数字が並んだ配列を生成
df_2.index = np.arange(len(df_2))
print(df_2)

# 新たな列を代入
df_2['居住地'] = ['東京', '大阪', '北海道', '宮城', '富山', '大分', '沖縄']
print(df_2)

# 削除： drop
df_3 = df_2.drop(2, axis=0)
df_4 = df_2.drop('性別', axis=1)
print(df_3)
print(df_4)

# 列名の変更：columns
df_4.columns = ['name', 'age', 'residence']
print(df_4)
~~~