プロクラシスト

今日の寄り道 明日の近道

【Day-4】都道府県のデータをいじりながら、pandasを学ぶ


スポンサーリンク

f:id:imslotter:20171204215003p:plain

データ分析ガチ勉強アドベントカレンダー4日目。 今日はpandasを取り扱う。

機械学習系の本にも、numpy、scipy, matplotlibの使い方は載っていても、pandasを載せている本って意外と少ない。 けれど、実際numpyの次くらいによく使う。データを取り扱ったり、計算したりするときにとても便利。一方で、癖があって慣れるまでに時間がかかる。なので、基礎的な事項をまとめておこうと思う。

今回も、githubにコードや扱うデータを配置している。

github.com

都道府県の重心データを使いながら、pandasのお勉強をしようという試みである。

pandasとは

配列データの取扱が便利に行える

  • データの取り出し
  • データの操作
  • 統計計算
  • 時系列データの処理

などを簡単に行えるため、重宝する。

基礎事項は、公式ページの10 minutes to pandasを参考にすると良い。しかしこれ、確実に10分で終わらない内容となっている。その分濃いのでまあOKとする。

また、リファレンスとしては下記の本も有用である。pandasの製作者が作っているので、信頼性は高い。

Pythonによるデータ分析入門 ―NumPy、pandasを使ったデータ処理

Pythonによるデータ分析入門 ―NumPy、pandasを使ったデータ処理

基本事項

データの読み込み/書き込み

pandasの使い所としては、自分でデータ配列を作るよりかは、読み込んだcsv等のファイルを取り扱う時のほうが多いので、まずはソレ。pythonの組み込み関数であるcsvを使ってもいいが、pandasのほうがより手軽である。

# 読み込み(csv)
df = pd.read_csv("japan.csv", index_col="prefecrue")
# 書き込み(csv)
df.to_csv("japan2.csv")

index_colは、インデックスにしたい列のこと。行の指定をするときに最もわかりやすいモノ(専門的に言えば主キーのようなもの?)を指定する。指定しなければ通し番号になる。

Tips : データの文字コードがアレだと、下記のようなエラーが出るときもある。

UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8e in position 0: invalid start byte

そういうときは、

df = pd.read_csv("japan.csv", encoding="shift-jis")

とすると、解決する

SeriesとDataFrameの作成

読み込んでしまうと、そのまま表がDataFrameとして保管されるが、時には自ら作る場合もあるだろう。 pandasで用意されているデータ構造は下記のようなものがある。

種類 特徴
Series 1次元配列。要素をindexに保管
DataFrame 2次元配列。行をindex、列をcolumnとして保存する
Panel 3次元配列 参考

正直、SeriesとDataFrameだけで良い。Panelは初めて知った。

下記が、データフレームの作り方である

# seriesが1次元配列、dataframeが多次元配列
se = pd.Series([1,3,5,np.nan,6,8])
print(se)
# dataframe
dates = pd.date_range("20130101",periods=6) 
df = pd.DataFrame(np.random.randn(6,4), index=dates, columns=list('ABCD'))

indexは指定しなければ、通し番号になる。datetimeなどで指定してやると後々時刻の範囲検索などもできるので便利である。

データの基本的な情報をGetする

(基本的にDataFrameの話を中心にすすめる)

こうしてGETしたDataFrameの、基本的な情報は、下記のようにしてアクセスできる

  • df.head(3) # 初めの3つを見る
  • df.tail(3)) # 後の3つを見る
  • df.index # インデックスを確認
  • df.columns # カラムを表示
  • df.values # 中の値をarray形式で表示
  • df.describe() # 統計量(頻度、uniqueな値の個数、max,min,平均、25%点etc...)を表示

df.valuesまでは、は中身を見るのにどれもよく使う。describeは初めて知った。便利そうだから今後使ってみる。

データ内部へのアクセス

