🐈

Act 06. Pythonでデータ処理を行う

2024/10/25に公開

はじめに

Act 01. AIで外国為替を自動売買するまでの道のりをベースに学習を進めて行く。

Pythonを用いて機械学習を行う場合、データの前処理が必要らしい。
Pythonではデータ処理を行うための様々なライブラリが提供されている。

結構なボリュームになりそうだが挫けずに勉強しようと思う。

そもそも何を勉強すれば良いか分からないため、ChatGPTさんに質問してみた。
どうやら為替などの時系列データを扱う場合は以下を学んだ方がよいらしい。

以下、ChatGPTさんの回答

  1. Pandas
    時系列データの前処理において最も一般的なライブラリです。データのクリーニング、欠損値の処理、リサンプリング、データの結合やフィルタリングなど、多くの機能を提供しています。

  2. NumPy
    数値計算を効率的に行うための基盤ライブラリで、配列操作や数学的な計算が必要な場合に役立ちます。Pandasと組み合わせて使うことが多いです。

  3. Feature-engine
    特徴量エンジニアリングに特化したライブラリです。データの変換やエンコーディング、スケーリング、フィルタリングなど、機械学習の準備をスムーズに行うことができます。

  4. Scikit-learn
    データ前処理のためのツールも豊富です。データのスケーリング、エンコーディング、特徴選択、交差検証など、機械学習のためのデータ準備が行えます。

  5. Dask
    大規模データを扱う場合、Pandasに似たAPIを持ちながら並列処理をサポートしているため、メモリに収まらないデータの前処理に役立ちます。

  6. Category Encoders
    カテゴリカルデータのエンコーディングに特化したライブラリで、様々なエンコーディング手法を提供しています。これにより、モデルへの入力データを整形する際に便利です。

まとめ
データの前処理には、PandasとNumPyが基本ですが、特定のニーズに応じてFeature-engineやScikit-learn、Daskを組み合わせて使うと、より効率的にデータを整形できます。データの性質に応じて最適なツールを選ぶと良いでしょう。

なるほど、全くわからないがとりあえず基本と言われているNumPyPandasを学ぼうかな。
それ以外のライブラリについては必要に応じて学ぼうと思う。

ここでは時系列データの学習に使える便利なライブラリが、後4つは存在しているということだけ覚えておく。未来の自分が躓いた時に勉強してくれるだろう。

NumPy

まずはNumPyから。
と思ったけど、NumPyは数学を学んでからの方がいい気がしてきた。

NumPyはPythonで数値計算を行うためのライブラリらしい。
N次元配列や算術演算や三角関数、指数関数、対数関数、線形代数など。。

しっかりと理解しながら進めて行きたいからここでは一旦スキップ。
NumPyが見たくてこの記事にたどり着いた人には大変申し訳ない。

けどこのシリーズの記事は自分の日記や備忘録のために載せてるんだ。。
「数学の知識がない状態でNumPyに手を出すのはやめた方がいい」という考えになったことをここに残しておく。

Act01で立てた予定通りにはいかないもんだね。面白い

Pandas

Pandasは、Pythonでデータ操作や分析を行うための強力なライブラリらしい。
少し調べてみたが、表とかを操作するようなイメージだった。
こっちは数学とかあまり関係なさそうだからこのタイミングで学習を進めようと思う。

まずは実際に使うとしたらどういう感じになるかイメージしてみる。
ぱっと思いついたのは以下。

  • APIで為替のJSONデータを上手く使う(よくわかっていないので曖昧な表現)
  • 取得したデータから新たなデータを計算して追加したい(移動平均線を計算するイメージ)
  • MAX、MIN、AVEを取得したい
  • 時間指定でデータを取得したい

とりあえずこんな内容で学習を進めて行く。
やっている途中で気づいたことがあったら追記するかも。

【追記】
思いついたことを全部試している。かなり長い記事になってるから心して読んでね。

JSONの読み込みと変換

ChatGPTさんに頼んで以下のデータを作ってもらった。
これは1時間分の5分足データで、日時 / 始値 / 高値 / 安値 / 終値 / ボリュームのデータが存在する。

