📖

【新】ライブラリ「pandas」基礎(表計算)

2023/05/10に公開

本記事はAidemyの【新】ライブラリ「pandas」基礎(表計算)の講義ノートです。


[!abstract]+ Curriculum

  1. pandas とは
  2. pandas の操作方法
  3. 複数の DataFrame の利用
  • 添削問題

Pandas とは

テーブルデータを扱うことに特化したライブラリ。
Pandas vs. NumPy|600


Pandas 操作

データの読み書き

#pd/リード #pd/セーブ

  • pd.read_csv() : sep, header, names, encodinng
  • pd.read_excel() : 'Sheet1'.
  • .to_csv(˶´꒳˵), .to_excel(˶´꒳˵) : index, header

データ操作:作成、タイプ、参照、並べ替え、追加、削除

データ生成

#pd/new

  • シリーズ生成 : pd.Series(dic)
  • DataFrame 生成 : pd.DataFrame(dic) or .DataFrame([Series1, Series2, ... ])

データタイプ

#pd/タイプ

  • タイプの確認 : .dtypes()
  • タイプ変更 : .astype()
df["price"] = df["price"].astype(float) # 非破壊なメソッドなのでイコールを用いて上書き

データ参照

#pd/access

  • Series : スライスは自動的に角括弧の扱いを受けると思えばよい。
series[1]
print(series[0:2])
series[['orange','peach']]
series["orange":]
series['orange']
  • df
    • head, tail
    • loc : インデックススライスから最後のインデックスまで含む。
    • iloc : インデックススライスはいつも通り。
print(df.head())
print(df.tail(10))
print(df.loc[1:2,"product":])

>>>出力結果
  product  price  quantity
1  orange   1000         2
2  orange    800         1

#pd/access/bull

  • Bull 代数を使った参照
import pandas as pd

food = {"snack": 200, "ra-men": 1000, "rice": 800, "coffee": 100, "green-tea":250, "wine":900}
series = pd.Series(food)
conditions = [True, True, False, False, False, False]

print(series[conditions])

>>>出力結果
snack      200
ra-men    1000
dtype: int64
import pandas as pd

data = {"store": ["shibuya", "shinjuku", "yokohama", "shibuya", "shinjuku", "shibuya"],
        "product": ["banana", "orange", "orange", "grape", "banana", "peach"],
        "price": [200, 1000, 800, 100, 250, 900],
        "quantity": [1, 2, 1, 2, 3, 2]}
df = pd.DataFrame(data)

print(df["price"]>500)
print()
print(df[df["price"]>500])

>>>出力結果
0    False
1     True
2     True
3    False
4    False
5     True
Name: price, dtype: bool

      store product  price  quantity
1  shinjuku  orange   1000         2
2  yokohama  orange    800         1
5   shibuya   peach    900         2

データソート

#pd/ソート

  • Series : インデックスソート、値ソート: ascending
print(series.sort_index())
series.sort_values(ascending=False)
  • df : 列を指定してソート。複数のソートが可能。
print(df.sort_values(by=["quantity", "price"], ascending=True))

データの追加、削除

#pd/append

  • Series : Series を追加します。非破壊なので代入が必要。
grape = {"grape": 3} # 既に作成したseriesにgrapeを追加
series = series.append(pd.Series(grape)) # 非破壊なメソッドなのでイコールを用いて上書き
  • df
    • インデックスの方向 : Series を append.もし、今までなかった新しい列を追加する場合、既存のインデックスに対しては新しい列の値が NaN に設定されます。
    • カラム方向 : dic に新しい要素を追加するようにする。
import pandas as pd

data = {"store": ["shibuya", "shinjuku", "yokohama", "shibuya", "shinjuku"],
        "product": ["banana", "orange", "orange", "grape", "banana"],
        "price": [200, 1000, 800, 100, 250],
        "quantity": [1, 2, 1, 2, 3]}
