python§03:データ分析ライブラリーpandasを徹底解説します

Python基礎

pandasとは何か?

pandasというのは、pythonでデータ分析をするためのライブラリーの名前です。

二次元データ(エクセルの表のようなもの)をエクセル以上のパフォーマンスの高い処理ができる非常に優れた機能をもっているのがpandasです。

例えば、1000万行のデータをエクセルでグラフなど描こうとすれば、固まってしまうでしょう。ところが、pythonで処理をすれば、びっくりするくらい軽快にグラフが表示されることに驚くと思います。それでは、pandasがどのようなものか、触れていきましょう。

csvファイルを準備する

pandasには、データフレームシリーズという二つの構造があります。データフレームが二次元データで、シリーズは一次元データです。ほとんどのデータ解析はデータフレームを使いますので、二次元データをまず、読み込んでみましょう。

エクセルでこのような表があったとします。

A列には、行の名前を示した「インデックス

1行目には、Data1、Data2、Data3という具合に列名が示されています

そして、11~33のデータが二次元的に配置しています。

これをCSVファイル(カンマで区切られたファイル)として保存します。

このファイル名をdata.csvとします。

また、タブ区切りでも保存しておきましょう。(tsvファイルということもあります)

このファイル名をdata.tsvとします。

どちらのファイルも内容は同じです。

CSV、TSVファイルをpandasで読み込む方法

以下のソースコードを説明していきます。

import pandas as pd
filename='data.csv'
df=pd.read_csv(filename,index_col=0)

print('csv filename={}'.format(filename))
print(r"command:df2=pd.read_csv(filename,index_col=0)")
print(df)

print('--------------------------------')
filename='data.tsv'

df2=pd.read_csv(filename,index_col=0,sep='\t')

print('tsv filename={}'.format(filename))
print(r"command:df2=pd.read_csv(filename,index_col=0,sep='\t')")
print(df2)

a=input()

まず1行目:pandasライブラリーをインポートして、pdという省略名で使えるようにします。

import pandas as pd

 

2行目:ファイル名をfilenameという変数に格納しておきます

3行目:pandasの機能であるread_csvメソッドを呼び出します。

filename='data.csv'
df=pd.read_csv(filename,index_col=0)

ここでは、index_col=0として、1列目をインデックスとして指定しています。もしこのindex_colを指定しないと、データ列として認識されます。

5行目から9行目は読込んだデータフレームdfの表示を含めて、理解しやすいようにファイル名、コマンド、dfの内容を表示させています。

print('csv filename={}'.format(filename))
print(r"command:df2=pd.read_csv(filename,index_col=0)")
print(df)

print('--------------------------------')

10行目から16行目までは、同じようにtsvファイルに対して実行しています。

filename='data.tsv'

df2=pd.read_csv(filename,index_col=0,sep='\t')

print('tsv filename={}'.format(filename))
print(r"command:df2=pd.read_csv(filename,index_col=0,sep='\t')")
print(df2)

12行目を見てみると、

sep='\t'

というオプションで、区切り文字がタブであることを教えています。

実行結果は以下のようになります

 

csv filename=data.csv
command:df2=pd.read_csv(filename,index_col=0)
      Data1  Data2  Data3
ROW1     11     12     13
ROW2     21     22     23
ROW3     31     32     33
--------------------------------
tsv filename=data.tsv
command:df2=pd.read_csv(filename,index_col=0,sep='\t')
      Data1  Data2  Data3
ROW1     11     12     13
ROW2     21     22     23
ROW3     31     32     33

 

さきほどのindex_colを設定しない場合の表示例も参考まで載せると、以下のようにROW1以下データ列となっています。
列名はUnnamed: 0となっています。そして、一番左端にある0,1,2というのが、インデックスとなっています。このようにインデックスがないデータも多くあります。

ここでは、インデックスは行名を設定することもできるし、行番号(0始まり)を設定することもできると理解しておいてください。

csv filename=data.csv
command:df2=pd.read_csv(filename,index_col=0)
  Unnamed: 0  Data1  Data2  Data3
0       ROW1     11     12     13
1       ROW2     21     22     23
2       ROW3     31     32     33
--------------------------------

 

データフレームの構造を知る .shape

 

import pandas as pd

filename='data.csv'
df=pd.read_csv(filename,index_col=0)

print('csv filename={}'.format(filename))
print(r"command:df2=pd.read_csv(filename,index_col=0)")
print(df)

