[python][turfpy]緯度経度範囲内検出の処理時間検証

# はじめに
前回turfpyを使用する際の緯度経度指定方法検証について記事を書いたが
複数範囲も指定できるのが分かり、実行してみると動作時間が増えたので
処理内容で処理時間がどれぐらい変化についてまとめる。

https://qiita.com/ryoEast/items/72fa83093a0eef80e629

# 動作環境
- windows 11([FRGXB660/WS15/NTK](https://www.frontier-direct.jp/direct/g/g112906-dec1/))
- python 3.10.5
- turfpy 0.0.7

# 予測
- 単独地点では範囲を広げる、指定地点を増やすでは時間に変化はない
- 複数地点は増やすほど処理時間が増える


# 検証方法：①単独地点での範囲内検出(1範囲4ポイント)
## 場所
愛知県豊田市豊田スタジアム周辺
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632401/ce629b94-a4f7-5624-4e36-5220a6866c71.png)

## ポイント数
ランダムに10000ポイント生成し、設定した範囲の
内：skybule（水色）
外：red（赤色）
にマーカーを変化させる処理を実行する
※処理時間が長い為、地図表示処理は計測に含まない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632401/b043e725-b97d-67d1-c6b1-423585e904a9.png)

## 処理

### 範囲設定
```python
from turfpy.measurement import boolean_point_in_polygon
from geojson import Point, Polygon, Feature

def point_check(latitude, longitude):
  point = Feature(geometry=Point((latitude, longitude)))
  polygon = Polygon(
      [
          [
            #   1：左上
              (35.08498611052201, 137.1702668998151),
            #   2：右上
              (35.08517234972593, 137.1712000309319),
            #   3：右下
              (35.084110780567734, 137.17151866106937),
            #   4：左下
              (35.083930747001176, 137.17060070281622),
          ]
      ]
  )

  return boolean_point_in_polygon(point, polygon)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632401/5ba6b786-1ab0-6e78-2ad2-d09627908a5f.png)

### 範囲内検出
```python
import random
import time

import folium
from folium.features import DivIcon
map1 = folium.Map(location=[35.08590488646905, 137.16832477326307], zoom_start=16)
random.seed(1)
times =[]
for i in range(10):

    start_time = time.perf_counter()
    
    for index in range(10000):
        # 緯度経度を指定した範囲でランダムに出力
        y = random.uniform(35.08109982212356, 35.0893067505472)
        x = random.uniform(137.16334807397342, 137.17556222924227)
        
        # 判定し結果によってポインターの色を範囲内は水色、範囲外は赤にする
        output = point_check(y, x)
        match output:
            case False:
                color = "red"
            case True:
                color = "skyblue"

    end_time = time.perf_counter()
    elapsed_time = end_time - start_time
    print(f'{i + 1} 回目：{elapsed_time:.3f}秒')
    times.append(elapsed_time)

ave = sum(times) / len(times)
print(f'平均処理速度：{ave:.3f}秒')
```
地図に出力はしないで判定のみを実行し
10回の平均処理時間を算出

## 結果
1 回目：0.134秒
2 回目：0.134秒
3 回目：0.134秒
4 回目：0.133秒
5 回目：0.130秒
6 回目：0.135秒
7 回目：0.132秒
8 回目：0.132秒
9 回目：0.134秒
10 回目：0.151秒
平均処理速度：0.135秒

# ②単独地点で範囲を広げた際の範囲内検出(1範囲4ポイント)
### 範囲設定
範囲設定のみを変更する
```python
from turfpy.measurement import boolean_point_in_polygon
from geojson import Point, Polygon, Feature

def point_check(latitude, longitude):
  point = Feature(geometry=Point((latitude, longitude)))
  polygon = Polygon(
      [
          [
            #   1：左上
              (35.08546640100173, 137.16915620996878),
            #   2：右上
              (35.08570264165712, 137.17167330297343),
            #   3：右下
              (35.08378316652754, 137.17211537307102),
            #   4：左下
              (35.08320731518087, 137.17001328464778),
          ]
      ]
  )

  return boolean_point_in_polygon(point, polygon)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632401/2a69b1af-1564-af18-a210-dc48387be8f3.png)
推定：面積が広がると処理時間が増える
→場所は同じで範囲を広げる

## 結果
以降、「範囲内検出」の処理は上記と同じ
1 回目：0.145秒
2 回目：0.128秒
3 回目：0.133秒
4 回目：0.137秒
5 回目：0.134秒
6 回目：0.131秒
7 回目：0.131秒
8 回目：0.131秒
9 回目：0.132秒
10 回目：0.130秒
平均処理速度：0.133秒

範囲を広くても、処理時間は変わらない

