Data分析に使えるPython Library、Pandasについて調べてみた

# Pandasとは
データ構造を扱ったり、データ分析するのにとっても便利なPythonのLibraryです。

[公式サイト](https://pandas.pydata.org/pandas-docs/stable/index.html) 
> pandas is an open source, BSD-licensed library providing high-performance, easy-to-use data structures and data analysis tools for the Python programming language.

本記事では、このLibraryを使ってWebスクレーピングするって課題を非プログラマーが取り組んでたのを、
たまたま助ける機会があって軽く調べたので導入編ってことでデータの作り方を紹介します。

# データの種類
　データには以下の２種類が大きくわけてありそうです。
## シリーズ(Series)
Seriesは1列のみのデータ型。エクセルの一列だけあるような感じ。

## データフレーム(DataFrame)
データフレームは2次元のラベル付きのデータ構造。エクセルや表のテーブル形式なデータを扱うイメージ。
本資記事では主にデータフレームメインで書きます。

# 使い方
## 基本
- columnsで行名を設定できる
    - 指定しない場合は、１列目を0(zero)として連番が振られる
- indexで列名を設定できる
    - 指定しない場合は、１行目を0(zero)として連番が振られる

## 多次元List(配列)型データからデータ作成
list '[]' の list '[]'で、1行ごとのデータをリストしてデータを作ることができる

```python
import pandas as pd

list1 = ['a','b','c']
list2 = ['d','e','f']
data = [list1, list2] # [ ['a','b','c'], ['d','e','f'] ]
df = pd.DataFrame(data, columns=['A','B','C'])
'''
df:
   A  B  C
0  a  b  c
1  d  e  f
'''
```

## Dict(辞書)型データからデータ生成
dict '{"key":"value"}' のKeyに列名、Valueにその列のデータリストを設定してデータを作ることができる

```python
import pandas as pd

list1 = ['a0','a1','a2']
list2 = ['b0','b1','b2']
data = {"A":list1, "B": list2} # { "A": ['a0','a1','a2'], "B": ['b0','b1','b2'] }
df = pd.DataFrame(data)
'''
df:
    A   B
0  a0  b0
1  a1  b1
2  a2  b2
'''
```

## 行や列を追加
### 行の追加
locコマンドを使って追加
locコマンド自体は、行と列を指定して要素を抜き出すコマンドだが、
行ラベルで指定した行に値を設定することで、指定した行がなければ値を追加、存在していれば上書きとなる

```python
import pandas as pd

data = [['a0', 'b0'], ['a1', 'b1']]
df = pd.DataFrame(data, columns=['A','B'])
'''
df:
    A   B
0  a0  b0
1  a1  b1
'''

df.loc['4'] = 2 # 行名が'4'の行に2の値を設定('4'行がないので行追加)

'''
df:
    A   B
0  a0  b0
1  a1  b1
4   2   2
'''
```
値にListを指定すると対象の行に左から順にその値が設定される
(列の数とListの要素数、つまり値の数が一致しないとエラーになるので注意)

```python
df.loc['X'] = ['AX', 'BX'] # 行名が'X'の行に3の値を設定('X'行がないので行追加)
'''
    A   B
0  a0  b0
1  a1  b1
4   2   2
X  AX  BX
'''
```
ちなみにlocコマンドは列の追加にも使える

```python
df.loc[:,'C'] = 'c' # ('C'列がないので列追加)
'''
    A   B   C
0  a0  b0   c
1  a1  b1   c
4   2   2   c
X  AX  BX   c
'''
```
値にSeriesも指定できる
その際、Seriesのindex(行ラベル)が列ラベルとして扱われ、
Seriesの情報に、対応する列ラベルがない列には欠損値(NaN)が入り、
DataFrameに存在しない列ラベルのSeriesの情報は無視される。

```python
s = pd.Series(['b4', 'c4', 'd4'], index=['B', 'C', 'D'])
df.loc['Y'] = s
'''
s:
B    b4
C    c4
dtype: object

df:
     A   B   C
0   a0  b0   c
1   a1  b1   c
4    2   2   c
X   AX  BX   c
Y  NaN  b4  c4
'''
```
appendコマンドを使っても可能

```python
data1 = [['a0', 'b0'], ['a1', 'b1']]
data2 = [['a2', 'b2'], ['a3', 'b3']]
df1 = pd.DataFrame(data1, columns=['A','B'])
df2 = pd.DataFrame(data2, columns=['A','B'])
df3 = df1.append(df2,  ignore_index=True) #行ラベルを無視して結合 => df1のIndexに沿ってdf2の値が追加される
'''
df1:
    A   B
0  a0  b0
1  a1  b1

df2:
    A   B
0  a2  b2
1  a3  b3

df3:
    A   B
0  a0  b0
1  a1  b1
2  a2  b2
3  a3  b3
'''
```
`ignore_index=False` にすると、行ラベルを無視せずに結合 => df2のIndexの値のままdf2の値が追加される

```python
df4 = df1.append(df2,  ignore_index=False)
'''
df4:
    A   B
0  a0  b0
1  a1  b1
0  a2  b2
1  a3  b3
'''
```
appendされる側に存在しない列の情報を含んでいる場合、
列が追加されて元のデータの行には欠損値(NaN)が設定され、(C0, C1)
appendする情報に、appendされる側の列に対応する情報がない場合も欠損値(NaN)で補った上で行が追加される(A2)

```python
df5 = pd.DataFrame([['b4','c4']], columns=['B','C'])
df6 = df1.append(df5,  ignore_index=True)
'''
df6:
     A   B    C
0   a0  b0  NaN
1   a1  b1  NaN
2  NaN  b4   c4
'''
```

### 列の追加
dict型に値を追加するように( `dict["key"] = "value"` )、存在しない列名をKeyに値を設定すると、
その列名で列が追加され、各行に指定した値が設定される。値にはいろんなものを指定できる

- スカラー
- List
- Series

```python
import pandas as pd

data = [['a0', 'b0'], ['a1', 'b1']]
df = pd.DataFrame(data, columns=['A','B'])
'''
df:
    A   B
0  a0  b0
1  a1  b1
'''
```

値にスカラー(単一の値)を指定すると、全行にその値が設定される

```python
df['C'] = 'c'
'''
df:
    A   B  C
0  a0  b0  c
1  a1  b1  c
'''
```

値にListを指定すると上の行から順にその値が設定される
(行の数とListの要素数、つまり値の数が一致しないとエラーになるので注意)

```python
df['D'] = ['d0', 'd1']
''' 
df:
    A   B  C   D
0  a0  b0  c  d0
1  a1  b1  c  d1
'''
```
値にSeriesを指定することもできる。 
元のDataFrameのindexに対応する値がなかった場合は欠損値のNaNが入り、
元のDataFrameのindexにないindexの値は無視される

```python
s = pd.Series(['e1', 'e2'], index=[1, 2])
df['E'] = s

''' 
df:
    A   B  C   D    E
0  a0  b0  c  d0  NaN
1  a1  b1  c  d1   e1
'''
```

assignコマンドでも同様のことが可能

```python
df.assign(F='f')
''' 
df:
    A   B  C   D    E  F
0  a0  b0  c  d0  NaN  f
1  a1  b1  c  d1   e1  f
'''
```
insertコマンドを使うと任意の位置に列追加可能

```python
df.insert(0,'X','x') # 左から数えて1番目(1つ目は0)の列に、'X'という列名の列を追加し、値にxを入れる
'''
   X   A   B  C   D    E  F
0  x  a0  b0  c  d0  NaN  f
1  x  a1  b1  c  d1   e1  f
'''
```

## DataFrame/Series同士を結合
`pandas.concat()` 関数を使えばDataFrame同士、Series同士、DataFrameとSeriesのデータを結合することができる

- axisで結合の方向（並べ方）を指定できる
    - 0(index)で縦方向に並べる - 指定しなければこっちになる
    - 1(columns)で横方向に並べる

```python
import pandas as pd

s1 = pd.Series(['a0','a1','a2'])
'''
s1:
0    a0
1    a1
2    a2
dtype: object
'''
s2 = pd.Series(['b0','b1','b2'])
'''
s2:
0    b0
1    b1
2    b2
dtype: object
'''
df1 = pd.concat([s1,s2], axis=1)
''' s1とs2を横並びに結合
df1:
    0   1
0  a0  b0
1  a1  b1
2  a2  b2
'''
df2 = pd.DataFrame([['a3','b3']], index=[3])
'''
df2:
    0   1
3  a3  b3
'''
df3 = pd.concat([d1,d2])
''' d1とd2を縦並びに結合
df3:
    0   1
0  a0  b0
1  a1  b1
2  a2  b2
3  a3  b3
'''
```

## 表計算
### 列の値と列の値を結合して別の列に入れる
Excelでいう、 `=A0&" "&B0` てきなやつ

```python
import pandas as pd

data = [['Bob', 'Dylan'], ['Paul', 'Mccartney']]
df = pd.DataFrame(data, columns=['First','Last'])
'''
df:
  First       Last
0   Bob      Dylan
1  Paul  Mccartney
'''

d['Full Name'] = d['First'] + ' ' + d['Last']
'''
df:
  First       Last       Full Name
0   Bob      Dylan       Bob Dylan
1  Paul  Mccartney  Paul Mccartney
'''
```

# 総評
今回はまずデータを作ったり、行列を増やすことにフォーカスして調べましたが、
値を合成したり掛け合わせたりCSV出力してみたりと、計算や分析するためのLibraryなので、
ここから様々なコマンドを駆使して、データを分析していくことになるわけですね。
奥がとっても深そうでした。
分析していくコマンドについてはこの辺の記事を見てみたり検索してみるといいと思います。

https://qiita.com/ysdyt/items/9ccca82fc5b504e7913a


# Reference(参考文献)
https://note.nkmk.me/pandas/
https://utokyo-ipp.github.io/7/7-1.html
http://ailaby.com/lox_iloc_ix/
https://ai-inter1.com/pandas-dataframe_union/