---
# System prepended metadata

title: 在長期時頻譜圖上進行群聚分析
tags: [soundscape viewer, ' tutorial', ' ecoacoustics', ' clustering']

---

---
title: 在長期時頻譜圖上進行群聚分析
description: Spectrogram-based clustering
tags: soundscape viewer, tutorial, ecoacoustics, clustering
disqus: hackmd
---

# 在長期時頻譜圖上執行群聚分析

無論是何種環境，在長時間錄音中幾乎都可以收錄到大量聲音事件，這些聲音事件往往具有相對應的生態意義，例如：不同種類的昆蟲聲音、魚類發聲，甚至是不同類型的施工機具。要如何辨認聲音事件的組成與各種聲音事件的特性，是聲景生態學中重要的一環。但目前仍然沒有一個完整的聲音圖鑑，可以完整收錄地球上各式各樣環境中的聲音，在這種情況下我要如何辨別各種聲音事件?

透過機器學習，我們可以應用群聚分析來量化各種聲音事件彼此之間的相似度，把相似的分為同一類，不相似的則是為不同的聲音事件。舉例來說，我們可以聲音的頻譜特性作為特徵，以群聚分析來辨認出具有不同音色的聲音事件。

## 群聚分析
Soundscape Viewer 的群聚分析，主要目標是希望從 LTS 來快速辨認各種具有不同頻譜特性的聲音事件。首先，會利用主成分分析 (Principle Component Analysis) 來降低特徵維度，也就是資料欄位的數量。接著，再運用 K-means clustering 分析降維過後的資料。在這個分析中，有三個參數必須定義：
* 聲音事件的數量 (k)：大於1的整數，或是介於0-1之間的數值
* 原始資料在降維過後，能夠被主成分解釋的比例 (pca_percent)：介於0-1之間的數值
* 方法 (method)：'kmeans'

當 k 被設為大於1的整數時，則表示我們假設資料中有 k 個具有不同頻譜特性的聲音事件。但如果我們不清楚有多少聲音事件時怎麼辦? 在這種情況，我們可以設定 k 為介於 0-1 之間的數值，並要求 K-means clustering 嘗試不同數目的聲音事件 ($N$)，並量測每個分群中的資料變異值 ($V$)，以及所有分群的平均資料變異值占未分群的資料變異度的比例 ($V_{total}$) 後，便得知此分群結果能夠解釋多少比例的資料變異 ($R$)。若是分群結果能夠解釋的比例低於 k，則嘗試增加聲音事件的數目，一直到分群結果能解釋的資料變異比例高於指定的閾值為止。

> $V_{mean} = \dfrac{\sum_{k=1}^{N}V_{k}}{N}$
> $R = 1-\dfrac{V_{mean}}{V_{total}}$

在資料降維的部分，若是指定較高的 pca_percent，一般來說就會有較多的主成分被納入群聚分析，較低的 pca_percent 則會有較少的主成分被納入群聚分析。

關於群聚分析的方法，目前 Soundscape Viewer 僅支持kmeans一種方法，未來會持續增加更多群聚分析的方法，例如 Sparse NMF 或是 Gaussian Mixture Models。

將模型參數指定完畢之後，便可以將輸入資料準備好，執行群聚分析。可以嘗試看看當指定 k = 5 時，和指定 k = 0.9 時，兩個模型產生的分群結果會有甚麼差異。

```python=
from soundscape_IR.soundscape_viewer import clustering
cluster_result=clustering(k=2, pca_percent=0.9, method='kmeans')
cluster_result.run(input_data=separation_result.separation[0], f=LTS.f)
```
完成群聚分析之後，我們可以利用 **clustering.plot_cluster_feature**來繪製各分群的頻譜特性，以及該分群內所有資料的頻譜變動範圍 (第5百分位數至第95百分位數之範圍)。
```python=4
cluster_result.plot_cluster_feature(cluster_no=1, freq_scale='linear')
```
最後，我們可以利用 **clustering.save_cluster_feature** 來將所有分群結果的頻譜特性資料儲存為 csv 檔案。

```python=5
cluster_result.save_cluster_feature(filename='S1_Cluster_feature.csv', folder_id=[])
```