5min_data.json
[
  {"timestamp": "2024-10-25T10:00:00Z", "open": 1.1000, "high": 1.1020, "low": 1.0990, "close": 1.1010, "volume": 1000},
  {"timestamp": "2024-10-25T10:05:00Z", "open": 1.1010, "high": 1.1030, "low": 1.1000, "close": 1.1025, "volume": 1100},
  {"timestamp": "2024-10-25T10:10:00Z", "open": 1.1025, "high": 1.1040, "low": 1.1015, "close": 1.1035, "volume": 1050},
  {"timestamp": "2024-10-25T10:15:00Z", "open": 1.1035, "high": 1.1050, "low": 1.1025, "close": 1.1045, "volume": 950},
  {"timestamp": "2024-10-25T10:20:00Z", "open": 1.1045, "high": 1.1060, "low": 1.1035, "close": 1.1055, "volume": 980},
  {"timestamp": "2024-10-25T10:25:00Z", "open": 1.1055, "high": 1.1070, "low": 1.1045, "close": 1.1065, "volume": 1000},
  {"timestamp": "2024-10-25T10:30:00Z", "open": 1.1065, "high": 1.1080, "low": 1.1055, "close": 1.1075, "volume": 1200},
  {"timestamp": "2024-10-25T10:35:00Z", "open": 1.1075, "high": 1.1090, "low": 1.1065, "close": 1.1085, "volume": 1150},
  {"timestamp": "2024-10-25T10:40:00Z", "open": 1.1085, "high": 1.1100, "low": 1.1075, "close": 1.1095, "volume": 1100},
  {"timestamp": "2024-10-25T10:45:00Z", "open": 1.1095, "high": 1.1110, "low": 1.1085, "close": 1.1100, "volume": 1050},
  {"timestamp": "2024-10-25T10:50:00Z", "open": 1.1100, "high": 1.1120, "low": 1.1090, "close": 1.1110, "volume": 1200},
  {"timestamp": "2024-10-25T10:55:00Z", "open": 1.1110, "high": 1.1130, "low": 1.1100, "close": 1.1120, "volume": 1250}
]

まずはJSONファイルを読み込む方法を調べた。
PandasでJSONファイルを読み込む方法もあるっぽいけど、実際はそんな使い方をしない。

恐らくだが、requestsライブラリを使いAPIを呼び出して為替データを取得すると思う。
つまり、一度に一つの時間のデータ(X時Y分Z秒)しか取得することが出来ない。

ということで、今回はJSONファイルを1行ずつ読み込み、順に処理を行うようにしてみようと思う。
まずはファイルを読み込まないと話にならない。

Act06.py
import json

with open("5min_data.json") as f:
  data = json.load(f)
  print(data)

これでうまく読み込めた。
実行すると以下の出力。どうやら全行読み込んでしまった。

[{'timestamp': '2024-10-25T10:00:00Z', 'open': 1.1, 'high': 1.102, 'low': 1.099, 'close': 1.101, 'volume': 1000}, {'timestamp': '2024-10-25T10:05:00Z', 'open': 1.101, 'high': 1.103, 'low': 1.1, 'close': 1.1025, 'volume': 1100}, {'timestamp': '2024-10-25T10:10:00Z', 'open': 1.1025, 'high': 1.104, 'low': 1.1015, 'close': 1.1035, 'volume': 1050}, {'timestamp': '2024-10-25T10:15:00Z', 'open': 1.1035, 'high': 1.105, 'low': 1.1025, 'close': 1.1045, 'volume': 950}, {'timestamp': '2024-10-25T10:20:00Z', 'open': 1.1045, 'high': 1.106, 'low': 1.1035, 'close': 1.1055, 'volume': 980}, {'timestamp': '2024-10-25T10:25:00Z', 'open': 1.1055, 'high': 1.107, 'low': 1.1045, 'close': 1.1065, 'volume': 1000}, {'timestamp': '2024-10-25T10:30:00Z', 'open': 1.1065, 'high': 1.108, 'low': 1.1055, 'close': 1.1075, 'volume': 1200}, {'timestamp': '2024-10-25T10:35:00Z', 'open': 1.1075, 'high': 1.109, 'low': 1.1065, 'close': 1.1085, 'volume': 1150}, {'timestamp': '2024-10-25T10:40:00Z', 'open': 1.1085, 'high': 1.11, 'low': 1.1075, 'close': 1.1095, 'volume': 1100}, {'timestamp': '2024-10-25T10:45:00Z', 'open': 1.1095, 'high': 1.111, 'low': 1.1085, 'close': 1.11, 'volume': 1050}, {'timestamp': '2024-10-25T10:50:00Z', 'open': 1.11, 'high': 1.112, 'low': 1.109, 'close': 1.111, 'volume': 1200}, {'timestamp': '2024-10-25T10:55:00Z', 'open': 1.111, 'high': 1.113, 'low': 1.11, 'close': 1.112, 'volume': 1250}]