# ③単独地点で範囲のポイントを増やした時(1範囲12ポイント)
```python
from turfpy.measurement import boolean_point_in_polygon
from geojson import Point, Polygon, Feature

def point_check(latitude, longitude):
  point = Feature(geometry=Point((latitude, longitude)))
  polygon = Polygon(
      [
          [
            #   1：左上
              (35.08498611052201, 137.1702668998151),
              (35.08506011080733, 137.17050113715823),
              (35.08512156660048, 137.1709088328808),
            #   2：右上
              (35.08517234972593, 137.1712000309319),
              (35.08491964024918, 137.1712628844293),
              (35.08438409402701, 137.17143454578618),
            #   3：右下
              (35.084110780567734, 137.17151866106937),
              (35.084059252802035, 137.17130579976853),
              (35.08396267813433, 137.17085518870675),
            #   4：左下
              (35.083930747001176, 137.17060070281622),
              (35.0842611812832, 137.17049040832342),
              (35.08470893395838, 137.17035093347096),
          ]
      ]
  )

  return boolean_point_in_polygon(point, polygon)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632401/af35e2ba-70a2-2086-42ab-eb19cdfc88c8.png)
推定：範囲指定のポイント数が増えると処理時間が増える
→①と同じ範囲でポイント数を増やす
　①：4ポイントで四角の範囲指定
　③：四角の間に2ポイント追加し、計12ポイント

## 結果
1 回目：0.238秒
2 回目：0.242秒
3 回目：0.236秒
4 回目：0.242秒
5 回目：0.238秒
6 回目：0.240秒
7 回目：0.239秒
8 回目：0.233秒
9 回目：0.242秒
10 回目：0.238秒
平均処理速度：0.239秒

同じ面積でも範囲を指定するポイントを増やすと処理時間が増える

# ④複数個所(5範囲4ポイント)
`MultiPolygon`で複数範囲を指定できる
今まで使用していた豊田スタジアム周辺の５か所を指定する
```python
from turfpy.measurement import boolean_point_in_polygon
from geojson import Point, MultiPolygon, Feature

def point_check(latitude, longitude):
    point = Feature(geometry=Point((latitude, longitude)))
    polygons = MultiPolygon(
        [
            #   豊田スタジアム
            ([
                (35.08498611052201, 137.1702668998151),
                (35.08517234972593, 137.1712000309319),
                (35.084110780567734, 137.17151866106937),
                (35.083930747001176, 137.17060070281622),
            ],),
            #   白浜公園
            ([
                (35.084961185932634, 137.16505614259552),
                (35.084934847689475, 137.16564622850976),
                (35.08394812100898, 137.16559779523874),
                (35.08401300382069, 137.1649703119171),
            ],),
            #   サッカー場
            ([
                (35.08840799626122, 137.16594111795243),
                (35.088206078045935, 137.16689598424998),
                (35.08688042865314, 137.166402457849),
                (35.08711746688139, 137.16545832038628),
            ],),
            #   千石公園駐車場
            ([
                (35.08654146495958, 137.1694871513695),
                (35.08642733472229, 137.16985193175285),
                (35.086163956642075, 137.16987338942246),
                (35.08613761878727, 137.1695193378739),
            ],),
            #   豊田スタジアム駐車場
            ([
                (35.083451112923825, 137.16880050594204),
                (35.082985794095094, 137.17010942378815),
                (35.08231211159247, 137.16932096532983),
                (35.08267207841984, 137.1684197432063),
            ],),
        ]
    )

    return boolean_point_in_polygon(point, polygons)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632401/1bd28302-c0d8-b9bf-b2f4-561e62e516ed.png)

## 結果
1 回目：0.386秒
2 回目：0.373秒
3 回目：0.384秒
4 回目：0.385秒
5 回目：0.376秒
6 回目：0.381秒
7 回目：0.370秒
8 回目：0.373秒
9 回目：0.373秒
10 回目：0.368秒
平均処理速度：0.377秒

当然ではあるが範囲を増やすと処理時間は増える