df = pd.DataFrame(data)

print(df)  # 元のDataFrameの出力
print()  # 改行

series = pd.Series(
    {"store": "shibuya", "product": "peach", "price": 900, "quantity": 2, "month": "August"})
# Seriesの作成(DataFrameにはmonthカラムは存在しない)
df = df.append(series, ignore_index=True)

print(df)  # 追加後のDataFrameの出力

>>>出力結果
     store product  price  quantity
0   shibuya  banana    200         1
1  shinjuku  orange   1000         2
2  yokohama  orange    800         1
3   shibuya   grape    100         2
4  shinjuku  banana    250         3

      store product  price  quantity   month
0   shibuya  banana    200         1     NaN
1  shinjuku  orange   1000         2     NaN
2  yokohama  orange    800         1     NaN
3   shibuya   grape    100         2     NaN
4  shinjuku  banana    250         3     NaN
5   shibuya   peach    900         2  August
import pandas as pd

data = {"store": ["shibuya", "shinjuku", "yokohama", "shibuya", "shinjuku"],
        "product": ["banana", "orange", "orange", "grape", "banana"],
        "price": [200, 1000, 800, 100, 250],
        "quantity": [1, 2, 1, 2, 3]}
df = pd.DataFrame(data)

print(df)
print()  # 改行
df["month"] = ["August", "September", "November",
               "January", "October"]  # カラムmonthを追加

print(df)

>>>出力結果
     store product  price  quantity
0   shibuya  banana    200         1
1  shinjuku  orange   1000         2
2  yokohama  orange    800         1
3   shibuya   grape    100         2
4  shinjuku  banana    250         3

      store product  price  quantity      month
0   shibuya  banana    200         1     August
1  shinjuku  orange   1000         2  September
2  yokohama  orange    800         1   November
3   shibuya   grape    100         2    January
4  shinjuku  banana    250         3    October

#pd/del

  • シリーズ
# バナナのインデックスを削除
series = series.drop("banana") # 非破壊なメソッドなのでイコールを用いて上書き
  • df : axis 指定でインデックスだけでなくカラム削除も可能。
# インデックス1,2を削除
df = df.drop(range(0, 2)) # 非破壊なメソッドなのでイコールを用いて上書き
df = df.drop("store", axis=1) # カラムstoreの削除

DataFrame を利用したデータ分析

DataFrame の計算処理

#pd/cal

  • 列同士の四則演算が可能
import pandas as pd
import numpy as np

data = {"apple": [6, 1, 4, 4, 8],
        "orange": [1, 4, 5, 6, 3],
        "banana": [6, 10, 9, 10, 5],
        "strawberry": [3, 4, 9, 2, 4],
        "kiwifruit": [10, 10, 1, 5, 8]
        }
df = pd.DataFrame(data)

print(df)
print() # 改行
print(df['apple']+df["strawberry"])  # カラム同士の足し算

>>>出力結果
   apple  orange  banana  strawberry  kiwifruit
0      6       1       6           3         10
1      1       4      10           4         10
2      4       5       9           9          1
3      4       6      10           2          5
4      8       3       5           4          8

0     9
1     5
2    13
3     6
4    12
dtype: int64
  • ブロードキャスト可能。しかし、strデータがあれば不可能。
import pandas as pd

data = {"store": ["shibuya", "shinjuku", "yokohama", "shibuya", "shinjuku", "shibuya"],
        "product": ["banana", "orange", "orange", "grape", "banana", "peach"],
        "price": [200, 1000, 800, 100, 250, 900],
        "quantity": [1, 2, 1, 2, 3, 2]}
df = pd.DataFrame(data)

print(df+2)  # DataFrameの要素全てに2を足す

>>>出力結果
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
〜中略〜

TypeError: can only concatenate str (not "int") to str

NumPy の併用

#pd/np #np/pd

  • np 関数に Series や DataFrame を引数に入れると、全ての要素について計算。