以下に修正してみた。

Act06.py
import json

with open("5min_data.json") as f:
  data = json.load(f)
  for item in data:
    print(item)
    print("="*60)

実行結果は以下。どうやら1行ずつ読み込んでいる。いいね

{'timestamp': '2024-10-25T10:00:00Z', 'open': 1.1, 'high': 1.102, 'low': 1.099, 'close': 1.101, 'volume': 1000}
============================================================
{'timestamp': '2024-10-25T10:05:00Z', 'open': 1.101, 'high': 1.103, 'low': 1.1, 'close': 1.1025, 'volume': 1100}
============================================================
{'timestamp': '2024-10-25T10:10:00Z', 'open': 1.1025, 'high': 1.104, 'low': 1.1015, 'close': 1.1035, 'volume': 1050}
============================================================
{'timestamp': '2024-10-25T10:15:00Z', 'open': 1.1035, 'high': 1.105, 'low': 1.1025, 'close': 1.1045, 'volume': 950}
============================================================
{'timestamp': '2024-10-25T10:20:00Z', 'open': 1.1045, 'high': 1.106, 'low': 1.1035, 'close': 1.1055, 'volume': 980}
============================================================
{'timestamp': '2024-10-25T10:25:00Z', 'open': 1.1055, 'high': 1.107, 'low': 1.1045, 'close': 1.1065, 'volume': 1000}
============================================================
{'timestamp': '2024-10-25T10:30:00Z', 'open': 1.1065, 'high': 1.108, 'low': 1.1055, 'close': 1.1075, 'volume': 1200}
============================================================
{'timestamp': '2024-10-25T10:35:00Z', 'open': 1.1075, 'high': 1.109, 'low': 1.1065, 'close': 1.1085, 'volume': 1150}
============================================================
{'timestamp': '2024-10-25T10:40:00Z', 'open': 1.1085, 'high': 1.11, 'low': 1.1075, 'close': 1.1095, 'volume': 1100}
============================================================
{'timestamp': '2024-10-25T10:45:00Z', 'open': 1.1095, 'high': 1.111, 'low': 1.1085, 'close': 1.11, 'volume': 1050}
============================================================
{'timestamp': '2024-10-25T10:50:00Z', 'open': 1.11, 'high': 1.112, 'low': 1.109, 'close': 1.111, 'volume': 1200}
============================================================
{'timestamp': '2024-10-25T10:55:00Z', 'open': 1.111, 'high': 1.113, 'low': 1.11, 'close': 1.112, 'volume': 1250}
============================================================

次にPandasで操作できる形式に変換しようと思う。
一旦データを一つだけ使ってPandasを試してみる。

ここで一つ注意するのは、PandasのDataFrameクラスに渡す引数は配列にするということ。

Act06.py
import json
import pandas as pd

with open("5min_data.json") as f:
  data = json.load(f)
  pd = pd.DataFrame([data[0]]) ### 配列にする
  print(pd)
  # for item in data:
  #   print(item)
  #   print("="*60)

出力は以下の通り。
すご!インデックスにカラムまでついていい感じになってる。

              timestamp  open   high    low  close  volume
0  2024-10-25T10:00:00Z   1.1  1.102  1.099  1.101    1000

