昨今、FIAのリザルトとデータのページがアクセスできなくなっており、ラップタイムを入手するにはFIAのイベントページからPDFをダウンロードせざるを得なくなった。一方、9/13にはOpenAIから論理・数学知能に長けたOpenAI o1がリリースされた。
そこで、当サイトでは、GPTs(GPT-4o)にPDFをエクセルに貼り付けやすい表形式に変換してもらい、o1にはエクセル内の作業を自動化するVBAマクロを書いてもらうことで、作業の効率化を図ることとした。
1. PDFから表へ
以下のGPTsを使用する。
https://chatgpt.com/gpts/editor/g-bBZcBoHyy
PDFを送れば、表を出力してくれる。GPT-4oの能力の限界の都合上、4人ずつの出力となり、「next」と送ると次の4人に進むことができる。なお、筆者の分析用エクセルシートに合わせて、Verstappen, Perez, Hamilton, Russel、次にLeclerc, Sainz, Norris, Piastri、次にGasly, Ocon, Tsunoda, Ricciardo、次にAlonso, Stroll, Albon, Colapinto、最後にBottas, Zhou, Hulkenberg, Magnussenの順となっている。こだわりがある方は、自分なりの順序をGPTに伝えれば。
また、案内に記述してあるが、最初にPDFと共に
・最初に周回数が少ないドライバーについて、「フェルスタッペンとハミルトンは59周まで、ルクレールは41周までしかないことに気をつけてください。」のように最初に注意喚起。
・代役出走がある場合はその旨を指示。
の2点は押さえておく必要がある。特に後者は忘れるとハルシネーションに繋がる確率が高いだろう。ただし、そこまでやっても特に全周回数を走り切っていないドライバーのラップタイムを無理やり生成してくることは時折あるので、その部分だけ人間のチェックが必要だ。
例えばアゼルバイジャンGPであれば、以下のように書けば良い。
“””
オコンとボッタスは50周まで、ペレスとサインツは49周まで、ストロールは45周まで、角田は14周までしかないことに気をつけてください。
また、マグヌッセンに代わってベアマンが出走していることにも気をつけてください。
よろしくお願いいたします。
“””
時折、リタイア・周回遅れ組の注意書きに釣られて、その順番で出力してくることがあるので、一時停止して、Instructionに書いてある順番を守ってもらうよう注意喚起すると良いだろう。
この表をスプレッドシートやエクセルに貼り付けて、ご使用いただける。
2. VBA
表をエクセルシート(A列が周回数で、BからU列まで20人が並ぶ。4行目が1周目。)に貼り付けたら、10チームのレースペースグラフを予め作成しておく。グラフの縦軸(タイム)の最適な最大値・最小値はレースによって異なり、横軸(周回数)も当然異なるので、人力で調整するのは意外に面倒くさい。ここを自動化するのが以下のVBAプログラムだ。
〜〜〜コード1〜〜〜
Sub UpdateGraphs()
Dim ws As Worksheet
Dim lastRow As Long
Dim chartObj As ChartObject
Dim cht As Chart
Dim ser As Series
Dim i As Integer
Dim colIndex As Integer
Dim colLetter As String
Dim s As Integer
Dim minValue As Double
Dim minValueTruncated As Double
Dim maxValue As Double
Dim dataRange As Range
‘ アクティブなワークシートを設定
Set ws = ActiveSheet
‘ 列Bから列Uまでの最終行を取得(列Bから列Uの中で最も下にあるデータの行)
lastRow = ws.Range(“B:U”).Find(What:=”*”, SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
‘ データ範囲を設定(B4:U lastRow)
Set dataRange = ws.Range(“B4:U” & lastRow)
‘ データ範囲内の最小値を取得
minValue = WorksheetFunction.Min(dataRange)
‘ 最小値の小数点以下1秒未満を切り捨てて.000にする
minValueTruncated = Int(minValue * 86400) / 86400
‘ 最大値を最小値+8秒に設定
maxValue = minValueTruncated + (8 / 86400)
‘ グラフ1から10までループ
For i = 1 To 10
‘ グラフオブジェクトを取得(グラフの名前を適宜変更してください)
Set chartObj = ws.ChartObjects(“グラフ ” & i) ‘ グラフ名が “グラフ 1”, “グラフ 2”, … の場合
‘ グラフが存在する場合のみ処理を実行
If Not chartObj Is Nothing Then
Set cht = chartObj.Chart
‘ 系列の数を取得(各グラフには2つの系列があると仮定)
For s = 1 To 2
‘ 系列を取得
Set ser = cht.SeriesCollection(s)
‘ 系列のY値の列を取得
‘ 指定された対応に基づいて列インデックスを計算
‘ 列Bは2列目なので、Excelの列インデックスに合わせる
colIndex = 2 * (i – 1) + s + 1 ‘ グラフ番号と系列番号から列インデックスを計算
‘ 列インデックスが21(列U、列インデックス21)を超えないようにする
If colIndex <= 21 Then
colLetter = Split(ws.Cells(1, colIndex).Address, “$”)(1)
‘ 系列のY値の範囲を設定
ser.Values = ws.Range(“$” & colLetter & “$3:$” & colLetter & “$” & lastRow)
‘ X値の範囲を設定(例として列Aを使用)
ser.XValues = ws.Range(“$A$3:$A$” & lastRow)
End If
Next s
‘ グラフのY軸の最小値と最大値を設定
With cht.Axes(xlValue)
.MinimumScale = minValueTruncated
.MaximumScale = maxValue
End With
End If
Next i
End Sub
〜〜〜〜〜〜
筆者は、ファステストラップの小数点以下を切り捨てた値を最小値に設定し、その8秒落ちを最大値としてきているため、このようになったが、この辺りは個人の好みで良いだろう。あるいは、ウェットレースなどで、自分で弄りながら決めたい際はグラフ 1のみ手動で行い、残り9つは以下のプログラムでグラフ 1と同じ設定にすれば良いだろう。
〜〜〜コード2〜〜〜
Sub SetAxisMinMax()
Dim chart1 As ChartObject
Dim chart1Axis As Axis
Dim chart2to10 As ChartObject
Dim i As Integer
‘ グラフ1の最小値と最大値を取得
Set chart1 = ActiveSheet.ChartObjects(1)
Set chart1Axis = chart1.Chart.Axes(xlValue, xlPrimary)
minValue = chart1Axis.MinimumScale
maxValue = chart1Axis.MaximumScale
‘ グラフ2から10の軸に最小値と最大値を設定
For i = 2 To 10
Set chart2to10 = ActiveSheet.ChartObjects(i)
Set chartAxis = chart2to10.Chart.Axes(xlValue, xlPrimary)
chartAxis.MinimumScale = minValue
chartAxis.MaximumScale = maxValue
Next i
End Sub
〜〜〜〜〜〜
最後に、分析をする上で欠かせないのが、クリアエアとダーティエアの識別だ。これは前方にいるドライバーが2秒以内にいる際にそのラップのセルに色をつけるようにすれば良い。以下のプログラムで可能だ。
〜〜〜コード3〜〜〜
Sub HighlightCloseGapsAdvanced()
Dim ws As Worksheet
Dim lastRow As Long
Dim lastCol As Long
Dim i As Long, j As Long
Dim driverCount As Long
Dim lapTimes() As Variant
Dim cumulativeTimes() As Double
Dim positions() As Long
Dim driverIndices() As Long
Dim timeDiff As Double
Dim sortedIndices() As Long
Dim temp As Double
Dim k As Long
‘ アクティブなワークシートを設定
Set ws = ActiveSheet
‘ ドライバーの数(列数)を取得(列BからUまでの20列)
driverCount = ws.Range(“B1:U1”).Columns.Count
‘ ドライバーの列インデックスを取得
Dim driverCols() As Long
ReDim driverCols(1 To driverCount)
For j = 1 To driverCount
driverCols(j) = ws.Range(“B1”).Column + j – 1
Next j
‘ データの最終行を取得(列BからUの中で最も下にあるデータの行)
lastRow = ws.Range(“B:U”).Find(What:=”*”, SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
‘ ラップごとに処理
For i = 4 To lastRow
‘ 各ドライバーの累積タイムを計算
ReDim cumulativeTimes(1 To driverCount)
For j = 1 To driverCount
cumulativeTimes(j) = 0
For k = 4 To i
If IsNumeric(ws.Cells(k, driverCols(j)).Value) Then
cumulativeTimes(j) = cumulativeTimes(j) + ws.Cells(k, driverCols(j)).Value
Else
cumulativeTimes(j) = 0 ‘ データがない場合は0に設定
Exit For ‘ データがない場合は計算を中断
End If
Next k
Next j
‘ ドライバーのインデックスを保持
ReDim driverIndices(1 To driverCount)
For j = 1 To driverCount
driverIndices(j) = j
Next j
‘ 累積タイムに基づいてドライバーをソート(バブルソートを使用)
For j = 1 To driverCount – 1
For k = j + 1 To driverCount
If cumulativeTimes(j) > cumulativeTimes(k) Then
‘ 累積タイムをスワップ
temp = cumulativeTimes(j)
cumulativeTimes(j) = cumulativeTimes(k)
cumulativeTimes(k) = temp
‘ ドライバーのインデックスをスワップ
temp = driverIndices(j)
driverIndices(j) = driverIndices(k)
driverIndices(k) = temp
End If
Next k
Next j
‘ 各ドライバーについてタイム差を計算し、ハイライト
For j = 2 To driverCount
Dim currentDriver As Long
Dim previousDriver As Long
currentDriver = driverIndices(j)
previousDriver = driverIndices(j – 1)
‘ データが存在するか確認
If cumulativeTimes(j) > 0 And cumulativeTimes(j – 1) > 0 Then
timeDiff = (cumulativeTimes(j) – cumulativeTimes(j – 1)) * 86400 ‘ 秒に変換
‘ タイム差が0以上2.0秒以下の場合
If timeDiff >= 0 And timeDiff <= 2 Then
‘ セルをハイライト(例: 黄色に設定)
ws.Cells(i, driverCols(currentDriver)).Interior.Color = RGB(204, 193, 218)
Else
‘ ハイライトを解除
ws.Cells(i, driverCols(currentDriver)).Interior.ColorIndex = xlNone
End If
Else
‘ ハイライトを解除
ws.Cells(i, driverCols(currentDriver)).Interior.ColorIndex = xlNone
End If
Next j
‘ 先頭のドライバーのハイライトを解除
currentDriver = driverIndices(1)
ws.Cells(i, driverCols(currentDriver)).Interior.ColorIndex = xlNone
Next i
End Sub
〜〜〜〜〜〜
※管理人のシート上では時折ダーティエアにも関わらずハイライトされていないことがあるが、原因は不明。コードではなくシート側に問題がある可能性もあり。
これにて、分析を始めるまでの段階の多く部分を自動化できた。筆者の分析スタイルに合ったものにはなってしまっているが、列や行の使い方、ドライバーの並び、ダーティエアの基準など、個々人でカスタマイズするなり、これをヒントにo1とのやり取りを通してより優れた手法を生み出していっていただければ本望だ。
Writer: Takumi