IT

【Python】NumpyとPandas

2021年7月8日

NumpyとPandasとは?

Pythonのライブラリで様々なデータを配列だったり、データフレーム、行列に変換することのできるライブラリのことです。

NumpyとPandasの関係性

Numpyは数値の配列を簡単に作成できます。主に数列など!
さらに数列が作れるのであれば行列もNumpyで作成できます。

そしてPandasでも数値の配列や行列の作成ができます。
え?じゃあNumpyとPandasの違いってなんだろう!

それはキー(index)を持つかどうかです!
Numpyでは配列の各要素に対してkeyがなく、アクセスする場合はa[0]やa[4]のようにアクセスします。
そして行列も作成できますが、行列は配列の集合体(厳密にはベクトルの集合体)で、
こちらもa[1,1]などのようにアクセスします。

逆にPandasではindexをつけることができるので、
a["orange"]だったりでアクセスできますし、
numpyでいう行列は、pandasではデータフレームといい、これはa["column","row"]のようにindexでアクセスすることができます。
ちなみにnumpyでいう配列はSeriesと言います。
phpで言えば連想配列的なイメージです。

上記のことから、
numpyで生成した配列や行列を使って、pandasではSeriesやDataframeを作成することができます。


https://numpy.org/doc/stable/reference/distutils_guide.html

コード

import numpy as np
               
np.arrange(5)
np.arrange(6).reshape((2,3))    # 2,3次元配列(行列)
np.zero(3)                      # 3次正方行列(すべての要素を0にする)
np.ones(3)                      # 3次正方行列(すべての要素を1にする)

# ランダム系
np.random.uniform()             # 平均、分散を指定するとそのランダムを算出してくれる
np.random.rand()             # 一様分布
np.random.normal(a, b, size)       # 平均a, 分散b、個数sizeの正規分布
np.random.randn()            # 標準正規分布(平均0, 分散1)
np.random.beta(a,b)          # ベータ分布


import numpy as np
import pandas as pd

# numpyからpandasの形式に変換する
# numpyの1字形式からseries
# numpyの2字形式からdataframe

# numpyからpandas形式に変換
pd.Series(np.arrange(5), index=)                                   # Series
pd.DataFrame(np.arrange(6).reshape((2,3)), index=, columns=)       # DataFrame (index=行, columns=列)

# カラム名取得
dataframe.index
dataframe.columns


# インデックス名の変更
Series.reindex([,,,])                               # Seriesの行の名前を変更する
DataFrame.reindex([,,,])                            # DataFrameの列の名前を変更する
DataFrame.reindex([,,,], axis=1)                    # DataFrameの行の名前を変更する
DataFrame.reset()                                   # index, columnsのindex名、などを削除して0,1,2,3..という初期の値を入れる

# 列単位、行単位の取得
Series.ix[]
DataFrame.columns名                 # dataframeでの列の取得
DataFrame.ix[index名]               # dataframeでの行の取得

# DataFrameのピンポイントの取得 → 新たなdataframeを作成

# データの取り込み
# csvやtsvデータなどは基本的に複数行となる。(戻りはDataFrame)
pd.read_csv('')                     # csv専用の読み込み。csvなのでシートは1つのシートのみなので、引数にシート名はない
pd.read_table('', sheet_name="", sep="")        # excel、txt、tsvなどいろいろ読み込める。excelの場合はどのシートを読み込むかを指定。txtで,区切りなら、sep=","を指定
pd.read_clipboard()                 # クリップボードのデータをDataFrame化する(ctrl+CでコピーしたものをDataFrame化する)