DataFrame型へのアクセスは、様々用意されている。が、様々用意されているが故に、どれがどのようなアクセスの仕方だったのか、わかりにくくなっているのも事実である。ここで、どういうアクセスの仕方が可能なのか、まとめておく。

  • 基本
    • df["longtitude] # カラムの値(df.longtitudeでも可能)
    • df[0:3] # indexの指定
  • ラベルで指定 : df.loc
    • df.loc["東京都"] # indexの指定
    • df.loc[:,["longtitude","latitude"]] # columnのみ指定
    • df.loc["東京都",["longtitude","latitude"]] #両方指定
    • df.loc["東京都","longtitude"] # セル一つ分の指定
    • df.at["東京都","longtitude"] # セル一つ分の指定(より高速なアクセスが可能)
  • 位置による指定 ; df.iloc
    • df.iloc[3] # ilocによる行指定
    • df.iloc[3:5, 0:2] # ilocによる行列範囲指定
    • df.iat[1,1] # scalarの値(高速版)
  • 条件検索
    • df = df[(df.index!="沖縄県")&(df.index!="北海道")] # 沖縄と北海道は除外
    • 数値的な条件(>, == など)も可能

新しいcolumnの追加、計算の適用。

japanデータは、緯度経度が136:08:07のように、数値で入っていない。なので、この60度法で書かれたものをfloat型に変換し、新しいcolumnを追加したい。columnの追加は以下のような方法で出来る。辞書の追加のようなものだ。

df["new_column"] = (新しい配列 or Series)

変数の変換には、calc_numberという関数を用意した。

def calc_number(d_num):
    """
    度であらわされてるのを、小数に変換
    """
    d = d_num.split(":")
    n = int(d[0])+float(d[1])/60+float(d[2])/3600
    return n

さて、問題は、これをlongtitude,latitude関数の全てのindexに適用させるにはどうしたら良いかだ。 方法は2つある。

  • 一度配列を作り直して、新しいcolumnとして追加する
  • apply関数を適用する

二番目の方法のほうが、シンプル。apply関数をつかうと、指定したcolumn全体に所与の関数を適用してくれる。 さっきのcalc_number関数を適用する

df["latitude_num"]=df.latitude.apply(calc_number)
df["longtitude_num"]=df.longtitude.apply(calc_number)
print(df[df["latitude_num"]>135].index)

出力

Index(['山梨県', '静岡県', '長野県', '岐阜県', '富山県', '新潟県', '石川県', '栃木県', '群馬県', '埼玉県',
       '福島県', '北海道', '山形県', '福井県', '岩手県', '東京都', '奈良県', '宮城県', '秋田県', '三重県',
       '神奈川県', '青森県', '愛知県', '和歌山県', '滋賀県', '大阪府', '茨城県', '京都府', '千葉県'],

ちゃんと西の方にある県が取り出せているよう。

イテレーションを回す

pandasはイテレーション用のメソッドを持っている。 が、なんかややこしいのでなかなか覚えられない。コチラのサイトを無限回見ている。何度もググって何度もこのページを開くのも流石にアレなので、ここにメモしておく。

DataFrameなら、下記の3種類のイテレーション方法がある

http://cdn-ak.f.st-hatena.com/images/fotolife/s/sinhrks/20150618/20150618222231.png
(StatsFragmentsより引用)

イテレーションの練習に、各都道府県の重心をプロットしてみる。*1

plt.figure(figsize=(8,8))
for key, row in df.loc[:,["longtitude_num","latitude_num"]].iterrows():
    plt.scatter(row["latitude_num"],row["longtitude_num"],
                marker="x",color="blue")

f:id:imslotter:20171204211523p:plain

日本地図っぽい点群が出てきた。

統計計算をしてみる

今回の最後に、統計計算をpandasでしてみる。 pandasでは、簡単に統計計算を行うことが出来る。例えば以下の様なものが用意されている

  • df.mean() : 平均
  • df.std() : 標準偏差
  • df.var() : 分散
  • df.min() : 最小値
  • df.max() : 最大値

全国の緯度と経度の平均を取ってみて、先程の都道府県重心プロットに重ね合わせる。どこになると思います?予想してみてください。

longtitude_mean = df["longtitude_num"].mean()
latitude_mean = df["latitude_num"].mean()
print("latitude;{:.2f}, longtitude_mean:{:.2f}".format(latitude_mean, longtitude_mean))
# >>> latitude;136.01, longtitude_mean:35.34

さっきの日本地図に重ね合わせると

f:id:imslotter:20171204212326p:plain

こんな感じ。値をgooglemapで確認すると... f:id:imslotter:20171204212724p:plain

滋賀県に!

まとめ

というわけで、よく使ったり調べたりする事柄を、まとめておいた。*2 しかし、ここに載せているのはpandasの機能のほんの一部分に過ぎない。 もともと金融データを取り扱う用に作られている*3ため、特に時系列データの取扱いは得意なようである*4。そのあたりもどこかでまとめられたらまとめる。

明日はjupyter!!

*1:pandasでもplotの関数はあるが、調べるのもめんどくさいので、matplotlibのものを使っている。

*2:10 minutes to pythonは途中で飽きたので中座。。。

*3:って書いていた気がする

*4:rolling関数とか

PROCRASIST