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('何かキーを押してください')
コメント