集計の種類
主な集計は以下です。()内に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

コメント