pandasの基本と応用：データ構造からデータ抽出・加工、統計分析まで

## はじめに

pandasは、データ分析のためのデータ構造やツールを提供するライブラリです。データフレーム（DataFrame）やシリーズ（Series）というデータ構造を使って、簡単にデータの抽出、加工、分析が可能です。ここでは、pandasの基本的な使い方を書いていきます！


### データ構造
pandasは、NumPyを基盤として構築されていますが、より高レベルなデータ操作を可能にしています。主に使用されるデータ構造は以下の2つです。

シリーズ（Series）: 一次元の配列で、ラベル（インデックス）が付いています。辞書のようなデータ構造と考えると理解しやすいです。
データフレーム（DataFrame）: 二次元のテーブル形式のデータ構造で、行と列にラベルが付いています。エクセルのスプレッドシートのようなものです。

### データフレーム作成

まずは、pandasをインポートして、基本的なデータフレームを作成します。

```python
import pandas as pd

data = {
    'name': ['Alice', 'Bob', 'Charlie'],
    'age': [25, 30, 35],
    'Occupation': ['エンジニア', 'デザイナー', '医者']
}

df = pd.DataFrame(data)
print(df)

```

出力結果↓

```markdown
      Name  Age Occupation
0     Alice   25   Engineer
1       Bob   30   Designer
2   Charlie   35     Doctor
```

### データの抽出
データフレームから特定の行や列を抽出する基本的な方法を紹介します。

・列の抽出
データフレームの特定の列を抽出するには、列名を指定します。列名を指定する方法には、角括弧を使う方法と、ドットを使う方法の2つがあります。

```python
data = {
    'Name': ['Alice', 'Bob', 'Charlie'],
    'Age': [25, 30, 35],
    'Occupation': ['Engineer', 'Designer', 'Doctor']
}

df = pd.DataFrame(data)

# 'Name'列を抽出
names = df['Name']
print(names)
```

出力結果↓
```
0      Alice
1        Bob
2    Charlie
Name: Name, dtype: object
```

・複数の列を抽出する

``` python
# 'Name'と'Occupation'列を抽出
subset = df[['Name', 'Occupation']]
print(subset)
```

出力結果↓
```
       Name Occupation
0     Alice   Engineer
1       Bob   Designer
2   Charlie     Doctor
```

・行の抽出
インデックスを使って行を抽出することができます。インデックスには、整数インデックス（位置）を使う方法と、ラベル（行ラベル）を使う方法があります。

ilocを使うと、整数インデックスを使って行を抽出できます。
``` python
# インデックスが1の行を抽出
row = df.iloc[1]
print(row)
```

出力結果↓
```
Name          Bob
Age            30
Occupation  Designer
Name: 1, dtype: object
```

locを使うと、ラベルを使って行を抽出できます。
```python
# 行ラベルが1の行を抽出
row = df.loc[1]
print(row)
```
出力結果は上記と同じになります。

・複数の行を抽出する
複数の行を抽出する場合は、インデックスやラベルのリストを使います。
```python
# インデックスが0と2の行を抽出
rows = df.iloc[[0, 2]]
print(rows)
```

出力結果↓
```
       Name  Age Occupation
0     Alice   25   Engineer
2   Charlie   35     Doctor
```

・ 条件に基づく抽出

Ageが30以上の行を抽出しています。


```python
# 'Age'が30以上の行を抽出
filtered_df = df[df['Age'] >= 30]
print(filtered_df)
```

出力結果↓
```
       Name  Age Occupation
1       Bob   30   Designer
2   Charlie   35     Doctor
```

・複数の条件を使った抽出
複数の条件を組み合わせて抽出する場合は、ANDやORを使います。
```python
# 'Age'が30以上かつ'Occupation'が'Doctor'の行を抽出
filtered_df = df[(df['Age'] >= 30) & (df['Occupation'] == 'Doctor')]
print(filtered_df)
```
出力結果↓
```
       Name  Age Occupation
2   Charlie   35     Doctor
```

### データ加工
pandasではデータ分析の前処理やクリーニング、解析のために、データの追加、削除、変換、集計、再構成など、さまざまなデータ加工がサポートされています。


・新しい列の追加
計算結果や他の列の情報を使って、新しい列を追加することができます。

``` python
data = {
    'Name': ['Alice', 'Bob', 'Charlie'],
    'Age': [25, 30, 35],
    'Occupation': ['Engineer', 'Designer', 'Doctor']
}

df = pd.DataFrame(data)

# 'Age'に1を加えた新しい列'New Age'を追加
df['New Age'] = df['Age'] + 1
print(df)
```

出力結果↓
```
       Name  Age Occupation  New Age
0     Alice   25   Engineer       26
1       Bob   30   Designer       31
2   Charlie   35     Doctor       36
```