# 要約統計量
dataframe.sum()                                     # 列ごとに合計値を出力
dataframe.sum( axis = 1 )                           # 行ごとに合計値を出力
dataframe.min()                                     # 列ごとに最小値を出力
dataframe.min( axis = 1)                            # 行ごとに最小値を出力
dataframe.max()                                     # 列ごとに最大値を出力
dataframe.max( axis = 1)                            # 行ごとに最大値を出力
dataframe.cumsum()                                  # 累積合計値を埋め込んでいく(1行目から累積で表示。そのため順番が大事。)
dataframe.describe()                                # dataframeの詳細情報を出力(主に要約統計量)


# 列の削除
del DataFrame.columns名
DataFrame.drop([columns名])                         # 指定したカラムを削除(複数の場合はlistで指定)
DataFrame.drop([index名], axis=1)                   # 指定したindexを削除(複数の場合はlistで指定)

# NAを探す
DataFrame.naAll()?

# 列ごとに処理を適用する
dataframe.apply( lambda { 行ごとに実行したいロジック } )    # 列ごとに処理を行う

# データフレームの上位5件(デフォルト)を表示
dataframe.head()
dataframe.head(10)        # 10件表示
# データフレームの下位5件を表示
dataframe.tail()

# データフレームの表示
display(df)

# 既存データフレームにカラムの追加
# dfに顧客番号、商品カテゴリ、商品カテゴリ単価、購入数、受注日があったとして、これに新たなカラムとして「購入額」を追加したい場合
df["購入額"] = df["商品カテゴリ単価"]*df["購入数"]
# 普通に追加すればいい

# ============ SQLチックなこと。(SQLでできることを) ============
# ① join
# 複数のdataframeのmerge(2つが同じキーの名前)
pd.merge(df1, df2, on='顧客番号')

# ② group by
# pandasでもgroupbyです
.groupby('顧客番号')

# ③ order by
# pandasではsort_values()で行います。
sort_values('受注日', ascending=True)

# ④ where
# pandasでは色々やり方はあります。
df[df['受注日'] > '20220101']]     # データフレームの受注日が2022年のもののみに絞る
df[df['受注日'] > '20220101' && df['商品カテゴリ'] == "商品AA"]]       # 2022年で、商品AAのみ

# ⑤ having
# 普通にgroupbyしてsumか何かした後のデータフレームに対して④を行う

# ⑥ limit
# 並び替えをして
.head(10)     上位10件
.tail(8)      下位8件
   


 
SQLチックなことのところは、
これらはカラムを指定してorderbyしたり、groupbyしたりしています。
カラムを指定する、、カラムがないと使用できないので、numpyではカラムはなくただのベクトル、行列なので、データフレームというpandasを利用しないとこれらの処理はできません。
numpyはあくまで数値を生み出したり、数値に対して何かをするというものです。
なのでサンプルデータを生み出したり、規則性のあるような数値をサンプリングしたりするのに使い、
そこで生まれたベクトルや行列を、pandasで使えるように
pd.Dataframe(numpy型)
でpandasで、そしてデータフレームで扱えるようにします。
 

groupby

Rもそうですが、関数型言語であるため、メソッドチェーンができます。
groupbyにはグルーピングしたいものを指定します。
以下では顧客番号でグルーピングする例が出てますが、顧客番号だけでなく、顧客番号×商品カテゴリで顧客番号粒度だと、顧客番号ごとに売上を出したりしますが、
顧客番号と商品カテゴリをかけることで、この組み合わせごとに売上を出してくれるので、ユーザーごとにどんな商品を好んで買うのかを集計できます。

df[['顧客番号','受注日']].sort_values('受注日', ascending=True).groupby('顧客番号').tail(1).rename(columns={'受注日':'最新購入日(受注日)'})

 

そして複数指定したい場合は、以下のようにリスト化することで、使用できます。

df[['顧客番号','商品カテゴリ','受注日']].sort_values('受注日', ascending=True).groupby(['顧客番号','商品カテゴリ']).tail(1).rename(columns={'受注日':'最新購入日(受注日)'})

 
pythonでは複数の値を扱いたい場合は、リスト化して指定するのが通常です。

