【Python】Pandasの基本まとめ（初心者向け）

#はじめに
Pythonのライブラリの１つである**Pandas**について初心者でも超わかりやすくまとめてみました。


#本記事の内容

- 1.Pandasとは
- 2.SeriesとDataFrameについて
- 3.ファイルの読み込み・書き出し
- 4.データセットからDataFrameを作成
- 5.データの参照
- 6.ソート（並び替え）
- 7.DataFrameの列の追加

※順番に意味はなし

#参考教材

- 産婦人科医とみーさんのブログ「Tommy blog」

リンク→[Python入門者のための学習ロードマップ【ブログでも独学可能】](https://obgynai.com/python-roadmap/)

- AI Academyさんのテキスト教材

リンク→[AI Academy](https://aiacademy.jp/goals/)

どちらもめっちゃわかりやすくオススメです。

#環境
Python 3.7.6
Jupyter Notebook 6.0.3

#1.Pandasとは
![https___qiita-image-store.s3.amazonaws.com_0_100780_ff5f5d02-6967-1e1c-7823-5dfa73927a2e.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/ac123b1d-1cb3-6092-b73a-fc24241468d6.jpeg)

Pandas（パンダス）はPythonのデータ整形用ライブラリの１つです。

>pandasは、プログラミング言語Pythonにおいて、データ解析を支援する機能を提供するライブラリである。
出典：Wikipedia

機械学習をする上で必須となるデータの解析や加工を行うことがライブラリです。
表形式のデータをSQL、Rのように操作することが可能で、かつ高速に処理可能。

Pandasでできること＆よく使う機能を噛み砕いて書くとすると、

- CSV等のファイルの読み込み、書き出し
- 列・行の追加や削除
- データの抽出
- 欠損値（NaN）の補完（他の数字で置換する）
- データの結合

あたりだと感じてます。

上記の機能をまとめると**「データの前処理」**ですかね。
（データの整形、とも言うのかな？）

#2.SeriesとDataFrameについて
Pandasの使ってデータを整形していく上での基本的なデータ構造。

- Series：１次元配列データ
- DataFrame：２次元配列データ

##2-1.Seriesの作成

```python:series.py
import pandas as pd

s = pd.Series([1, 11, 111, 1111])
print(s)

#出力
#左の列は行ラベル（インデックス）指定しなければ0からの連番になる
#右の列はSeriesのデータ
0 1
1 11
2 111
3 1111
```

参考：[Pandasの基本的なデータ構造Seriesの基礎と活用方法](https://deepage.net/features/pandas-series.html#series%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AE%E7%94%9F%E6%88%90)


##2-2.DataFrameの作成

```python:dataframe.py
import pandas as pd

df = pd.DataFrame（[
    [1, 11, 111],
    [2, 22, 222],
    [3, 33, 333],
    [4, 44, 444]
])
print(df)

#出力
  0  1   2
0 1 11 111
1 2 22 222
2 3 33 333
3 4 44 444
```

指定しない場合、１番左の列=インデックス（index）と１番上の行=カラム(columns）が自動で0からの連番が割り振られます。

インデックスとカラムを指定したDataFrameの作成

```python:dataframe2.py
import pandas as pd

#indexとcolumnsはリスト型で定義する
index = [2017, 2018, 2019, 2020]
columns = ["部員数", "マネージャー数", "成績",]

#dataもリスト型で定義する
data = [
    [30, 2, "１回戦負け"],
    [35, 0, "3回戦負け"],
    [50, 1, "準優勝"],
    [70, 5, "優勝"]
]

df = pd.DataFrame(data=data, index=index, columns=columns)
print(df)

#出力
      部員数  マネージャー数     成績
2017   30        2  １回戦負け
2018   35        0  3回戦負け
2019   50        1    準優勝
2020   70        5     優勝
```

作成されたDataFrameを表形式で表すと以下の通り。
2017〜2020がインデックス（index）、
部員数〜成績がカラム(columns)です。

||部員数|マネージャー数|成績|
|--:|--:|--:|--:|
| 2017 | 30 | 2 | １回戦負け |
| 2018 | 35 | 0 | 3回戦負け |
| 2019 | 50 | 1 | 準優勝 |
| 2020 | 70 | 5 |優勝|

DataFrameの作成方法について詳しく学びたい方は以下のリンクから飛んでください。

参考：[【Python】pandas.DataFrameの概要と作成方法・変換方法](https://obgynai.com/python-pandas-dataframe-index-columns-data/)
参考：[Pandasのデータを格納するオブジェクトDataFrameを理解する](https://deepage.net/features/pandas-dataframe.html#%E5%AE%9F%E9%9A%9B%E3%81%AB%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B)


##2-3.SeriesとDataFrameまとめ
SeriesとDataFrameとは

|データ型|概要|
|:--:|:--:|
|Series（シリーズ）|１次元配列データ|
|DataFrame（データフレーム）|２次元配列データ|

作成方法

```python:create_series.py
pd.Series(data, index)
```
```python:create_dataframe.py
pd.DataFrame(data, index, columns)
```

#3.ファイルの読み込み・書き出し
Pandasでかなり使用頻度の高い機能です。

##3-1.読み込み
読み込みは以下のコードで行う。
（読み込みたいファイルが、コードを書くファイルと同階層に存在する場合はファイルパスの記載は不要なのでファイル名の記載のみでOK）

    pd.read_ファイル形式("ファイルのパス/ファイル名"）

##3-2.CSVファイルを読み込む場合
（読み込むCSVファイル（sample.csv)はJupyter Notebookと同じ階層とする）

```python:read_csv.py
import pandas as pd

#CSVファイルを読み込む
#encoding="cp932"がないと文字化けすることがある
data = pd.read_csv("sample.csv", encoding="cp932")

print(type(data))

#出力
#CSVファイルを読み込むとDataFrame型になっている
<class 'pandas.core.frame.DataFrame'>

```

読み込めるファイル形式はCSVだけでなく、Excel等も可能

参考：[【Python】pandasでCSV/TSVファイルを読み込む方法](https://obgynai.com/python-pandas-csv-tsv/)
参考：[pandasでcsv/tsvファイル読み込み（read_csv, read_table）](https://note.nkmk.me/python-pandas-read-csv-tsv/)


##3-3.書き出し
書き出しは以下のコードで行う。
（書き出したファイルをコードを書いているコードと同階層に保存する場合はファイルパスの記載は不要なのでファイル名のみでOK）

    df.to_ファイル形式("ファイルのパス/ファイル名"）

dfは定義する時に`pd.DataFrame`をしているので`df.pd.to_ファイル形式`にしなくてOKです。
※これはDataFrame型のデータを格納した変数に関してはどのメソッド（関数）でも同じです。

##3-4.CSVファイルを書き出す場合
（Jupyter Notebookと同じ階層に書き出すことにする）

```python:to_csv.py
import pandas as pd

#書き出すDataFrameを定義
index = [2017, 2018, 2019, 2020]
columns = ["部員数", "マネージャー数", "成績",]

data = [
    [30, 2, "１回戦負け"],
    [35, 0, "3回戦負け"],
    [50, 1, "準優勝"],
    [70, 5, "優勝"]
]

df = pd.DataFrame(data=data, index=index, columns=columns)

#CSVファイルを書き出す
#encoding="cp932"がないと文字化けすることがある（今回はしました）
df.to_csv("sample.csv", encoding="cp932")
```

上記コードを実行するとsample.csvが生成されます。
<img width="422" alt="スクリーンショット 2020-05-09 16.41.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/693291ee-386f-fd2d-582d-f62e104a4cc5.png">

Jupter Notebook上でCSVファイルを開くとこんな感じです。
<img width="352" alt="スクリーンショット 2020-05-09 16.53.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/023a28e0-bdd3-9062-7ad8-78b84423e22e.png">

csvファイルをExcelで実際に開いて確認するとしっかり確認できています。
encoding="cp932"がない状態で書き出ししてみると文字化けしてました。
（ぜひご自分で試してみてください）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/3bb36800-3a7b-904a-9321-edf09610e482.png)


書き出す時に
インデックス（１番左の列）を表示しない場合は

    df.read_csv("sample.csv", index=False)

カラム（１番上の行）を表示しない場合は

    df.read_csv("sample.csv", header=False)

インデックス、カラムどちらも表示しない場合は

    df.read_csv("sample", index=False, header=False)

※デフォルトはTrueなので何も指定しなければインデックスとカラムは表示されます

参考：[【Python】pandasでCSV/TSVファイルを読み込む方法](https://obgynai.com/python-pandas-csv-tsv/)
参考：[pandasでcsvファイルの書き出し・追記（to_csv）](https://note.nkmk.me/python-pandas-to-csv/)

##3-5.ファイルの読み込み・書き込みまとめ
|用途|書き方|注意点|
|:--|:--|:--|
|CSVファイルを読み込む|df.read_csv("ファイルパス/ファイル名")|encoding="pc932"を記載しないと文字化けする可能性がある|
|CSVファイルに書き出す|df.to_csv("ファイルパス/ファイル名")|encoding="pc932"を記載しないと文字化けする可能性がある|
※扱えるファイル形式はCSVだけではない。


#4.データセットからDataFrameの準備
これまでDataFrameは適当な数字で作りましたが、これ以降は**Scikit-learn**という機械学習用ライブラリに用意されている**iris**というデータセットを使ってみます。
（後述するが**Seaborn**でも呼び出し可能）

irisとはアヤメという花の名前で、その花の情報がまとめられています。

Scikit-learnにはirisの他にも以下の通りすぐに機械学習やデータ分析に使えるデータが準備されています。

- boston（ボストン市の住宅価格データ)
- diabetes（糖尿病患者の診療データ）
- digits（数字の手書き文字データ）
- linnerrud（生理学的特徴と運動能力の関係についてのデータ）
- wine（ワインの品質データ）
- breast_cancer(乳がんデータ)

上記のirisを含むデータセットの説明と読み込み方はこちら
[scikit-learnに付いてくるデータセット7種類を全部まとめてみた](https://yolo.love/scikit-learn/datasets/#Iris_plants_dataset)


まず、DataFrameを作成します。

##4-1.irisデータセットの読み込み

```python:
from sklearn.datasets import load_iris

# irisデータセットをirisに格納
iris = load_iris()
```


##4-2.読み込んだirisデータセットをDataFrameに変換して表示

```python
from sklearn.datasets import load_iris
import pandas as pd

# irisデータセットをirisに格納
iris = load_iris()

# irisデータセットをDataFrameに変換
df = pd.DataFrame(iris.data, columns=iris.feature_names)

df
```
実行すると、以下の表が表示されます。

<img width="498" alt="スクリーンショット 2020-05-16 21.28.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/233cd0e1-8738-aef0-e214-e0ff87e439c4.png">

Jupiter Notebookの良いところはDataFrame自体を打ち込んで実行すると綺麗な表形式で表示してくれるところですね。

    print(df)

を実行してみると違いがわかります。

ここで、以下の式について軽く説明しておきます。

```python
# irisデータセットをDataFrameに変換
df = pd.DataFrame(iris.data, columns=iris.feature_names)
```

irisデータセットにはdataオブジェクトとtargetオブジェクトがあり、

[Scikit-learnの公式ドキュメント](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_iris.html#sklearn.datasets.load_iris)を見ると、

>data:{ndarray, dataframe} of shape (150, 4)
The data matrix. If as_frame=True, data will be a pandas DataFrame.

>target: {ndarray, Series} of shape (150,)
The classification target. If as_frame=True, target will be a pandas Series.

と書かれており、

`iris.data`・・・行列データ（分類するための情報）=**説明変数**
`iris.target`・・・分類対象=**目的変数**

と書くことでそれぞれの情報を取得することができます。


カラム名の指定（`columns=iris.feature_names`)についてですが、

先ほど同様、[Scikit-learnの公式ドキュメント](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_iris.html#sklearn.datasets.load_iris)に、

>feature_names: list
The names of the dataset columns.

と書かれており、カラム名は`iris.feature_name`で取得することができます。

以上で、DataFrameを作成し、Pandasのメソッドを使う準備ができました。

##4-3.irisデータセットからDataFrameの準備（その2）
Pythonのデータ可視化用ライブラリである`Seaborn`を使ってもirisデータセットを読み込むことができます。

以下のコードを実行することでirisデータセットを読み込むことができます。
Serbornはなぜかsnsという別名をつけるのが一般的です

```python
import seaborn as sns

iris = sns.load_dataset("iris")

iris
```
<img width="498" alt="スクリーンショット 2020-05-17 12.59.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/5233910a-675a-f9f7-b9e1-78f115a6f072.png">

Serbornでirisデータセットを読み込んだ場合、DataFrame型として読み込まれるので、
Scikit-learnで読み込んだ時のようにデータ型の変換は不要です。

その証拠に`iris.head()`でDataFrameの先頭から５つのデータを読み込むことができます。

<img width="440" alt="スクリーンショット 2020-05-17 13.06.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/a0cf7ebb-a914-a959-4e08-4ce428d68399.png">

以降は**Seaborn**を使って作成したDataFrameである**iris**を使います。

#5.データの参照
データの参照はPandasの中でも重要な機能です。

以下のことを指します。

- データ情報の取得
- データの先頭、最後尾を数行表示
- データの中の一部を抽出

##5-1.データの情報を取得
データの情報を取得するには以下のように記述。
情報なので`info`、そのままですね。

    iris.info()

ちなみにPandasが用意しているので`pd.info()`じゃないの？
と思われた方もいるかもしれませんが、DataFrame型のデータの場合、pandas.DataFrameなのでPandasが既に適用されているので不要です。

（`pd.DataFrame.pd.info()`になってしまう）

出力結果
<img width="303" alt="スクリーンショット 2020-05-26 19.49.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/4374ba31-8928-bcd3-dd63-974fffebf2d3.png">

上の出力結果からざっくりわかることは以下の通り

- データの型がDataFrame型
- 行数が150つで、0から149ある
- 列数が５つ
- データの型、列名

そのDataFrameの全体的な情報を観見たい時に使います。

##5-2.行数、列数の取得

```python
#行数の取得
len(iris)

#出力結果
150


#列数の取得
len(iris.columns)

#出力結果
5
```
データの数を取得するには`len`を使います。（lengthのlen）
行数と列数をかければセルの数がわかります。
(150×5=750）

##5-1.列名、行名の取得

列名、行名を取得するためには以下のコードを記述します。
（dfはDataFrame型のデータとします）

|書き方|意味|
|:--|:--|
|df.columns|列名を取得|
|df.index|行名を取得|

実際にirisデータセットから作成したDataFrame（iris）で試します。

```python
#列名を取得
iris.columns

#出力結果
Index(['sepal_length', 'sepal_width', 'petal_length','petal_width','species'],dtype='object')


#行名を取得
iris.index

#出力結果
#行名は0から150まで１ずつ割り振られていることがわかる
RangeIndex(start=0, stop=150, step=1)

```
##5-2.列のみを指定して取得
ここからは実際にDataFrameのデータの一部を抽出していく操作です。

列のみを指定する場合は以下の通り記述します。

```python
#１列のデータを取得する
df.["列名"]

#複数列のデータを取得する
#リストで渡す
df.[["列名1", "列名2", "列名3"]]
```

実際にirisで試してみると

    iris.["sepal_length"]

出力結果

![スクリーンショット 2020-05-26 20.15.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/eeba5b67-d253-35d4-07e1-119f8b8d0aa2.png)

となります。

出力結果からもわかるように１列のみの取得の場合、取り出したデータの型は**Series**になります。

実際に

    type(iris.["sepal_length"])

を実行してみるとわかります。

複数列を取得してみると

    iris.[["sepal_length", "sepal_width"]]

出力結果

![スクリーンショット 2020-05-26 20.15.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/f47b6b45-2fc7-edf5-73ff-88fad7f0faaa.png)

こちらは２列以なのでDataFrame型です。

Jupyter Notebookだと`type()`を使わなくてもビジュアルでSeriesとDataFrameがわかりますね。


---
ちなみに、列名が設定されてない場合は、列に０からの数字が割り振られているので以下の記述で取得可能。

    df[番号]

例えば以下のようなDataFrameとすると、
![スクリーンショット 2020-05-26 20.28.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/c71bbe92-8ad8-a1a3-5291-3b1b8d76cb21.png)

    df[1]

を実行すると、以下の通り左から2列目のデータを取得できます。

![スクリーンショット 2020-05-26 20.28.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/1007b6af-3b65-9f8b-67b6-16ce37d8b0ac.png)

ですが、実際にデータ分析をするデータには列名が設定されているので列番号による取得を使う機会は少ないと思います。

---


##5-3.行のみを指定して取得
行を指定してデータを取得する場合は以下の通り記述します。

　　　　df[ここから:ここまで]

**ここから**と**ここまで**には行に0から割り振られた数字が入ります。
（１番上が0行目で1、2、3・・・と下にいく）

つまり、

    df[2:6]

は**2行目から5行目まで**となります。（※ここまで、の番号は入らない）

では実際にirisで試してみます。

    iris[2:6]

出力結果
![スクリーンショット 2020-05-26 20.45.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/b1f04751-7dd3-6e6a-8e43-1edb4ae79747.png)

ちなみに１行だけ取得する場合はこのように記述します。
（４行目だけ取得）

    df[4:5]

出力結果
![スクリーンショット 2020-05-26 20.46.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/c7ae441c-e9a0-d46e-5746-52a28635a5c2.png)

ちなみに

    df[4:4]

こう書いてしまうと、以下の通りヘッダーだけが表示されますのでご注意ください。
![スクリーンショット 2020-05-26 20.48.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/3311b6a8-8a50-2e1c-89af-f417ff4c9c18.png)

##5-4.行と列を組み合わせて取得（行のみ取得も可能）

行と列を組み合わせて取得するにはloc[]、iloc[],query()等を使います。

###5-4-1.loc[]での抽出
loc[]の使い方は以下の通り

    df.loc[行, 列]

loc[]の引数には**ラベル名（index名、columns名）**を渡す必要があります。

行に関しては名前が設定されていない場合も多いので0からの連番で指定することが多いです。

```python:loc1.py
#2行目、sepal_length列を取得する
iris.loc[2, "sepal_length"]

#出力結果
4.7

#どちらも絶対座標（行名、列名を指定していない時に割り振られる順番）を指定するとエラーになる
print(df.loc[1, 2])

#出力はエラーメッセージになります
```

複数の行と列を指定する方法は以下の通りです。

    df.loc[開始行：終了行,　開始列：終了列]

```python:loc2.py
iris.iloc[2:6, "sepal_length":"sepal_width"]
```

上のコードで取得できるデータは以下の通り

- ２行目から６行目
- sepal_length列からsepal_width列まで

出力結果
![スクリーンショット 2020-05-26 21.15.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/f1dbcaba-018f-84f9-8c93-45d35e54201a.png)

loc[]を使った場合は**終了行**、**終了列**のデータも含まれることがわかります。

###5-4-2.iloc[]での抽出   
iloc[]の使い方は以下の通り

    df.iloc[開始行番号, 終了列番号]

iloc[]の引数には番号を渡す必要があります。
※loc[]の時のようにラベル名（index名、columns名）だとエラーになりますので注意

```python:iloc.py
#４行目、３列目を取得する
iris.iloc[3, 2]

#出力結果
1.5

#ラベル名（index名、columns名)を指定するとエラーになる
iris.iloc[2018, "petal_length"]

#出力はエラーメッセージになります
```

列は省略して行のみを指定することも可能。

````python:iloc2.py
#10行目を取得（列は省略可能）
iris.iloc[10]
````

出力結果
![スクリーンショット 2020-05-26 21.38.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/c46884ea-9ffd-aa1b-0c3e-120c0bebeb97.png)

1行のみを取得した場合は**Series**型になります。

データの抽出では特定の範囲を指定することが可能。

    iris.iloc[0:3, 0:2]



上記コードは

- 行：0〜2行目
- 列：0〜１列目

のデータを抽出するという意味になります。
**:**は**〜**と同じ使い方をします。

loc[]と違い、A:Bで指定した**Bは抽出対象に含まれない**ことに注意です。


出力結果
![スクリーンショット 2020-05-26 21.32.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/a40aad1c-2366-5466-d2a9-937ff45e8a28.png)


ではこちらは。

    iris.iloc[:, :]

上記の場合は

- 行：全行
- 列：全列

のデータを抽出するので元々のデータフレームが返されます。

ではではこちら

    iris.iloc[60:, :2]

上記の場合は

- 行：60行目〜最終行までの行
- 列：０列目〜1列目までの列

のデータを抽出することができます。

出力結果
![スクリーンショット 2020-05-26 21.34.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/3d784ede-c370-b622-9eb8-2b3f650130aa.png)


iloc[]の使う方をまとめると以下の表の通りになります。

|[]の中|意味|
|:--:|:--|
|[4]|4行目（列は省略）|
|[:10]|0〜9行目（列は省略）|
|[3:9]|３〜８行目|
|[2:4, 4:6]|2〜3行目、4〜6列目|
|[:, 4]|全行、４列目|
|[2, :]|２行目、全列|
|[:, :]|全行、全列（元のDataFrameが返る）|
|[1:, :5]|１〜最終行、0〜４列目|

上表の意味はすぐわかるようにしっかり抑えておきましょう。

参考：[Pandasで要素を抽出する方法(loc,iloc,iat,atの使い方)](https://deepage.net/features/pandas-location.html)

###5-4-3.query()での抽出（条件付加）
条件に応じてデータを抽出したいときはquery()と使う。

query()の使い方は以下の通り

    df.query("条件")

```python:query1.py
#sepal_width列の値が3.5より大きく、4以下の行を取得
iris.query("3.5 < sepal_width <= 4")
```

出力結果
![スクリーンショット 2020-05-26 22.00.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/b1fc933b-b972-5a86-307d-633cbb1a6917.png)


```python:query2.py
#species列がvirginicaのもの
#そのまま出力すると数が多いのでhead()で先頭５行だけ表示
iris.query("species == 'virginica' ").head()
```
![スクリーンショット 2020-05-27 20.58.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/bbadb441-d855-e0df-f740-fe551c135588.png)

query()でデータを取得する場合、()の中の条件にはクオーテーション(' or ")を付けなければエラーになります。

以下、参考までに。

```python:query3.py
#条件にクオーテーションを付けないとエラーになる
iris.query(species == 'virginica' ).head()

#出力結果
NameError: name 'species' is not defined
```
エラーメッセージが表示されます。

では、最後にこちら。

```python:query4.py
#species列にsetocaとvirginicaがないもの
#そのまま出力すると数が多いのでhead()で先頭５行だけ表示
iris.query(" species not in ['setosa', 'virginica']").head()
```

下の画像のように**versicolor**のデータのみが取得できます。

![スクリーンショット 2020-05-27 21.05.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/b138a819-1ee3-8eb0-2e9e-a85344c5321c.png)

参考：[pandas.DataFrameの行を条件で抽出するquery](https://note.nkmk.me/python-pandas-query/)

##5-4.データの抽出まとめ

|用途|使い方|注意点|
|:--|:--|:--|
|行名、列名を指定|loc[行,列]]|終了行、終了列のデータも含む|
|行番号、列番号を指定|iloc[行,列]|終了行、終了列のデータは含まない|
|条件を指定|query("条件")||

データの抽出の詳しい内容は以下のリンクから飛んでください。
参考：[pandasのdataframeの要素の参照方法をマスターしよう](https://obgynai.com/python-pandas-dataframe-referance/)



#6.ソート（並び替え）
Pandasを使うと、要素をソート（並び替え）することができます。

ソートではScikit-learnのirisデータセットから作成したDataFrameである**df**を使用していきます。

（理由は特にないので、これまで通りSeabornのirisデータセットから作成したDataFrameである**iris**を使っても全く問題ないですし、結果も同じです）

ソートする前にもう一度、dfを表示させておきます。

こちらを色々な方法でソートします。
<img width="498" alt="スクリーンショット 2020-05-16 21.28.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/513967e2-ad0b-71bf-a63e-e29a8c9e573f.png">

##6-1.要素でソート
**要素でソート＝特定のカラム（複数選択可）にある要素をソート**

###6-1-1.１列目の`sepal length (cm)`の要素をソート（昇順）

```python
df.sort_values('sepal length (cm)')

# 注意点：lengthと(cm)の間に半角スペースを入れないとエラーになる
# 'でも"でもどちらでもOK
```

下の画像のように`sepal length(cm)`列の要素が4.3→7.9のように並び替えられました。
（列名がバラバラになっている）
<img width="498" alt="スクリーンショット 2020-05-17 0.10.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/6ad09968-ad02-d5b7-cd97-78f89d88dae0.png">

デフォルトでは昇順にソートされるので、降順でソートするためには第２引数に`ascending=False`をつける。

ちなみに昇順、降順は以下の意味です。

- 昇順：小→大
- 降順：大→小

###6-1-2.１列目の`sepal length (cm)`の要素をソート（降順）

```python
df.sort_values('sepal length (cm)', ascending=False)

# 注意点：lengthと(cm)の間に半角スペースを入れないとエラーになる
# 'でも"でもどちらでもOK
```
下の画像のように`sepal length(cm)`列の要素が7.9→4.3のように並び替えられました。
（列名がバラバラになっている）
<img width="498" alt="スクリーンショット 2020-05-17 0.19.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/813f69b7-fe24-cd4c-0bf2-01ca3e792209.png">

デフォルトでは昇順でソートされますが、第２引数に`ascending=True`をつけてもOK。

###6-1-3.３列目（petal lenght (cm))と４列目（petal width (cm))でソート（複数列指定）

複数列の要素を同時にソートする場合は引数にリストで指定する。

```python
# リストで指定する
df.sort_values(['petal length (cm)', 'petal width (cm)'])

# 注意点：length（width)と(cm)の間に半角スペースを入れないとエラーになる
# 'でも"でもどちらでもOK
```
<img width="498" alt="スクリーンショット 2020-05-17 0.29.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/39784ce9-7b0c-b2f9-4fa7-bf6e14df3c33.png">

イメージとしては`petal length (cm)`の値を昇順でソートして値が同じデータがあれば、`petal width (cm)`の値を昇順でソートする感じ。

上の画像だと122行目と117行目は`petal length (cm)`の値はどちらも6.7です。

ソートの基準が`petal length (cm)`だけだったら上から117行目、122行目になるはずです。

今回は引数に`petal width (cm)`も指定しているので、`petal width (cm)`の値が小さい122行目が先に表示されています。

参考までに`petal length (cm)`だけでソートした結果
<img width="498" alt="スクリーンショット 2020-05-17 0.39.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/29405a07-903f-0e9c-2f88-91f9742e290e.png">

２つの画像で122行目と117行目の順番が逆になっている。


##6-2.インデックス（行名・列名）でソート
**インデックスでソート＝行名または列名自体をソート**

###6-2-1.行名をソート
まず、行名に関しては元々のDataFrameが0から昇順に並んでいるので降順でソートします。

```python
# ascending=Falseは降順の意味
df.sort_index(ascending=False)
```
下の画像のように行名が149→0にソートされます。
<img width="498" alt="スクリーンショット 2020-05-17 0.42.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/89431b44-9ac8-88b1-7fa0-97d3a34e3ef7.png">

###6-2-2.列名をソート
列名ソートするためには第1引数に`axis=1`を指定する。降順の指定はこれまでと同じ

```python
df.sort_index(axis=1)
```
列名がアルファベット順にソートされました。
<img width="498" alt="スクリーンショット 2020-05-17 0.49.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/3879df09-2181-349e-11cd-732ebc2cc7b4.png">

降順にソートする場合は第二引数に`ascending=False`を指定するだけなので割愛。

ソートの方法はこちらの記事にもわかりやすくまとめられています。
参考：[pandas.DataFrame, Seriesをソートするsort_values, sort_index](https://note.nkmk.me/python-pandas-sort-values-sort-index/)

#7.DataFrameの列の追加

列の追加もソート同様、Scikit-learnのirisデータセットから作成したDataFrameである**df**を使用していきます。

（理由は特にないので、これまで通りSeabornのirisデータセットから作成したDataFrameである**iris**を使っても全く問題ないですし、結果も同じです）

DataFrameに列を追加する・値を上書きする方法は以下の通り。

- df[列名] = 値
- assign()メソッド

（他にもありますが本記事では割愛）

列の追加はデータ分析において、元々のデータから新しい特徴量（≒説明変数）を作成してDataFrameに追加する時に使用されます。

##7-1.df[列名] = 値

dfにaddという列を追加します。（簡略化のため値は全て0）

```python 
df['add'] = 0

df
```

<img width="521" alt="スクリーンショット 2020-05-17 14.20.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/b634b655-76e2-b3df-4100-e249046a5cea.png">

add列が追加されています。

ちなみに既存列を指定することでデータを上書きすることもできます。

```python 
df['sepal length (cm)'] = 0

df
```
<img width="521" alt="スクリーンショット 2020-05-17 14.27.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/19f9c168-9bd7-290a-26af-ef108e10acac.png">

##7-2.assign()メソッド
先ほど同様、add列を追加します。

```python
df.assign(add=0)

df

# assgin()メソッドでは列名が文字列でも''を付けるとエラーになる
# エラー例
# df.assign('add'=0)
```
<img width="521" alt="スクリーンショット 2020-05-17 14.33.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/3374c7fe-9cfe-14f9-acdc-e98aaf2873e3.png">

あれ？変わっていませんね。

ここが先ほどの`df[列名] = 値`での追加と異なるところです。

assign()メソッドで列を追加した場合、**新たなオブジェクト（DataFrame）が返され、元のオブジェクトは変更されません。**

なので最後に`df`を表示させると元々のirisデータセットが表示されます。

逆に`df[列名] = 値`で列を追加もしくは既存列データの上書きをした場合は元のオブジェクトが変更されてしまうので注意が必要です。

例えば、`df[列名] = 値`の形で列を追加した場合は以下の通りになります。
（add列追加、sepal length (cm)列のデータ上書きどちらも反映）

```python
df['add'] = 0

df['sepal length (cm)'] = 0

df
```

出力結果
<img width="521" alt="スクリーンショット 2020-05-17 14.52.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/8b7d06f6-f562-fc93-77f0-c8c5d200549c.png">

上の画像からわかるように元々のDataFrameに影響を及ぼします。

※なのでJupyter Notebookでこの処理を複数回実行してしまうとどんどん列が追加されてしまいます。
列を追加する処理はパートを分けて書いて上げると良いです。


`df[列名] = 値`でのDataFrameの操作の注意点を説明したところで話を戻します。

assign()メソッドを使用するときは以下のように実行します。

```python
#この書き方をすると列がされた状態のDataFrameを表示可能
df.assign(add=0)
# ここで実行

# もしくは

#返された新たなオブジェクトを変数に格納
df_new = df.assign(add=0)

df
#ここで実行
```
<img width="521" alt="スクリーンショット 2020-05-17 14.38.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/f02be29c-1580-13ea-22d8-5b75cb368174.png">

これでadd列が追加されましたね。

上書きの場合も同様です。


列の追加、行の追加も下リンクの記事に詳しく書かれています。
参考：[pandas.DataFrameに列や行を追加（assign, appendなど）](https://note.nkmk.me/python-pandas-assign-append/)

列、行の名前の変更はこちら
参考：[【Python】pandas.DataFrameの概要と作成方法・変換方法](https://obgynai.com/python-pandas-dataframe-index-columns-data/)


#まとめ

今回の記事ではPandasの基本的な扱い方を初学者の方でもかなりわかりやすいようにまとめました。

- 1.Pandasとは
- 2.SeriesとDataFrameについて
- 3.ファイルの読み込み・書き出し
- 4.データセットからDataFrameを作成
- 5.データの参照
- 6.ソート（並び替え）
- 7.DataFrameの列の追加


内容に間違い等あればコメントいただけると嬉しいです。
また、わかりにくいところがあればそちらもコメントいただけると嬉しいですm(__)m

僕がこれまでに投稿したPython関連の記事はこちら↓
[【Python】集合型（セット）について図でわかりやすくまとめてみた](https://qiita.com/shimotaroo/items/130ec5d9c5b46326ce55)