print(df.shape)

a=input()

 

10行目のdf.shapeを表示させると

(3,3)

と3行、3列のデータであることがわかります。

列名を表示させる .columns

 

import pandas as pd

filename='data.csv'
df=pd.read_csv(filename,index_col=0)

print('csv filename={}'.format(filename))
print(r"command:df2=pd.read_csv(filename,index_col=0)")
print(df)

#print(df.shape)
print(df.columns)

a=input()

10行目にあるdf.columnsによって、列名をリストとして返します

Index([‘Data1’, ‘Data2’, ‘Data3′], dtype=’object’)

これはリストなので、for文を使って、取り出すこともできます。

 

import pandas as pd

filename='data.csv'
df=pd.read_csv(filename,index_col=0)

print('csv filename={}'.format(filename))
print(r"command:df2=pd.read_csv(filename,index_col=0)")
print(df)

#print(df.shape)
#print(df.columns)

for i,r in enumerate(df.columns):
    print(i,r)

a=input()

13行目から14行目にかけて、df.colmunsの中身を表示しています。

enumerateを使えば、連番も表示できるようになります。

0 Data1
1 Data2
2 Data3

各列のデータ型を調べる .types

 

import pandas as pd

filename='data.csv'
df=pd.read_csv(filename,index_col=0)

print('csv filename={}'.format(filename))
print(r"command:df2=pd.read_csv(filename,index_col=0)")
print(df)

#print(df.shape)
#print(df.columns)

#for i,r in enumerate(df.columns):
#    print(i,r)

print(df.dtypes)

a=input()



16行目のdf.dtypesによって、各行のpandasの型pythonの型ではないことに注意

を取得できます。

Data1 int64
Data2 int64
Data3 int64

のように3列ともint64となっています。

pandasのデータ型は以下のとおりです。( )内はpythonの型を示します。

pandasの型(pythonの型)

object   (string)

int64    (int)

float64   (float)

datetime  (datetime) ※このデータを扱うには、datetimeライブラリーをインポートすること

データの詳しい情報を知る .info()

print(df.info())により、詳しいデータの情報が得られます。

コードは省略しますが、以下のような出力となります。すべての列に3個のデータがあり、欠損がない、int64型の情報であることを示しています。

0 Data1 3 non-null int64
1 Data2 3 non-null int64
2 Data3 3 non-null int64

列を抽出する方法 df[‘列名’]

データフレーム名のあとに[‘列名’]とすれば、列を抽出することができます。

下記の例では、Data1の列はd1という変数に取り出しています。

import pandas as pd

filename='data.csv'
df=pd.read_csv(filename,index_col=0)

print('csv filename={}'.format(filename))
print(r"command:df2=pd.read_csv(filename,index_col=0)")
print(df)

#print(df.shape)
#print(df.columns)

#for i,r in enumerate(df.columns):
#    print(i,r)

#print(df.dtypes)
#print(df.info())

d1=df['Data1']
d2=df['Data2']
d3=df['Data3']

print('----Data1--------')
print(d1.head())
print('----Data2--------')
print(d2.head())
print('----Data3--------')
print(d3.head())
print('------------')
a=input()



表示結果は、以下のようになります。単にデータだけを表示しているのではなく、インデックスとともに表示されています。

csv filename=data.csv
command:df2=pd.read_csv(filename,index_col=0)
Data1 Data2 Data3
ROW1 11 12 13
ROW2 21 22 23
ROW3 31 32 33
—-Data1——–
ROW1 11
ROW2 21
ROW3 31
Name: Data1, dtype: int64
—-Data2——–
ROW1 12
ROW2 22
ROW3 32
Name: Data2, dtype: int64
—-Data3——–
ROW1 13
ROW2 23
ROW3 33
Name: Data3, dtype: int64
————

行の抽出 loc (インデックスを使う)

行を抽出するにはlocを使います。

import pandas as pd

filename='data.csv'
df=pd.read_csv(filename,index_col=0)

print('csv filename={}'.format(filename))
print(r"command:df2=pd.read_csv(filename,index_col=0)")
print(df)
print('-----ROW1--------------------------')

print(df.loc['ROW1'])
print('-----ROW2--------------------------')
print(df.loc['ROW2'])
print('-----ROW3--------------------------')
print(df.loc['ROW3'])
print('-------------------------------')


a=input()

表示結果は、以下のとおりです。それぞれの行の3つの列のデータが表示されています。

