集計の種類
主な集計は以下です。()
内にaxis=1
と指定すれば行毎に集計することができますが、このページでは基本的に列の集計とします。
合計 | sum() |
平均 | mean() |
中央値 | median() |
最大値 | max() |
最小値 | min() |
データ数 | count() |
標準偏差 | std() |
パーセンタイル | quantile(0.9)* |
最頻値 | mode()、またはvalue_counts()* |
*別途、以下で説明します。
パーセンタイル
ディープラーニングはもちろん投資でも、異常値を外すためにパーセンタイルを使う場合があります。
パーセンタイルは統計学になるので説明は難しいですが、超簡単に言えば、最小値から数えてX%に位置する値ということです。なので例えば90%パーセンタイルを超える(簡単に言えば全体の90%を超える)データを異常値とみなして外しましょうということです。
パーセンタイルで得た値をもとに、条件式で抽出すれば異常値を切ることができます。
以下のように、全ての列、指定した列、パーセントを複数指定することができます。
df = pd.DataFrame([[90,80,70],[95,85,75],[99,89,79]], columns = ["aaa", "bbb", "ccc"]) # リスト型のデータで作成 print(df) # aaa bbb ccc # 0 90 80 70 # 1 95 85 75 # 2 99 89 79 # 全ての列 print(df.quantile(0.9)) # aaa 98.2 # bbb 88.2 # ccc 78.2 # Name: 0.9, dtype: float64 # 指定した列 print(df.aaa.quantile(0.9)) # 98.2 # パーセントを複数指定 print(df.quantile([0.9, 0.5])) # aaa bbb ccc # 0.9 98.2 88.2 78.2 # 0.5 95.0 85.0 75.0
最頻値
mode()
で最頻値を取得できます。
df = pd.DataFrame([["2020/05/01 12:34:56",1,100],["2020/05/01 16:34:56",4,98],["2020/05/02 16:34:56",4,90]], columns = ["Date Time", "bbb", "ccc"]) # リスト型のデータで作成 df['Date Time'] = pd.to_datetime(df['Date Time']) print(df) # Date Time bbb ccc # 0 2020-05-01 12:34:56 1 100 # 1 2020-05-01 16:34:56 4 98 # 2 2020-05-02 16:34:56 4 90 aaa = df['bbb'].mode() print(aaa[0]) # 0 4 print(aaa[0]) # 4
value_counts()
を利用すると出現回数を含めてデータフレームの形式で取得できます。
df = pd.DataFrame([["2020/05/01 12:34:56",1,100],["2020/05/01 16:34:56",4,98],["2020/05/02 16:34:56",4,90]], columns = ["Date Time", "bbb", "ccc"]) df['Date Time'] = pd.to_datetime(df['Date Time']) print(df) # Date Time bbb ccc # 0 2020-05-01 12:34:56 1 100 # 1 2020-05-01 16:34:56 4 98 # 2 2020-05-02 16:34:56 4 90 aaa = df['bbb'].value_counts() print(aaa) # 4 2 # 1 1 # Name: bbb, dtype: int64 print(aaa[0:1]) # 4 2 # Name: bbb, dtype: int64
最大値と最小値のインデックスを取得
集計ではないですが、最大値と最小値のインデックスを取得する方法です。
idxmax()
:最大値のインデックスを取得idxmin()
:最小値のインデックスを取得
rolling()
には使用できないので注意しましょう。
import pandas as pd df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns = ["aaa", "bbb", "ccc"]) # リスト型のデータで作成 print(df) # aaa bbb ccc # 0 1 2 3 # 1 4 5 6 # 2 7 8 9 print(df["ccc"].max()) # 9 print(df["ccc"].idxmax()) # 2 print(df["ccc"].min()) # 3 print(df["ccc"].idxmin()) # 0
行の集計
ページの冒頭で説明した通り、axis=1
を指定することにより列での集計が可能です。
import pandas as pd df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns = ["aaa", "bbb", "ccc"]) # リスト型のデータで作成 print(df) # aaa bbb ccc # 0 1 2 3 # 1 4 5 6 # 2 7 8 9 df["ddd"] = df.max(axis=1) print(df) # aaa bbb ccc ddd # 0 1 2 3 3 # 1 4 5 6 6 # 2 7 8 9 9
行で集計する列(カラム)を指定
- 対象となるカラムを
df[["aaa","bbb"]]
のように指定します。 []
が入れ子になっていますので注意してください。- 範囲での指定はできないようです。
import pandas as pd df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns = ["aaa", "bbb", "ccc"]) # リスト型のデータで作成 print(df) # aaa bbb ccc # 0 1 2 3 # 1 4 5 6 # 2 7 8 9 df["ddd"] = df[["aaa","bbb"]].max(axis=1) print(df) # aaa bbb ccc ddd # 0 1 2 3 2 # 1 4 5 6 5 # 2 7 8 9 8
集計の絞り込み
全てのデータ
df.カラム名.集計方法()
またはdf["カラム名"].集計方法()
で集計します。
df = pd.DataFrame([["2020/04/01 12:34:56",1,True],["2020/05/01 16:34:56",4,False]], columns = ["Date Time", "bbb", "ccc"]) # リスト型のデータで作成 df.index = pd.DatetimeIndex(pd.to_datetime(df['Date Time'], utc=True), name='Date Time') del df['Date Time'] print(df) # bbb ccc # Date Time # 2020-04-01 12:34:56+00:00 1 True # 2020-05-01 16:34:56+00:00 4 False print(df.bbb.sum()) # 5
条件付け
df[条件式].カラム名.集計方法()
またはdf[条件式]["カラム名"].集計方法()
で集計します。
df = pd.DataFrame([["2020/04/01 12:34:56",1,True],["2020/05/01 16:34:56",4,False]], columns = ["Date Time", "bbb", "ccc"]) # リスト型のデータで作成 df.index = pd.DatetimeIndex(pd.to_datetime(df['Date Time'], utc=True), name='Date Time') del df['Date Time'] print(df) # bbb ccc # Date Time # 2020-04-01 12:34:56+00:00 1 True # 2020-05-01 16:34:56+00:00 4 False print(df[df.index >= "2020/05/01"].bbb.sum()) # 4
複数カラム
以下のようにすれば、まとめて複数の集計が可能です。
df = pd.DataFrame([[90,80,70],[95,85,75],[99,89,79]], columns = ["aaa", "bbb", "ccc"]) # リスト型のデータで作成 print(df) # aaa bbb ccc # 0 90 80 70 # 1 95 85 75 # 2 99 89 79 print(df.agg(['min', 'max', 'sum'])) # aaa bbb ccc # min 90 80 70 # max 99 89 79 # sum 284 254 224
グループ化(グルーピング
df.groupby('カラム名').集計方法()
としてグループ化した集計ができます。
投資においては、年や月、曜日などでグループ化して集計するといいですね。
df = pd.DataFrame([["2020/05/01 12:34:56",1,True],["2020/05/01 16:34:56",4,False],["2020/05/02 16:34:56",4,False]], columns = ["Date Time", "bbb", "ccc"]) df['Date Time'] = pd.to_datetime(df['Date Time']) print(df) # Date Time bbb ccc # 0 2020-05-01 12:34:56 1 True # 1 2020-05-01 16:34:56 4 False # 2 2020-05-02 16:34:56 4 False df['week'] = df['Date Time'].dt.strftime('%a') print(df) # Date Time bbb ccc week # 0 2020-05-01 12:34:56 1 True Fri # 1 2020-05-01 16:34:56 4 False Fri # 2 2020-05-02 16:34:56 4 False Sat # 全ての列を取得 print(df.groupby('week').mean()) # bbb ccc # week # Fri 2.5 0.5 # Sat 4.0 0.0 # 指定の列のみ取得 print(df.groupby('week').bbb.mean()) # week # Fri 2.5 # Sat 4.0 # Name: bbb, dtype: float64
リサンプル
グルーピングと似ていますが、datetime
のインデックスから直接期間で集計することができます。
df.resample(rule="集計単位", label="値", closed="値").カラム名.mean()
集計単位の主な設定は以下です。集計単位は、例えば5分間隔の場合、5T
と指定できます。
D | 日 |
W | 週 |
M | 月 |
Q | 四半期 |
A | 年 |
AS | Year start |
H | 時 |
T, min | 分 |
S | 秒 |
B | Business day |
BA | Business year |
label
とclosed
でインデックスの日時を開始とするか終了とするかを指定します。
label="left"
:開始日時、label="right"
:終了日時closed="left"
:含めず、label="right"
:含める
例えば、df.resample(rule="3D", label="right", closed="right")
とした場合、「インデックスの日を終了日とし、その日も含め、3日前」という意味になります。
ちょっと難しいですね。投資のチャートの5分足なども上記のようになっていることが多いと思います。
(OandaやIB証券ではそうでした。
rule
によりlabel
とclosed
のデフォルト値が異なるので指定した方が無難です。
以下の例では、日次の平均を出力しています。
df = pd.DataFrame([["2020/05/01 12:34:56",1,100],["2020/05/01 16:34:56",4,98],["2020/05/02 16:34:56",4,90],["2020/05/02 16:34:56",5,90]], columns = ["Date Time", "bbb", "ccc"]) # リスト型のデータで作成 df.index = pd.DatetimeIndex(pd.to_datetime(df['Date Time']), name='Date Time') del df['Date Time'] print(df) # bbb ccc # Date Time # 2020-05-01 12:34:56 1 100 # 2020-05-01 16:34:56 4 98 # 2020-05-02 16:34:56 4 90 # 2020-05-02 16:34:56 5 90 print(df.resample(rule="D", label="right", closed="right").ccc.mean()) # Date Time # 2020-05-02 99 # 2020-05-03 90 # Freq: D, Name: ccc, dtype: int64
datetime
となっている必要があります。ダウンサイジング(リサンプル)1分足を5分足になど
リサンプルの応用編になるが、以下のような1分足を5分足にダウンサイジングすることが可能です。
df.resample(rule="集計単位", label="値", closed="値").agg(集計方法の連想配列)
df.resample
:期間で集計する。- 期間はリサンプルと同様です。日足を週足にする場合は、“W-Mon”とすれば週間の月曜日スタートになります。
- その他の、closedとlabelは上記のリサンプルに記載していますので確認してください。
agg
:カラムの集計方法を連想配列で設定する。
# Open High Low Close Volume # Date Time # 2019-01-01 22:00:00+00:00 109.590 109.590 109.590 109.590 1.0 # 2019-01-01 22:01:00+00:00 109.673 109.673 109.673 109.673 1.0 # 2019-01-01 22:02:00+00:00 109.673 109.673 109.673 109.673 1.0 # 2019-01-01 22:03:00+00:00 109.673 109.673 109.673 109.673 1.0 # 2019-01-01 22:04:00+00:00 109.673 109.673 109.673 109.673 1.0 agg_columns = { 'Open': 'first', 'High': 'max', 'Low': 'min', 'Close': 'last', 'Volume': 'sum' } df_resample = df.resample('5T', closed='left', label='left').agg(agg_columns) print(df_resample.head()) # Open High Low Close Volume # Date Time # 2019-01-01 22:00:00+00:00 109.590 109.673 109.590 109.673 5.0 # 2019-01-01 22:05:00+00:00 109.673 109.673 109.669 109.669 5.0 # 2019-01-01 22:10:00+00:00 109.669 109.669 109.650 109.650 11.0 # 2019-01-01 22:15:00+00:00 109.650 109.674 109.635 109.635 26.0 # 2019-01-01 22:20:00+00:00 109.635 109.654 109.616 109.651 16.0 # 実際のデータ # Date Time Open High Low Close Volume # 0 2019-01-01 22:00:00+00:00 109.590 109.673 109.590 109.673 3 # 1 2019-01-01 22:05:00+00:00 109.669 109.669 109.669 109.669 1 # 2 2019-01-01 22:10:00+00:00 109.666 109.669 109.650 109.650 6 # 3 2019-01-01 22:15:00+00:00 109.650 109.674 109.635 109.635 14 # 4 2019-01-01 22:20:00+00:00 109.630 109.654 109.616 109.651 13
集計が間違っているのではなく、ダウンロードした会社の集計方法が少し異なっているのだと思います。
投資の解析を行う場合は、特にシストレの場合は、実際に取得したデータで解析した方がいいと思います。
理由は、シストレの場合、リアルタイムでデータを取得することになりますが、その際、足データもその会社から取得することになります。誤差も含めて指標となる数値の解析をしてもデータが異なっては意味がありません。ですから、シストレで取得するデータで分析した方がいいですね。
四本値(始値、高値、安値、終値)OHLC
リサンプルでohlc
を使用すると簡単に四本値を求めることができます。
df.resample(rule="集計単位", label="値", closed="値").カラム名.ohlc()
以下の例は、あまりよくないですが、1分の価格だけある場合、それを5分足の四本値に変換しています。
実際はティックデータを1分足にするなどに利用できるかと思います。
出来高はsumで集計して追加するしか方法はないです。
これも同様に週足や月足などで集計が可能です。
# Price Volume # Date Time # 2019-01-01 22:00:00+00:00 109.590 1.0 # 2019-01-01 22:01:00+00:00 109.673 1.0 # 2019-01-01 22:02:00+00:00 109.673 1.0 # 2019-01-01 22:03:00+00:00 109.673 1.0 # 2019-01-01 22:04:00+00:00 109.673 1.0 df_ohlc = df.resample('5T', closed='left', label='left').Price.ohlc() print(df_ohlc.head()) # open high low close # Date Time # 2019-01-01 22:00:00+00:00 109.590 109.673 109.590 109.673 # 2019-01-01 22:05:00+00:00 109.673 109.673 109.669 109.669 # 2019-01-01 22:10:00+00:00 109.669 109.669 109.664 109.664 # 2019-01-01 22:15:00+00:00 109.650 109.670 109.635 109.635 # 2019-01-01 22:20:00+00:00 109.635 109.651 109.630 109.651 df_ohlc["volume"] = df.resample('5T', closed='left', label='left').Volume.sum() print(df_ohlc.head()) # open high low close volume # Date Time # 2019-01-01 22:00:00+00:00 109.590 109.673 109.590 109.673 5.0 # 2019-01-01 22:05:00+00:00 109.673 109.673 109.669 109.669 5.0 # 2019-01-01 22:10:00+00:00 109.669 109.669 109.664 109.664 11.0 # 2019-01-01 22:15:00+00:00 109.650 109.670 109.635 109.635 26.0 # 2019-01-01 22:20:00+00:00 109.635 109.651 109.630 109.651 16.0
集計の範囲
全体ではなく、一部分のデータを対象に集計します。条件式ではなく、その集計データを新たな列(カラム)として利用します。例えば、投資では移動平均線なんかに利用できます。
df.カラム名.rolling(データ数).集計方法()
データ数は対象行を含むデータ数となります。
df = pd.DataFrame([["2020/05/01 12:34:56",1,100],["2020/05/01 16:34:56",4,98],["2020/05/02 16:34:56",4,90],["2020/05/02 16:34:56",5,90]], columns = ["Date Time", "bbb", "ccc"]) # リスト型のデータで作成 df['Date Time'] = pd.to_datetime(df['Date Time']) print(df) # Date Time bbb ccc # 0 2020-05-01 12:34:56 1 100 # 1 2020-05-01 16:34:56 4 98 # 2 2020-05-02 16:34:56 4 90 # 3 2020-05-02 16:34:56 5 90 df["mean"] = df.ccc.rolling(2).mean() print(df) # Date Time bbb ccc mean # 0 2020-05-01 12:34:56 1 100 NaN # 1 2020-05-01 16:34:56 4 98 99.0 # 2 2020-05-02 16:34:56 4 90 94.0 # 3 2020-05-02 16:34:56 5 90 90.0
ピポットテーブル
pd.pivot_table(df, index="ラベル名", columns="ラベル名", values="ラベル名", aggfunc="集計方法")
index
:行(集計のインデックスのグルーピングcolumns
:列(集計のカラムのグルーピングvalues
:集計対象aggfunc
:集計方法
df = pd.DataFrame( [["2020/05/01 12:34:56",1,"x",100], ["2020/05/01 16:34:56",4,"y",98], ["2020/05/02 16:34:56",4,"x",90], ["2020/05/02 16:34:56",5,"y",90]], columns = ["Date Time", "aaa", "bbb", "ccc"] ) df.index = pd.DatetimeIndex(pd.to_datetime(df['Date Time']), name='Date Time') del df['Date Time'] print(df) # aaa bbb ccc # Date Time # 2020-05-01 12:34:56 1 x 100 # 2020-05-01 16:34:56 4 y 98 # 2020-05-02 16:34:56 4 x 90 # 2020-05-02 16:34:56 5 y 9 print(pd.pivot_table(df, index="aaa", columns="bbb", values="ccc", aggfunc="mean")) # bbb x y # aaa # 1 100.0 NaN # 4 90.0 98.0 # 5 NaN 90.0
pd.pivot_table
はdf.pivot_table
ではなく、( )
内に対象のデータフレームとなるdf
を指定します。分析
ユニークな値
ユニークな値の一覧
これは投資でも使えますね。例えば1分足のデータから営業日を出すときに、日時データを日付のみを取り出して、その日付のユニークな一覧を出せば、営業日の一覧となります。
df = pd.DataFrame([[1,2,3],[4,5,6],[4,5,6]], columns = ["aaa", "bbb", "ccc"]) print(data) # [[1 2 3] # [4 5 6]] print(df['aaa'].unique()) # [1 4]
ユニークな値の出現回数
df = pd.DataFrame([[1,2,3],[4,5,6],[4,5,6]], columns = ["aaa", "bbb", "ccc"]) print(data) # [[1 2 3] # [4 5 6]] print(df['aaa'].value_counts()) # 4 2 # 1 1
ユニークな値の個数
これは投資でも使いますね。例えば1分足のデータから営業日数を出すときに、日時データを日付のみを取り出して、その日付のユニークな個数を出せば、営業日数がわかります。
df = pd.DataFrame([[1,2,3],[4,5,6],[4,5,6]], columns = ["aaa", "bbb", "ccc"]) print(data) # [[1 2 3] # [4 5 6]] print(df['aaa'].nunique()) # 2
最大値・最小値のインデックスとカラム名を取得
投資では案外利用します。最大値や最小値の日時(インデックス)を取得するのに便利です。カラム名の取得はあまり使うことはないかも知れませんが。
- 最大値:
df.カラム名.idxmax()
*idxmax(axis=1)
とすればカラム名を取得 - 最小値:
df.カラム名.idxmin()
*idxin(axis=1)
とすればカラム名を取得
df = pd.DataFrame([["2020/05/01 12:34:56",1,2,3],["2020/05/02 12:34:56",4,5,6],["2020/05/03 12:34:56",7,8,9]], columns = ["DateTime", "aaa", "bbb", "ccc"]) df.index = pd.DatetimeIndex(pd.to_datetime(df['DateTime']), name='DateTime') del df['DateTime'] print(df) # aaa bbb ccc # DateTime # 2020-05-01 12:34:56 1 2 3 # 2020-05-02 12:34:56 4 5 6 # 2020-05-03 12:34:56 7 8 9 print(df.aaa.idxmax()) # 2020-05-03 12:34:56 print(df.aaa.idxmin()) # 2020-05-01 12:34:56 print(df.idxmax(axis=1)) # 2020-05-03 12:34:56 # DateTime # 2020-05-01 12:34:56 ccc # 2020-05-02 12:34:56 ccc # 2020-05-03 12:34:56 ccc # dtype: object print(df.idxmin(axis=1)) # 2020-05-01 12:34:56 # DateTime # 2020-05-01 12:34:56 aaa # 2020-05-02 12:34:56 aaa # 2020-05-03 12:34:56 aaa # dtype: object
応用
一定の期間の最大値(または最小値)のインデックスを取得する場合は以下のとおりです。
ループしているので処理は遅くなります。
for index, row in df.iterrows(): df[index-10:index]['aaa'].idxmax()
相関係数(相関性
投資ではよく相関性が議論されます。その相関性を簡単にチェックすることができます。
以下のように相関性はNumpy
ですが、Pandas
と組み合わせて使うので本ページで紹介します。
np.corrcoef(列1, 列2)[0, 1]
とするだけです。[0, 1]
としているのはおまじないだと思ってください。
df = pd.DataFrame([["2020/05/01 12:34:56",1,100],["2020/05/01 16:34:56",4,98],["2020/05/02 16:34:56",4,90]], columns = ["Date Time", "bbb", "ccc"]) df['Date Time'] = pd.to_datetime(df['Date Time']) print(df) # Date Time bbb ccc # 0 2020-05-01 12:34:56 1 100 # 1 2020-05-01 16:34:56 4 98 # 2 2020-05-02 16:34:56 4 90 aaa = np.corrcoef(df.bbb, df.ccc)[0, 1] print(aaa) # -0.6546536707079772
コメント