JSONファイルの内容を順に取得してみた。

Act06.py
import json
import pandas as pd

json_data_list = []

with open("5min_data.json") as f:
  data = json.load(f)
  for item in data:
    json_data_list.append(item)
  
df = pd.DataFrame(json_data_list)
print(df)

出力は以下の通り。
なんだかいい感じ。

               timestamp    open   high     low   close  volume
0   2024-10-25T10:00:00Z  1.1000  1.102  1.0990  1.1010    1000
1   2024-10-25T10:05:00Z  1.1010  1.103  1.1000  1.1025    1100
2   2024-10-25T10:10:00Z  1.1025  1.104  1.1015  1.1035    1050
3   2024-10-25T10:15:00Z  1.1035  1.105  1.1025  1.1045     950
4   2024-10-25T10:20:00Z  1.1045  1.106  1.1035  1.1055     980
5   2024-10-25T10:25:00Z  1.1055  1.107  1.1045  1.1065    1000
6   2024-10-25T10:30:00Z  1.1065  1.108  1.1055  1.1075    1200
7   2024-10-25T10:35:00Z  1.1075  1.109  1.1065  1.1085    1150
8   2024-10-25T10:40:00Z  1.1085  1.110  1.1075  1.1095    1100
9   2024-10-25T10:45:00Z  1.1095  1.111  1.1085  1.1100    1050
10  2024-10-25T10:50:00Z  1.1100  1.112  1.1090  1.1110    1200
11  2024-10-25T10:55:00Z  1.1110  1.113  1.1100  1.1120    1250

ここまで来てふと思った。
実際に使うときって、10:00~10:55までのデータは事前に持っていて、
11:00のデータをAPIで取得するはずじゃん。と、、

ということでコードを書き換えた。(思ったこと、気づいたことを記事にしてるから許して。)
これで10:00~10:55までのデータと11:00のデータがそろった。

Act06.py
import pandas as pd

# 事前に蓄えていたデータ
df = pd.read_json('5min_data.json')

# APIで取得するはずのデータ
next_data = {"timestamp": "2024-10-25 11:00:00+00:00", "open": 1.1120, "high": 1.1140, "low": 1.1110, "close": 1.1130, "volume": 1300}

行を末尾に追加する場合はappendメソッドを使用するらしい。
Pandasのappendメソッドは非推奨になっており、代わりにconcatを使うらしい。
concatはDataFrame同士を結合するメソッド。普段使うのはこれになりそう。

Act06.py
import pandas as pd

# 事前に蓄えていたデータ
df = pd.read_json('5min_data.json')

# APIで取得するはずのデータ
next_data = {"timestamp": "2024-10-25 11:00:00+00:00", "open": 1.1120, "high": 1.1140, "low": 1.1110, "close": 1.1130, "volume": 1300}
next_df = pd.DataFrame([next_data])

### `[df, next_df]`で結合したいDataFrameを複数指定
### `ignore_index=True`は、インデックスをいい感じに調整してもらう
df = pd.concat([df, next_df], ignore_index=True)
print(df)

出力は以下の通り。

                    timestamp    open   high     low   close  volume
0   2024-10-25 10:00:00+00:00  1.1000  1.102  1.0990  1.1010    1000
1   2024-10-25 10:05:00+00:00  1.1010  1.103  1.1000  1.1025    1100
2   2024-10-25 10:10:00+00:00  1.1025  1.104  1.1015  1.1035    1050
3   2024-10-25 10:15:00+00:00  1.1035  1.105  1.1025  1.1045     950
4   2024-10-25 10:20:00+00:00  1.1045  1.106  1.1035  1.1055     980
5   2024-10-25 10:25:00+00:00  1.1055  1.107  1.1045  1.1065    1000
6   2024-10-25 10:30:00+00:00  1.1065  1.108  1.1055  1.1075    1200
7   2024-10-25 10:35:00+00:00  1.1075  1.109  1.1065  1.1085    1150
8   2024-10-25 10:40:00+00:00  1.1085  1.110  1.1075  1.1095    1100
9   2024-10-25 10:45:00+00:00  1.1095  1.111  1.1085  1.1100    1050
10  2024-10-25 10:50:00+00:00  1.1100  1.112  1.1090  1.1110    1200
11  2024-10-25 10:55:00+00:00  1.1110  1.113  1.1100  1.1120    1250
12  2024-10-25 11:00:00+00:00  1.1120  1.114  1.1110  1.1130    1300