import pandas as pd
import numpy as np

data = {"apple": [6, 1, 4, 4, 8],
        "orange": [1, 4, 5, 6, 3],
        "banana": [6, 10, 9, 10, 5],
        "strawberry": [3, 4, 9, 2, 4],
        "kiwifruit": [10, 10, 1, 5, 8]
        }
df = pd.DataFrame(data)

print(df)
print()
print(np.log(df))  # Numpyの関数を用いて要素の値を対数変換

>>>出力結果
  apple  orange  banana  strawberry  kiwifruit
0      6       1       6           3         10
1      1       4      10           4         10
2      4       5       9           9          1
3      4       6      10           2          5
4      8       3       5           4          8

      apple    orange    banana  strawberry  kiwifruit
0  1.791759  0.000000  1.791759    1.098612   2.302585
1  0.000000  1.386294  2.302585    1.386294   2.302585
2  1.386294  1.609438  2.197225    2.197225   0.000000
3  1.386294  1.791759  2.302585    0.693147   1.609438
4  2.079442  1.098612  1.609438    1.386294   2.079442

要約統計量

#pd/stats

print(df.describe()) # 要約統計量

##グループ化

#pd/grouping

  • グループ化:特定のカラムに対して同じ値を持つ行を集約する操作。
  • .groupby()`で GroupByオブジェクトが返されるが、printで表示は不可。
    • グループ化後に関数を適用して確認可能**。
    • .min(), .max()` は文字列にも適用:文字コードの最小値、最大値**。
import pandas as pd

data = {"store": ["shibuya", "shinjuku", "yokohama", "shibuya", "shinjuku", "shibuya"],
        "product": ["banana", "orange", "orange", "grape", "banana", "peach"],
        "price": [200, 1000, 800, 100, 250, 900],
        "quantity": [1, 2, 1, 2, 3, 2]}
df = pd.DataFrame(data)

print(df)
print()  # 改行
print(df.groupby('store').sum())  # 合計
print()  # 改行
print(df.groupby('store').mean())  # 平均
print()  # 改行
print(df.groupby('store').var())  # 分散
print()  # 改行
print(df.groupby('store').min())  # 最小値
print()  # 改行
print(df.groupby('store').max())  # 最大値

>>>出力結果
     store product  price  quantity
0   shibuya  banana    200         1
1  shinjuku  orange   1000         2
2  yokohama  orange    800         1
3   shibuya   grape    100         2
4  shinjuku  banana    250         3
5   shibuya   peach    900         2

          price  quantity
store                    
shibuya    1200         5
shinjuku   1250         5
yokohama    800         1

          price  quantity
store                    
shibuya   400.0  1.666667
shinjuku  625.0  2.500000
yokohama  800.0  1.000000

             price  quantity
store                       
shibuya   190000.0  0.333333
shinjuku  281250.0  0.500000
yokohama       NaN       NaN

         product  price  quantity
store                            
shibuya   banana    100         1
shinjuku  banana    250         2
yokohama  orange    800         1

         product  price  quantity
store                            
shibuya    peach    900         2
shinjuku  orange   1000         3
yokohama  orange    800         1

複数のDataFrameの利用

DataFrame 接続、結合の概要

  • データを一括して管理しているところはなく、店舗程度、会員情報、商品情報のように分けて管理しているところが多い。
  • これらのデータをまとめて分析することで、より深い考察ができる。
  • 連結と結合
    • 連結 : インデックス方向やカラム方向にDataFrameをつなぐこと。
    • 結合 : keyという特定のカラムを基準にDataFrameをつなぐこと。

接続

#pd/concat

  • インデックスやカラムが一致しない部分はNaN表示。
import pandas as pd

data1 = {"store": ["shibuya", "shinjuku", "yokohama", "shibuya"],  # data2よりインデックスの数が1つ多い
         "product": ["banana", "orange", "orange", "grape"],
         "price": [200, 1000, 800, 1000],
         "quantity": [1, 2, 1, 1]}