# ⑤複数個所(3範囲4ポイント)
```python
from turfpy.measurement import boolean_point_in_polygon
from geojson import Point, MultiPolygon, Feature

def point_check(latitude, longitude):
    point = Feature(geometry=Point((latitude, longitude)))
    polygons = MultiPolygon(
        [
            #   豊田スタジアム
            ([
                (35.08498611052201, 137.1702668998151),
                (35.08517234972593, 137.1712000309319),
                (35.084110780567734, 137.17151866106937),
                (35.083930747001176, 137.17060070281622),
            ],),
            #   白浜公園
            ([
                (35.084961185932634, 137.16505614259552),
                (35.084934847689475, 137.16564622850976),
                (35.08394812100898, 137.16559779523874),
                (35.08401300382069, 137.1649703119171),
            ],),
            #   サッカー場
            ([
                (35.08840799626122, 137.16594111795243),
                (35.088206078045935, 137.16689598424998),
                (35.08688042865314, 137.166402457849),
                (35.08711746688139, 137.16545832038628),
            ],),
            # #   千石公園駐車場
            # ([
            #     (35.08654146495958, 137.1694871513695),
            #     (35.08642733472229, 137.16985193175285),
            #     (35.086163956642075, 137.16987338942246),
            #     (35.08613761878727, 137.1695193378739),
            # ],),
            # #   豊田スタジアム駐車場
            # ([
            #     (35.083451112923825, 137.16880050594204),
            #     (35.082985794095094, 137.17010942378815),
            #     (35.08231211159247, 137.16932096532983),
            #     (35.08267207841984, 137.1684197432063),
            # ],),
        ]
    )

    return boolean_point_in_polygon(point, polygons)
```
5か所を3か所に減らす
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632401/451b44bb-7b86-1253-7db2-1294aed6d9f4.png)
## 結果
1 回目：0.251秒
2 回目：0.253秒
3 回目：0.256秒
4 回目：0.252秒
5 回目：0.256秒
6 回目：0.251秒
7 回目：0.255秒
8 回目：0.259秒
9 回目：0.256秒
10 回目：0.262秒
平均処理速度：0.255秒


# ⑥複数個所(1範囲4ポイント)
```python
from turfpy.measurement import boolean_point_in_polygon
from geojson import Point, MultiPolygon, Feature

def point_check(latitude, longitude):
    point = Feature(geometry=Point((latitude, longitude)))
    polygons = MultiPolygon(
        [
            #   豊田スタジアム
            ([
                (35.08498611052201, 137.1702668998151),
                (35.08517234972593, 137.1712000309319),
                (35.084110780567734, 137.17151866106937),
                (35.083930747001176, 137.17060070281622),
            ],),
            # #   白浜公園
            # ([
            #     (35.084961185932634, 137.16505614259552),
            #     (35.084934847689475, 137.16564622850976),
            #     (35.08394812100898, 137.16559779523874),
            #     (35.08401300382069, 137.1649703119171),
            # ],),
            # #   サッカー場
            # ([
            #     (35.08840799626122, 137.16594111795243),
            #     (35.088206078045935, 137.16689598424998),
            #     (35.08688042865314, 137.166402457849),
            #     (35.08711746688139, 137.16545832038628),
            # ],),
            # #   千石公園駐車場
            # ([
            #     (35.08654146495958, 137.1694871513695),
            #     (35.08642733472229, 137.16985193175285),
            #     (35.086163956642075, 137.16987338942246),
            #     (35.08613761878727, 137.1695193378739),
            # ],),
            # #   豊田スタジアム駐車場
            # ([
            #     (35.083451112923825, 137.16880050594204),
            #     (35.082985794095094, 137.17010942378815),
            #     (35.08231211159247, 137.16932096532983),
            #     (35.08267207841984, 137.1684197432063),
            # ],),
        ]
    )

    return boolean_point_in_polygon(point, polygons)
```
複数半指定を1か所にして①と同じにする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632401/235dda07-26d6-3e38-0509-af68252d633b.png)

## 結果
1 回目：0.136秒
2 回目：0.130秒
3 回目：0.134秒
4 回目：0.133秒
5 回目：0.134秒
6 回目：0.132秒
7 回目：0.132秒
8 回目：0.134秒
9 回目：0.132秒
10 回目：0.134秒
平均処理速度：0.133秒
①とほぼ同じ処理時間になる

# まとめ

:::note
ポイント総数の増減が処理時間の増減に影響する
:::

- ①の範囲拡大の②、①と同じ範囲を複数範囲で指定した⑥の処理時間がほぼ同じ
- 単独範囲で12ポイント指定した③と複数範囲で12ポイント指定した⑤の処理時間がほぼ同じ

| No  | 範囲(数)    | ポイント/範囲 | ポイント総数 | 処理時間(秒) |
|:---:|:-----------:|:------------:|:-----------:|:-----------:|
| ①   | 単独(1)     | 4            | 4           | 0.135       |
| ②   | 単独(1拡大) | 4            | 4           | 0.133       |
| ③   | 単独(1)     | 12           | 12          | 0.239       |
| ④   | 複数(5)     | 4            | 20          | 0.377       |
| ⑤   | 複数(3)     | 4            | 12          | 0.255       |
| ⑥   | 複数(1)     | 4            | 4           | 0.133       |