考古学のためのRでGIS〜遺跡の標高と海岸線からの距離を分析する〜

道南ブロック博物館施設等連絡協議会のブログに[「コラムリレー（第193回）不思議な旧石器時代の遺跡分布」](https://dounan.exblog.jp/32903116/)を投稿しました。考古学で利用頻度が高そうな分析を行ったので、手順を紹介します。内容は初心者向けです。

## パッケージを読み込み
利用するパッケージは`sf`、`terra`、`tidyverse`です。
`sf`はベクタデータ、`terra`はラスタデータの読み込みと加工に使います。
```R
# パッケージ読み込み
library(sf)
library(terra)
library(tidyverse)
```

## データ読込
DEMは国土地理院基盤地図情報数値標高モデル10mメッシュ、海岸線は国土交通省国土数値情報、遺跡ポイントデータは[埋蔵文化財包蔵地（GISデータ）【北海道】](https://www.harp.lg.jp/opendata/dataset/1245/resource/2024/%E5%9F%8B%E8%94%B5%E6%96%87%E5%8C%96%E8%B2%A1%E5%8C%85%E8%94%B5%E5%9C%B0.zip)を利用しました。
```R
# DEM
dem <-
  terra::rast("elevation_utm54/DEM_JGD2000utm54.tif") 
# 遺跡ポイント
site <-
  sf::st_read("site_JGD2000UTMzone54.gpkg")
# 海岸線
coast <-
  sf::st_read("CostLineHKD.gpkg") %>% 
  summarise()
```
埋蔵文化財包蔵地データはポイントデータとポリゴンデータの2種があるのですが、ポリゴンデータは`sf::st_centroid()`関数で重心位置を算出してポイントデータに変換しています。

読み込んだデータを描画します。
うまく読み込めているようです。
```R
# 遺跡表示
plot(dem)
plot(st_geometry(site), add = T)
plot(coast, add = T)
```
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60438/e941deef-a411-4711-be57-4e6414c0a3dc.png)

## DEMの標高値をポイントデータに付値する

遺跡立地点の標高値をDEMから取得します。ラスタの値を抽出するコマンドはsfにもterraにもあるのですが、圧倒的にterraパッケージが高速です。`terra::extract()`コマンドは重複する位置にある他のGISデータの値を取得します。
```R
# 遺跡立地地点の標高値を抽出
elv <-
  terra::extract(
    x = dem,
    y = vect(site) # terraのSpatVector形式に変換
  ) %>% 
  rename(Elv = DEM_JGD2000utm54) 
```
抽出した標高値はこのようなdata.frameに格納されます。
```R
> head(elv)
  ID Elv
1  1  10
2  2  16
3  3   5
4  4  21
5  5  22
6  6  25
```
続いて、抽出した標高値を元の遺跡ポイントに結合します。あわせて`dplyr::select()`関数で不要な項目を削除しています。
```R
# 遺跡ポイントに標高値を付値
site <-
  site %>% 
  bind_cols(elv$Elv) %>%
  dplyr::rename(Elv = ...23) %>% # 標高値をrename
  dplyr::select(名称, 所在地, 種別, 時代, 立地, 標高, 出土遺物, Elv)
```
Elvに標高が格納されました。
<table>
 <thead>
  <tr>
   <th style="text-align:left;"> 名称 </th>
   <th style="text-align:left;"> 所在地 </th>
   <th style="text-align:left;"> 種別 </th>
   <th style="text-align:left;"> 時代 </th>
   <th style="text-align:right;"> Elv </th>
   <th style="text-align:left;"> geom </th>
  </tr>
 </thead>
<tbody>
  <tr>
   <td style="text-align:left;"> 坊主山遺跡 </td>
   <td style="text-align:left;"> 江別市対雁1・2 </td>
   <td style="text-align:left;"> 墳墓 </td>
   <td style="text-align:left;"> 続縄文、擦文、アイヌ </td>
   <td style="text-align:right;"> 10 </td>
   <td style="text-align:left;"> POINT (543667.1 4774414) </td>
  </tr>
  <tr>
   <td style="text-align:left;"> 江別第2チャシ跡 </td>
   <td style="text-align:left;"> 江別市対雁125-1ほか </td>
   <td style="text-align:left;"> チャシ跡 </td>
   <td style="text-align:left;"> アイヌ </td>
   <td style="text-align:right;"> 16 </td>
   <td style="text-align:left;"> POINT (542825.3 4774351) </td>
  </tr>
  <tr>
   <td style="text-align:left;"> 美原遺跡 </td>
   <td style="text-align:left;"> 江別市美原河川敷地 </td>
   <td style="text-align:left;"> 遺物包含地 </td>
   <td style="text-align:left;"> 不明 </td>
   <td style="text-align:right;"> 5 </td>
   <td style="text-align:left;"> POINT (546291.3 4774576) </td>
  </tr>
</tbody>
</table>

## 旧石器出土遺跡と非旧石器の遺跡を区分する
一つの埋蔵文化財包蔵地に複数の時代の遺跡が存在する場合、「時代」のフィールドには複数の時期が入力されていることがあります。以下のコードで旧石器出土遺跡と旧石器が出土しない遺跡に区分します。この場合、旧石器出土遺跡である「paleo」属性をもつ遺跡には、旧石器以外の時代が含まれることになります。

`dplyr::mutate()`関数で新たに「class」フィールドを作成し、`stringr::str_detect()`関数で「旧石器」という単語が含まれる場合は「paleo」、含まれない場合は「non-paleo」という値を入力します。

```R
# 旧石器出土遺跡と非旧石器の遺跡の区分
site <-
  site %>% 
  dplyr::mutate(
    class = case_when(
      str_detect(時代,"旧石器") ~ "paleo", # 旧石器遺跡はpaleo
      !str_detect(時代,"旧石器") ~ "non-paleo" # 非旧石器遺跡はnon-paleo
    )
  )
```
<table>
 <thead>
  <tr>
   <th style="text-align:left;"> 名称 </th>
   <th style="text-align:left;"> 所在地 </th>
   <th style="text-align:left;"> 種別 </th>
   <th style="text-align:left;"> 時代 </th>
   <th style="text-align:right;"> Elv </th>
   <th style="text-align:left;"> geom </th>
   <th style="text-align:left;"> class </th>
  </tr>
 </thead>
<tbody>
  <tr>
   <td style="text-align:left;"> 坊主山遺跡 </td>
   <td style="text-align:left;"> 江別市対雁1・2 </td>
   <td style="text-align:left;"> 墳墓 </td>
   <td style="text-align:left;"> 続縄文、擦文、アイヌ </td>
   <td style="text-align:right;"> 10 </td>
   <td style="text-align:left;"> POINT (543667.1 4774414) </td>
   <td style="text-align:left;"> non-paleo </td>
  </tr>
  <tr>
   <td style="text-align:left;"> 江別第2チャシ跡 </td>
   <td style="text-align:left;"> 江別市対雁125-1ほか </td>
   <td style="text-align:left;"> チャシ跡 </td>
   <td style="text-align:left;"> アイヌ </td>
   <td style="text-align:right;"> 16 </td>
   <td style="text-align:left;"> POINT (542825.3 4774351) </td>
   <td style="text-align:left;"> non-paleo </td>
  </tr>
  <tr>
   <td style="text-align:left;"> 美原遺跡 </td>
   <td style="text-align:left;"> 江別市美原河川敷地 </td>
   <td style="text-align:left;"> 遺物包含地 </td>
   <td style="text-align:left;"> 不明 </td>
   <td style="text-align:right;"> 5 </td>
   <td style="text-align:left;"> POINT (546291.3 4774576) </td>
   <td style="text-align:left;"> non-paleo </td>
  </tr>
</tbody>
</table>

## 海岸線からの距離を算出
`sf::st_distance()`関数で遺跡ポイントから海岸線までの直線距離を計算します。
```R
# 海岸線からの距離計算
site_near <- 
  sf::st_distance(site, coast)
> head(site_near)
Units: [m]
         [,1]
[1,] 20758.26
[2,] 20135.15
[3,] 22734.56
[4,] 20824.10
[5,] 20456.33
[6,] 20408.00
```
# 遺跡データに海岸線からの距離を結合
標高を付値したのと同じやり方で、海岸からの距離を遺跡データに付値します。
```R
site <-
  site %>% 
  bind_cols(site_near) %>% 
  dplyr::rename(coast_dist = ...8)
```

<table>
 <thead>
  <tr>
   <th style="text-align:left;"> 名称 </th>
   <th style="text-align:left;"> 所在地 </th>
   <th style="text-align:left;"> 種別 </th>
   <th style="text-align:left;"> 時代 </th>
   <th style="text-align:right;"> Elv </th>
   <th style="text-align:left;"> class </th>
   <th style="text-align:right;"> coast_dist </th>
   <th style="text-align:left;"> geom </th>
  </tr>
 </thead>
<tbody>
  <tr>
   <td style="text-align:left;"> 坊主山遺跡 </td>
   <td style="text-align:left;"> 江別市対雁1・2 </td>
   <td style="text-align:left;"> 墳墓 </td>
   <td style="text-align:left;"> 続縄文、擦文、アイヌ </td>
   <td style="text-align:right;"> 10 </td>
   <td style="text-align:left;"> non-paleo </td>
   <td style="text-align:right;"> 20758.26 </td>
   <td style="text-align:left;"> POINT (543667.1 4774414) </td>
  </tr>
  <tr>
   <td style="text-align:left;"> 江別第2チャシ跡 </td>
   <td style="text-align:left;"> 江別市対雁125-1ほか </td>
   <td style="text-align:left;"> チャシ跡 </td>
   <td style="text-align:left;"> アイヌ </td>
   <td style="text-align:right;"> 16 </td>
   <td style="text-align:left;"> non-paleo </td>
   <td style="text-align:right;"> 20135.15 </td>
   <td style="text-align:left;"> POINT (542825.3 4774351) </td>
  </tr>
  <tr>
   <td style="text-align:left;"> 美原遺跡 </td>
   <td style="text-align:left;"> 江別市美原河川敷地 </td>
   <td style="text-align:left;"> 遺物包含地 </td>
   <td style="text-align:left;"> 不明 </td>
   <td style="text-align:right;"> 5 </td>
   <td style="text-align:left;"> non-paleo </td>
   <td style="text-align:right;"> 22734.56 </td>
   <td style="text-align:left;"> POINT (546291.3 4774576) </td>
  </tr>
</tbody>
</table>

# 海岸からの距離をヒストグラムで可視化
旧石器出土遺跡と旧石器が出土しない遺跡の海岸からの距離を比較します。
```R
site %>% 
  drop_na(paleo) %>% 
  ggplot() +
  geom_histogram(aes(x = coast_dist/1000)) + # 海岸からの距離をkmで表示
  facet_wrap(~class, scales = "free_y", ncol = 1) +
  labs(x = "Distance from coast(km)")
```
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60438/73d95b0e-501e-7e8a-4266-5bbdc4b08af4.png)

## 標高差をヒストグラムで可視化

```R
site %>%
  drop_na(paleo) %>% 
  ggplot() +
  geom_histogram(aes(x = Elv)) +
  facet_wrap(~class, scales = "free_y", ncol = 1) +
  scale_x_continuous(limits = c(0, 600)) +
  labs(x = "Elevation(m)") 
```
![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60438/8a70ab80-a4f1-2132-3b47-66a2dc697522.png)