やっと一つ目のことが確認できた。

既存のデータをもとに新しい列を追加する

次にやりたいことは、データの内容を元に新しいデータを作成したい。
今回やってみるのは以下の2つ。

  1. onen, high, low, closeの平均を算出して、averageという列にデータを追加する
  2. 一つ前のvolumeとの差分を計算して、diff_volumeという列にデータを追加する

文章だとイメージがわかないかもだから早速1つ目を試してみる。

1. 平均を算出してaverageという列にデータを追加する

早速やっていくわけだが、まず最初に考えたのが特定のカラムのデータを取得する方法。
例えばopenの列のデータを取得したい。その場合は以下の記述で行けた。

Act06.py
df.open

これってもしかして、opencloseとかを足すことが出来るのでは・・・?
という甘い期待を抱いてこんなコードを書いてみた。

Act06.py
open = df.open
close = df.close
high = df.high
low = df.low
print((open + close + high + low) / 4)

出力は以下の通り。なんかいけちゃった

0     1.100500
1     1.101625
2     1.102875
3     1.103875
4     1.104875
5     1.105875
6     1.106875
7     1.107875
8     1.108875
9     1.109750
10    1.110500
11    1.111500
12    1.112500
dtype: float64

そして最終的なコードはこう!

Act06.py
import pandas as pd

# 事前に蓄えていたデータ
df = pd.read_json('5min_data.json')

# APIで取得するはずのデータ
next_data = {"timestamp": "2024-10-25 11:00:00+00:00", "open": 1.1120, "high": 1.1140, "low": 1.1110, "close": 1.1130, "volume": 1300}
next_df = pd.DataFrame([next_data])

df = pd.concat([df, next_df], ignore_index=True)
open = df.open
close = df.close
high = df.high
low = df.low
average = (open + close + high + low) / 4   ### 平均値を取得

### DataFrameのassignメソッドで列を追加する。
### 列名=データの形式で引数を渡す。
df = df.assign(average=average)
print(df)

出力は以下の通り。なんかいい感じ。

                    timestamp    open   high     low   close  volume   average
0   2024-10-25 10:00:00+00:00  1.1000  1.102  1.0990  1.1010    1000  1.100500
1   2024-10-25 10:05:00+00:00  1.1010  1.103  1.1000  1.1025    1100  1.101625
2   2024-10-25 10:10:00+00:00  1.1025  1.104  1.1015  1.1035    1050  1.102875
3   2024-10-25 10:15:00+00:00  1.1035  1.105  1.1025  1.1045     950  1.103875
4   2024-10-25 10:20:00+00:00  1.1045  1.106  1.1035  1.1055     980  1.104875
5   2024-10-25 10:25:00+00:00  1.1055  1.107  1.1045  1.1065    1000  1.105875
6   2024-10-25 10:30:00+00:00  1.1065  1.108  1.1055  1.1075    1200  1.106875
7   2024-10-25 10:35:00+00:00  1.1075  1.109  1.1065  1.1085    1150  1.107875
8   2024-10-25 10:40:00+00:00  1.1085  1.110  1.1075  1.1095    1100  1.108875
9   2024-10-25 10:45:00+00:00  1.1095  1.111  1.1085  1.1100    1050  1.109750
10  2024-10-25 10:50:00+00:00  1.1100  1.112  1.1090  1.1110    1200  1.110500
11  2024-10-25 10:55:00+00:00  1.1110  1.113  1.1100  1.1120    1250  1.111500
12  2024-10-25 11:00:00+00:00  1.1120  1.114  1.1110  1.1130    1300  1.112500

これでいいや。と思ったかもしれないが、もっといい方法があると思うのでChatGPTさんに質問。