csv filename=data.csv
command:df2=pd.read_csv(filename,index_col=0)
Data1 Data2 Data3
ROW1 11 12 13
ROW2 21 22 23
ROW3 31 32 33
—–ROW1————————–
Data1 11
Data2 12
Data3 13
Name: ROW1, dtype: int64
—–ROW2————————–
Data1 21
Data2 22
Data3 23
Name: ROW2, dtype: int64
—–ROW3————————–
Data1 31
Data2 32
Data3 33
Name: ROW3, dtype: int64
——————————-

行の抽出 iloc (行番号を使う)

locでは、インデックスを使いましたが、ilocという行番号を使う方法もあります。

import pandas as pd

filename='data.csv'
df=pd.read_csv(filename,index_col=0)

print('csv filename={}'.format(filename))
print(r"command:df2=pd.read_csv(filename,index_col=0)")
print(df)
print('-----1行目--------------------------')

print(df.iloc[0])
print('-----2行目--------------------------')
print(df.iloc[1])
print('-----3行目--------------------------')
print(df.iloc[2])
print('-------------------------------')


a=input()


 

表示結果は、以下のとおりで、locを使った場合と同じです。

csv filename=data.csv
command:df2=pd.read_csv(filename,index_col=0)
Data1 Data2 Data3
ROW1 11 12 13
ROW2 21 22 23
ROW3 31 32 33
—–1行目————————–
Data1 11
Data2 12
Data3 13
Name: ROW1, dtype: int64
—–2行目————————–
Data1 21
Data2 22
Data3 23
Name: ROW2, dtype: int64
—–3行目————————–
Data1 31
Data2 32
Data3 33
Name: ROW3, dtype: int64
——————————-

このilocはスライスを使うことができるので便利です。

例えば、

2行目から最後までなら df.iloc[1:]

最終行を取り出すなら df.iloc[-1]

1行目から2行目なら  df.iloc[0:2]

のようにできます。

pandas実践練習(実際の株価データを使って実践)

株価データをダウンロード

株価データで実践練習してみましょう。次の記事も参考してください:カスタム関数 株価ダウンロード

株価をダウンロードする関数のコードは以下のとおりです。

from pandas_datareader import data  
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import datetime

def read_stockdata(code='7203.JP',start='2015-01-01',end='2020-07-25',graph=True):  # ■株データダウンロード_stooq_J725
    df=data.DataReader(code,'stooq',start,end)
    df=df.sort_index()  #indexの日付をソートする
    
    if graph:
        date=df.index
        price=df['Close']
        plt.figure(figsize=(30,10))

        span01=5
        span02=25
        span03=75
        df['sma05']=price.rolling(window=span01).mean()
        df['sma25']=price.rolling(window=span02).mean()
        df['sma30']=price.rolling(window=span03).mean()

        plt.plot(date,price,label='7203',lw=5)
        plt.plot(date,df['sma05'],label='sma05')
        plt.plot(date,df['sma25'],label='sma25')
        plt.plot(date,df['sma30'],label='sma75')
        plt.title(code,color='blue',backgroundcolor='white',size=40,loc='center')
        plt.xlabel('date',color='black',size=30)
        plt.ylabel('price',color='black',size=30)
        plt.grid()
        plt.legend()
        
        plt.plot(date,price)
        plt.show()
    return df

引数の設定をします。

codeにトヨタ自動車の7203.JPを入れます。

startは2020-07-01

endは2020-07-30

graphはFalseにしてグラフ表示はなしにします。

def read_stockdata(code='7203.JP',start='2020-07-01',end='2020-07-30',graph=False)

この関数の戻り値は、pandasのDataFrameが返ってきます。

株価をダウンロードしてみましょう。

#!pip install pandas_datareader
from pandas_datareader import data
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import datetime

def read_stockdata(code='7203.JP',start='2015-01-01',end='2020-07-25',graph=True): # ■株データダウンロード_stooq_J725

df=data.DataReader(code,'stooq',start,end)
df=df.sort_index() #indexの日付をソートする

if graph:
date=df.index
price=df['Close']
plt.figure(figsize=(30,10))

span01=5
span02=25
span03=75
df['sma05']=price.rolling(window=span01).mean()
df['sma25']=price.rolling(window=span02).mean()
df['sma30']=price.rolling(window=span03).mean()