・列の削除
不要な列を削除するには、drop()メソッドを使用します。axis=1で列を削除することを指定します。
```python
# 'New Age'列を削除
df = df.drop('New Age', axis=1)
print(df)
```
出力結果↓
```
       Name  Age Occupation
0     Alice   25   Engineer
1       Bob   30   Designer
2   Charlie   35     Doctor
```
・行の追加
新しい行を追加するには、locまたはappend()メソッドを使用します。
```python
# 新しい行を追加
new_row = pd.Series({'Name': 'David', 'Age': 40, 'Occupation': 'Artist'})
df = df.append(new_row, ignore_index=True)
print(df)
```
出力結果↓
```
       Name  Age Occupation
0     Alice   25   Engineer
1       Bob   30   Designer
2   Charlie   35     Doctor
3     David   40     Artist
```

・データの置換
特定の値を他の値に置き換えるには、replace()メソッドを使用します。
```python
# 'Occupation'列の'Engineer'を'Architect'に置換
df['Occupation'] = df['Occupation'].replace('Engineer', 'Architect')
print(df)
```

出力結果↓
```
       Name  Age Occupation
0     Alice   25  Architect
2   Charlie   35     Doctor
3     David   40     Artist
```

・データの集計
pandasでは、さまざまな集計関数を使用して、データを集計できます。
```python
# 'Age'列の合計を計算
total_age = df['Age'].sum()
print(f'年齢の合計: {total_age}')
```

出力結果↓
```
年齢の合計: 100
```

```python
# 'Age'列の平均を計算
mean_age = df['Age'].mean()
print(f'平均年齢: {mean_age}')
```
出力結果↓
```
平均年齢: 33.333333333333336
```
・グループ化して集計
groupbyメソッドを使用すると、特定のカテゴリでデータをグループ化し、集計を行うことができます。
```python
# 'Occupation'ごとの平均年齢を計算
grouped = df.groupby('Occupation')['Age'].mean()
print(grouped)
```

出力結果↓
```
Occupation
Architect    25.0
Senior       37.5
Name: Age, dtype: float64
```

・データの再構成
pivot_tableメソッドを使用すると、データをピボットテーブル形式に再構成できます。
```python
data = {
    'Name': ['Alice', 'Bob', 'Charlie', 'David'],
    'Age': [25, 30, 35, 40],
    'Occupation': ['Engineer', 'Designer', 'Doctor', 'Artist'],
    'Salary': [50000, 55000, 60000, 65000]
}

df = pd.DataFrame(data)

# 'Occupation'ごとの平均給与をピボットテーブルで表示
pivot_table = df.pivot_table(values='Salary', index='Occupation', aggfunc='mean')
print(pivot_table)

```
出力結果↓
```
            Salary
Occupation        
Artist      65000.0
Designer    55000.0
Doctor      60000.0
Engineer    50000.0
```

・データの変形
meltメソッドは、データフレームを縦長の形式に変形します。これは、データの長形式への変換に便利です。
```python
# データフレームを縦長の形式に変形
melted = pd.melt(df, id_vars=['Name'], value_vars=['Age', 'Salary'])
print(melted)
```
出力結果↓
```
      Name variable  value
0    Alice      Age     25
1      Bob      Age     30
2  Charlie      Age     35
3    David      Age     40
4    Alice   Salary  50000
5      Bob   Salary  55000
6  Charlie   Salary  60000
7    David   Salary  65000
```

・行方向の結合
concatメソッドを使用して、複数のデータフレームを行方向に結合することができます。
```python
df1 = pd.DataFrame({
    'Name': ['Alice', 'Bob'],
    'Age': [25, 30]
})

df2 = pd.DataFrame({
    'Name': ['Charlie', 'David'],
    'Age': [35, 40]
})

# 行方向に結合
df_concat = pd.concat([df1, df2], ignore_index=True)
print(df_concat)
```
出力結果↓
```
       Name  Age
0     Alice   25
1       Bob   30
2   Charlie   35
3     David   40
```

　・列方向の結合
mergeメソッドを使用して、共通のキーを使ってデータフレームを結合することができます。
```python
left = pd.DataFrame({
    'Name': ['Alice', 'Bob', 'Charlie'],
    'Age': [25, 30, 35]
})

right = pd.DataFrame({
    'Name': ['Bob', 'Charlie', 'David'],
    'Salary': [55000, 60000, 65000]
})

# 'Name'をキーとして結合
df_merged = pd.merge(left, right, on='Name', how='inner')
print(df_merged)
```

出力結果↓
```
      Name  Age  Salary
0      Bob   30   55000
1  Charlie   35   60000
```


### 統計
pandasは統計量の計算もできます。基本的な統計量を計算するメソッドを紹介します。

・要約統計量の表示
describe()メソッドは、データの要約統計量を計算し、以下の統計量を表示することができます。

**count**: 欠損値を除いたデータの個数
**mean**: 平均値
**std**: 標準偏差
**min**: 最小値
**25%**: 第1四分位数（データの下位25%の値）
**50%**: 中央値（第2四分位数、データの中央値）
**75%**: 第3四分位数（データの上位25%の値）
**max**: 最大値
```python
data = {
    'Age': [23, 25, 28, 22, 30, 35, 40],
    'Salary': [50000, 55000, 60000, 52000, 58000, 62000, 64000]
}

df = pd.DataFrame(data)
summary = df.describe()
print(summary)
```