回答をもとにコードを変更してみた。
このコードでも同様の結果を得ることに成功。まあ、やってることは同じだしそりゃそうだ。
assignを使わないでも列を追加できることが分かったからよしとする。

Act06.py
import pandas as pd

# 事前に蓄えていたデータ
df = pd.read_json('5min_data.json')

# APIで取得するはずのデータ
next_data = {"timestamp": "2024-10-25 11:00:00+00:00", "open": 1.1120, "high": 1.1140, "low": 1.1110, "close": 1.1130, "volume": 1300}
next_df = pd.DataFrame([next_data])

df = pd.concat([df, next_df], ignore_index=True)
df['average'] = (df['open'] + df['close'] + df['high'] + df.get('low', 0)) / 4  # lowが存在しない場合は0として扱うことも可能

print(df)

もっと画期的な方法を教えてくれ!と懇願した結果、meanメソッドを教えてくれた。

Act06.py
import pandas as pd

# 事前に蓄えていたデータ
df = pd.read_json('5min_data.json')

# APIで取得するはずのデータ
next_data = {"timestamp": "2024-10-25 11:00:00+00:00", "open": 1.1120, "high": 1.1140, "low": 1.1110, "close": 1.1130, "volume": 1300}
next_df = pd.DataFrame([next_data])

df = pd.concat([df, next_df], ignore_index=True)
# DataFrameには`sum`や`mean`、`min`など様々なメソッドを提供しているため、列や行に対する処理を迅速に行うことが出来る
# `axis=1`というのは行を対象にしている。
df["average"] = df[["open", "close", "high", "low"]].mean(axis=1)

print(df)

ちなみに、axis=0にした場合は列が対象になるらしい。

それと、df[["open", "close", "high", "low"]]は、
df["open"]df["close"]・・・と同じ意味で、それぞれのカラムを一気に参照出来るっポイ。

最初に比べるときれいなコードになったし、きっとこれが正解だろう。

2. 一つ前との差分を計算してdiff_volumeという列にデータを追加する

ということで次に進もうと思う。
これは何かというと、11:00のdiff_volumeの値は、10:55と11:00のvolumeデータの差分を設定したい。

直ぐに調べる前に色々試してみる。
まずはこれ。indexが0のvolumeデータを取得できた。狙い通り。

Act06.py
df.volume[0]
# 出力:1000

一つ思いついたのは、
volumeデータを列ごと取得して一行ずらす。
その後に差分を求めれば行けるのでは?ってこと。試してみたけど断念。

Act06.py
volume = df.volume
volume = volume.drop(axis=0, index=volume.count() - 1)
print(volume)

出力は以下の通り。
末尾を消すことは出来たが、最初の一行目に追加する方法がよくわからなかった。
悔しいが何かいい方法がないか調べてみる。

0     1000
1     1100
2     1050
3      950
4      980
5     1000
6     1200
7     1150
8     1100
9     1050
10    1200
11    1250
Name: volume, dtype: int64

調べてらめっちゃ簡単だった。。
diffメソッドを使用すると簡単にデータの差分を取得できる。
知ってるのと知らないのだと天と地の差だね。

Act06.py
import pandas as pd

# 事前に蓄えていたデータ
df = pd.read_json('5min_data.json')

# APIで取得するはずのデータ
next_data = {"timestamp": "2024-10-25 11:00:00+00:00", "open": 1.1120, "high": 1.1140, "low": 1.1110, "close": 1.1130, "volume": 1300}
next_df = pd.DataFrame([next_data])

df = pd.concat([df, next_df], ignore_index=True)
df["average"] = df[["open", "close", "high", "low"]].min(axis=1)
df["diff_volume"] = df["volume"].diff()

print(df)

出力は以下の通り。
diffメソッドは引数に期間を指定することで、何個前との差分を取るかを指定できるらしい。

                    timestamp    open   high     low   close  volume  average  diff_volume
