3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[Plotly] 3D散布図で外れ値を強調する:外れ値・異常点を"立体"で見抜く

Posted at

はじめに

image.png

3Dデータは、場合によっては2Dよりも外れ値(異常点)が見つけやすい可視化方法のひとつです。
Plotlyの3D散布図では、色・サイズ・透明度・形状を組み合わせることで
異常点だけを自然に際立たせることができます。
今回は、外れ値を"目で見て判断できる"3D可視化を作っていきます。

この記事でできること

  • 3次元データの外れ値をPlotlyで強調表示する
  • 色(color)、サイズ(size)、透明度(opacity)で外れ値を分離
  • 簡単な外れ値検出(Zスコア方式)の実装
  • Colabでそのまま動くコード例

実装例: ランダム点群を生成する

まずは基本の3D散布図を作ります。

import plotly.graph_objects as go
import numpy as np

np.random.seed(0)

# 正規分布の点群
x, y, z = np.random.randn(3, 300)

fig = go.Figure(data=[go.Scatter3d(
    x=x, y=y, z=z,
    mode='markers',
    marker=dict(size=4, color='royalblue', opacity=0.7)
)])
fig.update_layout(title="Base 3D Scatter", scene=dict(aspectmode='data'))
fig.show()

まずは"普通の散布図"で外れ値を含めたデータを表示します。

image.png

外れ値を追加する

np.random.randn()だけでは外れ値が発生しにくいため、意図的に明確な外れ値を追加します。

# 明確な外れ値を3点追加
outlier_points = np.array([
    [5.0, 5.0, 5.0],
    [-4.5, -4.0, 4.5],
    [4.0, -5.0, -4.0]
])

x = np.append(x, outlier_points[:, 0])
y = np.append(y, outlier_points[:, 1])
z = np.append(z, outlier_points[:, 2])

これで確実に検出できる外れ値が含まれるようになります。

Zスコアで外れ値を検出する

以下は最もシンプルで動作確認しやすい方法です。

# Zスコアで外れ値判定
from scipy.stats import zscore

data = np.vstack([x, y, z]).T
zs = np.abs(zscore(data, axis=0))
outlier_mask = (zs > 3).any(axis=1)   # Zスコア3を超える点

# 検出数を確認
print(f"検出された外れ値の数: {outlier_mask.sum()}")
print(f"通常点の数: {(~outlier_mask).sum()}")
  • Zスコア > 3 を「外れ値」とするシンプルな基準
  • 任意にしきい値を変えてもOK
  • "どの軸方向でも外れ値なら外れ" というルール

image.png

Zスコアは各軸を独立に評価する簡易法であり、軸間の相関は考慮しません。より厳密な方法としてはマハラノビス距離やLOFなどがあります。

(zs > 3).any(axis=1) は「どの軸でもZスコアが3を超えたら外れ値」と判定します。

外れ値を色とサイズで強調表示する

外れ値(赤・大きい)と通常点(青・小さい)という2系統で可視化します。

fig = go.Figure()

# 通常点
fig.add_trace(go.Scatter3d(
    x=x[~outlier_mask], y=y[~outlier_mask], z=z[~outlier_mask],
    mode='markers',
    marker=dict(size=4, color='lightblue', opacity=0.5),
    name='Normal'
))

# 外れ値
fig.add_trace(go.Scatter3d(
    x=x[outlier_mask], y=y[outlier_mask], z=z[outlier_mask],
    mode='markers',
    marker=dict(size=8, color='crimson', opacity=1.0, symbol='diamond'),
    name='Outlier'
))

fig.update_layout(
    title="3D Scatter with Outlier Highlight",
    scene=dict(aspectmode='data')
)
fig.show()

外れ値を際立たせる属性設定

属性 外れ値への効果
色 = crimson 一番目立つ
size = 8 通常点の2倍
opacity = 1.0 完全不透明で"浮き上がる"
symbol = diamond 形状も差別化

3D空間でも外れ値が確実に見つかる表現になります。

image.png

距離ベースで外れ値を強調する

中心からの距離で判定する方法も実用的です。

center = np.array([x.mean(), y.mean(), z.mean()])
dist = np.sqrt((x-center[0])**2 + (y-center[1])**2 + (z-center[2])**2)

threshold = dist.mean() + 2 * dist.std()
outlier_mask2 = dist > threshold

print(f"距離ベースで検出された外れ値: {outlier_mask2.sum()}")

# 可視化
fig = go.Figure()

# 通常点
fig.add_trace(go.Scatter3d(
    x=x[~outlier_mask2], y=y[~outlier_mask2], z=z[~outlier_mask2],
    mode='markers',
    marker=dict(size=4, color='lightblue', opacity=0.5),
    name='Normal'
))

# 外れ値(距離ベース)
fig.add_trace(go.Scatter3d(
    x=x[outlier_mask2], y=y[outlier_mask2], z=z[outlier_mask2],
    mode='markers',
    marker=dict(size=8, color='orange', opacity=1.0, symbol='diamond'),
    name='Outlier (Distance)'
))

# 中心点を表示(オプション)
fig.add_trace(go.Scatter3d(
    x=[center[0]], y=[center[1]], z=[center[2]],
    mode='markers',
    marker=dict(size=10, color='green', symbol='cross'),
    name='Center'
))

fig.update_layout(
    title="Distance-based Outlier Detection",
    scene=dict(aspectmode='data')
)
fig.show()

球状のデータの"外側"にある点が外れ値として強調されます。

image.png

トラブルシュート

症状 原因・対処
外れ値が見えづらい 色をcrimson・sizeを10〜12に調整
外れ値が多すぎる Zスコア閾値 3 → 3.5 などに変更
外れ値が1個も検出されない 意図的に外れ値を追加するか、閾値を 3 → 2.5 に下げる
正常点が濃く重なる opacity を 0.4〜0.6 に下げて透明に
点が重すぎてColabが重い 5000点以上は subsample 推奨

PlotlyはWebGL対応で10万点でも動く場合がありますが、ブラウザや環境によっては重くなるため、必要に応じてサンプリングを推奨します。

まとめ

image.png

外れ値は Zスコアや距離ベースで手軽に検出でき、色・サイズ・透明度などで強調できます。
3D表示は距離感をそのまま視覚化できるため、平面では見逃しがちな“飛び出し”が直感的に見つかります。
異常検知やセンサーデータ、PCA可視化など幅広い用途で役立つ表現です。

参考情報

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?