plt.plot(date,price,label='7203',lw=5)
plt.plot(date,df['sma05'],label='sma05')
plt.plot(date,df['sma25'],label='sma25')
plt.plot(date,df['sma30'],label='sma75')
plt.title(code,color='blue',backgroundcolor='white',size=40,loc='center')
plt.xlabel('date',color='black',size=30)
plt.ylabel('price',color='black',size=30)
plt.grid()
plt.legend()

plt.plot(date,price)
plt.show()

return df

#■メインプログラム
if __name__ == '__main__':

#code:銘柄コード番号.JP の書式文字列を設定する
code='7203.JP'
#start:株価データの先頭期日
start='2020-07-01'
#end:株価データの最終期日
end='2020-07-30'

print(code,start ,end)
df=read_stockdata(code,start,end,graph=False)

print(df.head(10))

a=input('何かキーを押してください')

head()を使って表示させています。

print(df.head(10))

この例では、取得した株価データの10個分のデータを表示させています。以下は実行結果です。

【結果】

7203.JP 2020-07-01 2020-07-30
            Open  High   Low  Close   Volume
Date
2020-07-01  6760  6775  6643   6656  5028200
2020-07-02  6671  6821  6662   6777  5674100
2020-07-03  6776  6790  6713   6761  3843700
2020-07-06  6805  6859  6768   6859  4135000
2020-07-07  6860  6864  6748   6770  4395200
2020-07-08  6769  6819  6726   6728  4673400
2020-07-09  6700  6757  6681   6709  4001700
2020-07-10  6665  6673  6568   6568  6646300
2020-07-13  6675  6771  6618   6762  5240900
2020-07-14  6696  6793  6695   6744  4133600

最新の10個のデータを抽出 iloc

ilocを使って、最新、つまり最後の10個のデータを取り出してみましょう。

print(df.iloc[-10:,:])
【結果】
            Open  High   Low  Close   Volume
Date
2020-07-15  6800  6870  6795   6835  4753600
2020-07-16  6799  6859  6768   6790  5388600
2020-07-17  6815  6858  6806   6813  3214800
2020-07-20  6785  6827  6770   6794  2558600
2020-07-21  6830  6840  6756   6775  4080800
2020-07-22  6775  6809  6729   6729  3522200
2020-07-27  6633  6748  6631   6737  5116400
2020-07-28  6676  6706  6620   6636  4743800
2020-07-29  6561  6578  6433   6433  6465500
2020-07-30  6509  6523  6418   6435  4552600

列を指定して抽出する iloc

次は、列を抽出してみましょう。始値Openと終値Closeだけを取り出します。

Openは最初の列なので0番 Closeは4つ目なので3番を指定します。注意すべきは、列のところでリストとして与えていることです。
つまり、[0,3]のように[ ]でくくります。

print(df.iloc[-10:,[0,3]])
【結果】
            Open  Close
Date
2020-07-15  6800   6835
2020-07-16  6799   6790
2020-07-17  6815   6813
2020-07-20  6785   6794
2020-07-21  6830   6775
2020-07-22  6775   6729
2020-07-27  6633   6737
2020-07-28  6676   6636
2020-07-29  6561   6433
2020-07-30  6509   6435

うまく列を指定して取り出せましたね。

インデックス(行名)を指定して取り出す loc

locを使うと、インデックスを使ったり、列名を指定してデータを抽出することができましたね。

7月20日~7月22日までのデータを取り出してみます。このときも列はOpenとCloseにします。
ここで注意すべき点は、スライスのように使っていますが、7月20日と7月22日を指定していることです。Pythonのスライスでは終点は含まれなかったですよね。

print(df.loc["2020-07-20":"2020-07-22",["Open","Close"]])

 

【結果】
            Open  Close
Date
2020-07-20  6785   6794
2020-07-21  6830   6775
2020-07-22  6775   6729

 平均、最大、最小を計算する .mean() .max() .min()

pandasでは、統計計算も簡単にできます。フレームデータをdfとすると

求めたい列データの列名がCloseとすると

平均値→ df[‘Close’].mean()

最大値→ df[‘Close’].max()

最小値→ df[‘Close’].min()

として求めることができます。

    print("Code   :{}".format(code[0:4])) 
    print("Average:{}".format(df["Close"].mean()))
    print("max    :{}".format(df["Close"].max()))
    print("min    :{}".format(df["Close"].min()))
【結果】
Code   :7203
Average:6715.55
max    :6859
min    :6433