data2 = {"store": ["shibuya", "shinjuku", "shibuya"],  # data1にはないカラム
         "product": ["grape", "banana", "peach"],
         "価格": [100, 250, 900],
         "quantity": [2, 3, 2]}

df1 = pd.DataFrame(data1)
df2 = pd.DataFrame(data2)
print(pd.concat([df1, df2], axis=0))
print()  # 改行
print(pd.concat([df1, df2], axis=1))
print()  # 改行
print(pd.concat([df1, df2], axis=0).dtypes)

>>>出力結果
     store product   price  quantity     価格
0   shibuya  banana   200.0         1    NaN
1  shinjuku  orange  1000.0         2    NaN
2  yokohama  orange   800.0         1    NaN
3   shibuya   grape  1000.0         1    NaN
0   shibuya   grape     NaN         2  100.0
1  shinjuku  banana     NaN         3  250.0
2   shibuya   peach     NaN         2  900.0

      store product  price  quantity     store product     価格  quantity
0   shibuya  banana    200         1   shibuya   grape  100.0       2.0
1  shinjuku  orange   1000         2  shinjuku  banana  250.0       3.0
2  yokohama  orange    800         1   shibuya   peach  900.0       2.0
3   shibuya   grape   1000         1       NaN     NaN    NaN       NaN

store        object
product      object
price       float64
quantity      int64
価格          float64
dtype: object

結合

#pd/merge

二つのデータフレームの key セットをセット A、B とすると簡単。

  • 内部結合 : A∩B
  • 左、右外部結合 : それぞれ集合 A、集合 B
  • 完全外部結合 : A∪B

交差点

import pandas as pd
pd.merge(左のDataFrame, 右のDataFrame, on = "keyにするカラム名", how="inner")

集合 A

import pandas as pd
pd.merge(左のDataFrame, 右のDataFrame, on = "keyにするカラム名", how="left")

集合 B

import pandas as pd
pd.merge(左のDataFrame, 右のDataFrame, on = "keyにするカラム名", how="right")

和集合

import pandas as pd
pd.merge(左のDataFrame, 右のDataFrame, on = "keyにするカラム名", how="outer")

添削問題

import pandas as pd

store_data = {
    "store": ["shibuya", "shinjuku", "yokohama", "meguro", "ikebukuro"],
    "ID": [1, 2, 3, 4, 5]
}
store_df = pd.DataFrame(store_data)  # store_dfを作成

data = {"ID": [1, 2, 3, 3, 2, 1],
        "product": ["banana", "orange", "orange", "grape", "banana", "peach"],
        "price": [200, 1000, 800, 100, 250, 900],
        "quantity": [1, 2, 1, 2, 3, 2]}
df = pd.DataFrame(data)  # dfを作成

print(df)  # dfを出力
print()
print(store_df)  # store_dfを出力
print()

  
# 問題1
# dfのインデックスが0から4までの要素、カラム名を出力してください。
df_1 = df.head()
print(df_1)
print()

  
# 問題2
# df とstore_dfをkeyをIDとして外部結合してください。
df_2 = pd.merge(df, store_df, on='ID', how = 'outer')
print(df_2)
print()

  
# 問題3
# df とstore_dfをkeyをIDとして内部結合してください。
df_3 = pd.merge(df, store_df, on='ID', how = 'inner')
print(df_3)
print()

  
# 問題4
# 問題3の回答にて作成したdf_3とgroupbyメソッドを用いてstore毎のID、price、quantityの平均値を出力してください。
df_4 = df_3.groupby('store').mean()
print(df_4)
print()

  
# 問題5
# 問題3の回答にて作成したdf_3とdiscribeメソッドを用いてID、price、quantityの要約統計量を出力してください。
df_5 = df_3.describe()
print(df_5)

Discussion