0   2024-10-25 10:00:00+00:00  1.1000  1.102  1.0990  1.1010    1000   1.0990          NaN
1   2024-10-25 10:05:00+00:00  1.1010  1.103  1.1000  1.1025    1100   1.1000        100.0
2   2024-10-25 10:10:00+00:00  1.1025  1.104  1.1015  1.1035    1050   1.1015        -50.0
3   2024-10-25 10:15:00+00:00  1.1035  1.105  1.1025  1.1045     950   1.1025       -100.0
4   2024-10-25 10:20:00+00:00  1.1045  1.106  1.1035  1.1055     980   1.1035         30.0
5   2024-10-25 10:25:00+00:00  1.1055  1.107  1.1045  1.1065    1000   1.1045         20.0
6   2024-10-25 10:30:00+00:00  1.1065  1.108  1.1055  1.1075    1200   1.1055        200.0
7   2024-10-25 10:35:00+00:00  1.1075  1.109  1.1065  1.1085    1150   1.1065        -50.0
8   2024-10-25 10:40:00+00:00  1.1085  1.110  1.1075  1.1095    1100   1.1075        -50.0
9   2024-10-25 10:45:00+00:00  1.1095  1.111  1.1085  1.1100    1050   1.1085        -50.0
10  2024-10-25 10:50:00+00:00  1.1100  1.112  1.1090  1.1110    1200   1.1090        150.0
11  2024-10-25 10:55:00+00:00  1.1110  1.113  1.1100  1.1120    1250   1.1100         50.0
12  2024-10-25 11:00:00+00:00  1.1120  1.114  1.1110  1.1130    1300   1.1110         50.0

追加

指定した期間の平均値を求めることはできるのか?と気になって調べてみた。
結論、rollingメソッドを使用すればOKらしい。

Act06.py
import pandas as pd

# 事前に蓄えていたデータ
df = pd.read_json('5min_data.json')

# APIで取得するはずのデータ
next_data = {"timestamp": "2024-10-25 11:00:00+00:00", "open": 1.1120, "high": 1.1140, "low": 1.1110, "close": 1.1130, "volume": 1300}
next_df = pd.DataFrame([next_data])

df = pd.concat([df, next_df], ignore_index=True)
df["average"] = df[["open", "close", "high", "low"]].min(axis=1)
df["diff_volume"] = df["volume"].diff()
# windowで期間を取得し、その期間の平均を算出する
df["mean_open"] = df["open"].rolling(window=3).mean()

print(df)

出力は以下の通り。

                    timestamp    open   high     low   close  volume  average  diff_volume      mean_open
0   2024-10-25 10:00:00+00:00  1.1000  1.102  1.0990  1.1010    1000   1.0990          NaN       NaN
1   2024-10-25 10:05:00+00:00  1.1010  1.103  1.1000  1.1025    1100   1.1000        100.0       NaN
2   2024-10-25 10:10:00+00:00  1.1025  1.104  1.1015  1.1035    1050   1.1015        -50.0  1.101167
3   2024-10-25 10:15:00+00:00  1.1035  1.105  1.1025  1.1045     950   1.1025       -100.0  1.102333
4   2024-10-25 10:20:00+00:00  1.1045  1.106  1.1035  1.1055     980   1.1035         30.0  1.103500
5   2024-10-25 10:25:00+00:00  1.1055  1.107  1.1045  1.1065    1000   1.1045         20.0  1.104500
6   2024-10-25 10:30:00+00:00  1.1065  1.108  1.1055  1.1075    1200   1.1055        200.0  1.105500
7   2024-10-25 10:35:00+00:00  1.1075  1.109  1.1065  1.1085    1150   1.1065        -50.0  1.106500
8   2024-10-25 10:40:00+00:00  1.1085  1.110  1.1075  1.1095    1100   1.1075        -50.0  1.107500
9   2024-10-25 10:45:00+00:00  1.1095  1.111  1.1085  1.1100    1050   1.1085        -50.0  1.108500
10  2024-10-25 10:50:00+00:00  1.1100  1.112  1.1090  1.1110    1200   1.1090        150.0  1.109333
11  2024-10-25 10:55:00+00:00  1.1110  1.113  1.1100  1.1120    1250   1.1100         50.0  1.110167
12  2024-10-25 11:00:00+00:00  1.1120  1.114  1.1110  1.1130    1300   1.1110         50.0  1.111000