最大値、最小値のデータの日付(行名)を求める

それでは、終値(Close)が最大値や最小値をつけたデータを抽出してみましょう。
少し複雑な形になってきましたが、==で結んだ部分が条件を示しています。

    print(df.loc[df['Close']==df['Close'].max()])
    print(df.loc[df['Close']==df['Close'].min()])
【結果】
            Open  High   Low  Close   Volume
Date
2020-07-06  6805  6859  6768   6859  4135000
            Open  High   Low  Close   Volume
Date
2020-07-29  6561  6578  6433   6433  6465500

抽出できましたが、形式がフレームデータとなっていますので、日付形式で取り出すことをやってみましょう。
.index[0]とすることで、リストではなく単独の日付を取り出すことができます。

    print((df.loc[df['Close']==df['Close'].max()]).index[0])
    print((df.loc[df['Close']==df['Close'].min()]).index[0])
【結果】
2020-07-06 00:00:00
2020-07-29 00:00:00

しかし、まだ時刻のところが気に入りません。年月日だけの形式になおしてみましょう。
式が長くなるので、いったん、index_maxとindex_minという変数に格納してから、書式を変更しています。

    index_max=(df.loc[df['Close']==df['Close'].max()]).index[0]
    index_min=(df.loc[df['Close']==df['Close'].min()]).index[0]
    print(index_max.strftime("%Y-%m-%d"))
    print(index_min.strftime("%Y-%m-%d"))
【結果】
2020-07-06
2020-07-29

今度は、うまく年月日の文字列を表示できました。

一連のテストコード

上記の一連のテストを行ったテストコードをまとめておきます。pandasのデータフレームの取り扱いは、多岐にわたっており、書式などすぐに忘れるので、この記事は忘備録として活用できそうですね。

#!pip install pandas_datareader
from pandas_datareader import data  
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import datetime

def read_stockdata(code='7203.JP',start='2015-01-01',end='2020-07-25',graph=True):  # ■株データダウンロード_stooq_J725

    df=data.DataReader(code,'stooq',start,end)
    df=df.sort_index()  #indexの日付をソートする
    
    if graph:
        date=df.index
        price=df['Close']
        plt.figure(figsize=(30,10))

        span01=5
        span02=25
        span03=75
        df['sma05']=price.rolling(window=span01).mean()
        df['sma25']=price.rolling(window=span02).mean()
        df['sma30']=price.rolling(window=span03).mean()

        plt.plot(date,price,label='7203',lw=5)
        plt.plot(date,df['sma05'],label='sma05')
        plt.plot(date,df['sma25'],label='sma25')
        plt.plot(date,df['sma30'],label='sma75')
        plt.title(code,color='blue',backgroundcolor='white',size=40,loc='center')
        plt.xlabel('date',color='black',size=30)
        plt.ylabel('price',color='black',size=30)
        plt.grid()
        plt.legend()
        
        plt.plot(date,price)
        plt.show()

    return df

#■メインプログラム
if __name__  == '__main__':

    #code:銘柄コード番号.JP の書式文字列を設定する
    code='7203.JP'
    #start:株価データの先頭期日
    start='2020-07-01'
    #end:株価データの最終期日
    end='2020-07-30'

    print(code,start ,end)
    df=read_stockdata(code,start,end,graph=False)

    print(df.head(10))
    
    print(df.iloc[-10:,:])

    print(df.iloc[-10:,[0,3]])
    
    print(df.loc["2020-07-20":"2020-07-22",["Open","Close"]])
    
    print(df.dtypes)
    
    print("Code   :{}".format(code[0:4])) 
    print("Average:{}".format(df["Close"].mean()))
    print("max    :{}".format(df["Close"].max()))
    print("min    :{}".format(df["Close"].min()))
    
    print(df.loc[df['Close']==df['Close'].max()])
    print(df.loc[df['Close']==df['Close'].min()])
    
    print((df.loc[df['Close']==df['Close'].max()]).index[0])
    print((df.loc[df['Close']==df['Close'].min()]).index[0])
    
    index_max=(df.loc[df['Close']==df['Close'].max()]).index[0]
    index_min=(df.loc[df['Close']==df['Close'].min()]).index[0]
    print(index_max.strftime("%Y-%m-%d"))
    print(index_min.strftime("%Y-%m-%d"))

    a=input('何かキーを押してください')

コメント

タイトルとURLをコピーしました