出力結果↓
```
             Age        Salary
count   7.000000      7.000000
mean   29.000000  57333.333333
std     6.627722   5195.962293
min    22.000000  50000.000000
25%    24.500000  53000.000000
50%    28.000000  58000.000000
75%    33.750000  61000.000000
max    40.000000  64000.000000
```

・平均値
mean()メソッドは、各列の平均値を計算します。
```python
mean_age = df['Age'].mean()
mean_salary = df['Salary'].mean()
print(f'平均年齢: {mean_age}')
print(f'平均給与: {mean_salary}')
```

出力結果↓
```
平均年齢: 29.0
平均給与: 57333.333333333336
```

・中央値
median()メソッドは、データの中央値を計算します。
```python
median_age = df['Age'].median()
median_salary = df['Salary'].median()
print(f'年齢の中央値: {median_age}')
print(f'給与の中央値: {median_salary}')
```

出力結果↓
```
年齢の中央値: 28.0
給与の中央値: 58000.0
```

・分散
var()メソッドは、各列の分散を計算します。
```python
variance_age = df['Age'].var()
variance_salary = df['Salary'].var()
print(f'年齢の分散: {variance_age}')
print(f'給与の分散: {variance_salary}')
```

出力結果↓
```
年齢の分散: 43.916666666666664
給与の分散: 26995000.0
```

・標準偏差
std()メソッドは、各列の標準偏差を計算します。
```python
std_age = df['Age'].std()
std_salary = df['Salary'].std()
print(f'年齢の標準偏差: {std_age}')
print(f'給与の標準偏差: {std_salary}')
```

出力結果↓
```
年齢の標準偏差: 6.627722214849324
給与の標準偏差: 5195.962293475344
```

・最小値と最大値
min()とmax()メソッドは、各列の最小値と最大値をそれぞれ計算します。

```python
min_age = df['Age'].min()
max_age = df['Age'].max()
min_salary = df['Salary'].min()
max_salary = df['Salary'].max()
print(f'最小年齢: {min_age}, 最大年齢: {max_age}')
print(f'最小給与: {min_salary}, 最大給与: {max_salary}')
```

出力結果↓
```
最小年齢: 22, 最大年齢: 40
最小給与: 50000, 最大給与: 64000
```




### ラベリング
データフレームやシリーズの行や列に対して名前やラベルを付けて、データを視覚的に理解しやすくすることで簡単にデータ操作や分析を行えるようにできます。

データフレームやシリーズのラベリングには、インデックス（行ラベル）と列ラベルの2種類があります。


・インデックスの設定

```python
data = {
    'Name': ['Alice', 'Bob', 'Charlie'],
    'Age': [25, 30, 35],
    'Occupation': ['Engineer', 'Designer', 'Doctor']
}

# インデックスを指定してデータフレームを作成
df = pd.DataFrame(data, index=['A', 'B', 'C'])
print(df)
```
出力結果↓
```
     Name  Age Occupation
A   Alice   25   Engineer
B     Bob   30   Designer
C Charlie   35     Doctor
```

・インデックスの再設定
既存のデータフレームのインデックスを変更するには、set_index()メソッドを使用します。例えば、特定の列をインデックスとして使用したい場合に便利です。
```python
# 'Name'列をインデックスとして設定
df = df.set_index('Name')
print(df)
```

出力結果↓
```
          Age Occupation
Name                    
Alice      25   Engineer
Bob        30   Designer
Charlie    35     Doctor
```

・インデックスのリセット
インデックスをリセットして、デフォルトの整数インデックスに戻したい場合は、reset_index()メソッドを使用します。
```python
# インデックスをリセット
df = df.reset_index()
print(df)
```

出力結果↓
```
       Name  Age Occupation
0     Alice   25   Engineer
1       Bob   30   Designer
2   Charlie   35     Doctor
```

・列ラベルの変更
既存のデータフレームの列ラベルを変更するには、columns属性を使います。
```python
# 列ラベルを変更
df.columns = ['Full Name', 'Years', 'Job Title']
print(df)
```

出力結果↓
```
    Full Name  Years   Job Title
0       Alice     25   Engineer
1         Bob     30   Designer
2     Charlie     35     Doctor
```

・特定の列ラベルを変更
データフレームの一部の列ラベルだけを変更したい場合は、rename()メソッドを使用します。

```python
# 'Full Name'を'Name'に変更
df = df.rename(columns={'Full Name': 'Name'})
print(df)
```
出力結果↓
```
      Name  Years   Job Title
0    Alice     25   Engineer
1      Bob     30   Designer
2  Charlie     35     Doctor
```

## まとめ
pandasは、Pythonでのデータ操作や分析において非常に強力なツールです。データフレームやシリーズといったデータ構造を使って、データの抽出、加工、分析を効率的に行うことができます。これらをマスターすることで、より複雑なデータ分析や機械学習の前処理を行う際にも役立つと思います。