MAX、MIN、AVEを取得

こんなのもう余裕でしょ!

Act06.py
import pandas as pd

# 事前に蓄えていたデータ
df = pd.read_json('5min_data.json')

# APIで取得するはずのデータ
next_data = {"timestamp": "2024-10-25 11:00:00+00:00", "open": 1.1120, "high": 1.1140, "low": 1.1110, "close": 1.1130, "volume": 1300}
next_df = pd.DataFrame([next_data])

df = pd.concat([df, next_df], ignore_index=True)

print(df["open"].max())
print(df["open"].min())
print(df["open"].mean())

出力は以下の通り。

1.112
1.1
1.1063076923076922

さっきまでの学習のおかげで瞬殺だった。

時間指定でデータを取得

timestampがあるんだから、やっぱり時間指定してデータが欲しいよね。
これに関しては全く思いつかなかったから調べた。

まずはdf[condition]の形式。
どうやら条件を満たすものを取得できるらしい。

それと注意すべきがdf['timestamp'] = pd.to_datetime(df['timestamp'])の処理。
元々は文字列型だからそれをDateTime型に変換しないと<=などが使えない。

Act06.py
import pandas as pd

# 事前に蓄えていたデータ
df = pd.read_json('5min_data.json')

# APIで取得するはずのデータ
next_data = {"timestamp": "2024-10-25 11:00:00+00:00", "open": 1.1120, "high": 1.1140, "low": 1.1110, "close": 1.1130, "volume": 1300}
next_df = pd.DataFrame([next_data])

df = pd.concat([df, next_df], ignore_index=True)
df['timestamp'] = pd.to_datetime(df['timestamp'])

start_time = "2024-10-25 10:10:00+00:00"
end_time = "2024-10-25 10:40:00+00:00"
filtered_df = df[(df['timestamp'] >= start_time) & (df['timestamp'] <= end_time)]
print(filtered_df)

出力は以下の通り。

                  timestamp    open   high     low   close  volume
2 2024-10-25 10:10:00+00:00  1.1025  1.104  1.1015  1.1035    1050
3 2024-10-25 10:15:00+00:00  1.1035  1.105  1.1025  1.1045     950
4 2024-10-25 10:20:00+00:00  1.1045  1.106  1.1035  1.1055     980
5 2024-10-25 10:25:00+00:00  1.1055  1.107  1.1045  1.1065    1000
6 2024-10-25 10:30:00+00:00  1.1065  1.108  1.1055  1.1075    1200
7 2024-10-25 10:35:00+00:00  1.1075  1.109  1.1065  1.1085    1150
8 2024-10-25 10:40:00+00:00  1.1085  1.110  1.1075  1.1095    1100

次がqueryメソッドを使ったパターン。出力は先ほどと全く同じ。
df[conditions]は小規模データにqueryメソッドは大規模データに対してのパフォーマンスが向上するらしい。

queryメソッドの方が見やすいから好きなんだけどなー。。

Act06.py
import pandas as pd

# 事前に蓄えていたデータ
df = pd.read_json('5min_data.json')

# APIで取得するはずのデータ
next_data = {"timestamp": "2024-10-25 11:00:00+00:00", "open": 1.1120, "high": 1.1140, "low": 1.1110, "close": 1.1130, "volume": 1300}
next_df = pd.DataFrame([next_data])

df = pd.concat([df, next_df], ignore_index=True)
df['timestamp'] = pd.to_datetime(df['timestamp'])

start_time = "2024-10-25 10:10:00+00:00"
end_time = "2024-10-25 10:40:00+00:00"
# @で変数を参照できる
filtered_df = df.query("timestamp >= @start_time and timestamp <= @end_time")
print(filtered_df)

さいごに

Pandas触ってみたけど、めちゃくちゃ色々なことが出来るなという印象。
多分まだPandasの1%くらいしか理解していないんだろうけど、それでも便利なのはわかった。

これから色々なケースを試す時が来るだろうから、また1か月後くらいにこの記事を見直して、さらに深くPandasを学びたいと思った。

ではまた

Discussion