グルーピングしたいデータをdfから選択します。
それがdf[['顧客番号','受注日']]
そしてその後、sort_valuesで受注日に対して昇順に並び替えています。
そのデータフレーに対して、groupby('顧客番号')ということで、顧客番号ごとに処理を行い、
その処理にtail(1)つまり、昇順に並び替えている状態での各顧客番号ごとのtail(1)なので、最新受注日を取得します。
その結果、
出力されるデータフレームは、各顧客番号の最新受注日のデータフレームが作成されます。

groupbyで出力されるデータフレームに対して、カラムを最後変更して、現在のカラム名「受注日」→最新購入日(受注日)に変更して終了します。
 
適用する関数の順番によって処理の結果は変わります。
pandasやnumpyは直感的でわかりやすく、
基本的にデータフレームに対して関数を適用して、その関数の戻り値がデータフレーム型であれば、また別のデータフレーム対応の関数を適用して、、、の繰り返しなので、
今データがこういう処理されてこういう形になるから、次はこの関数でこうして、、、っていう想像がつきやすく、データ整形にはもってこいなライブラリですね。
javascriptのjqueryのようなメソッドチェーンですね。関数型言語の特徴であったりします。
 
※ groupbyをした結果は、

という形になります。
そのため、groupbyをした結果はindexが外れてしまいます。indexは1行目、2行目など、データフレームを表示した際に一番左に表示されるレコードのことですが、それらが消えてしまい、データフレームの中に組み込まれてしまいます。
そうなるとデータフレームの中に余分なデータが入ってしまいめんどくさくなります。なのでそうならないように、
groupbyの後に、reset_index()とすることで、元のindexを貼ってくれます。

groupbyには集計したい軸、つまりディメンションを指定します。ディメンションの指定は何個もできます。
そしてgroupbyを実行するdfの中ではそのディメンションとgroupbyによって集計したい処理したいメジャメント(数値)を置きます。
これにより集計されますが、
groupbyを実行するdf[['顧客番号','受注日']]の中に商品カテゴリがないのに、groupbyで指定することはできません。

型変換

通常、csvなどを読み込む場合は、データフレームで読み込みます。csvにはカラムがあるので。
でプログラムはAIではないので、ひとまず全てのカラムの型は、object型という型になります。

売上情報のcsvとかだと、個数は数値ですが、データフレームで読み込むとデフォルトでobject型になります。
なのでその型をint型に変換したい場合は、

df = df.astype({'金額': int, '数量': int})

のように指定します。

df = df.astype({'型を変更したいカラム名': 'どの型にしたいか'})

なので、上の例だと、金額というデータフレームのカラムの型をint型に変換し、数量というカラムをint型に変更するという処理です。

変更しないといけない理由としては、
object型で数値を扱ってしまうと、
例えばsumなどの集計関数では、集計なのでint型などの数値系の型をもつカラムでしか演算ができなかったり、
さらにはデータフレームの条件を絞りたい時、マイナスではなく数値がプラスのものに絞りたい場合に、object型だと
==
などで比較ができません。
int型にすることで、数値の比較ができるようになり、条件で絞れるようになります。
 

Numpyによるデータ生成

array creation routinesとある通り、規則性のある値の配列を作成します。
numpy.arrangeであれば等差数列の配列
numpy.zeroであれば0しか入らない配列
https://numpy.org/doc/stable/reference/routines.array-creation.html
 

numpy.randomでランダムサンプリングをする。
numpy.random.randは0から1でのランダムサンプリング
numpy.random.chisquareはカイ二乗分布のランダムサンプリング(サンプリングする範囲や分布のパラメータ、サンプルサイズは引数に指定したりする)
numpy.random.normalはガウス分布(正規分布)からのランダムサンプリング。
https://numpy.org/doc/stable/reference/random/generated/numpy.random.rand.html

-IT
-

© 2022 Yosshi Blog Powered by AFFINGER5