📋 このステップで学ぶこと
- 時系列データとは何か、なぜ重要なのか
- pandasのDatetimeIndexを使った日付データの処理
- 基本的な時系列グラフの作成方法
- ローソク足チャートで株価データを可視化する方法
- 移動平均線でトレンドを分析する方法
- レンジスライダーでインタラクティブに期間を操作する方法
- 異常検知やトレンド分析の実務活用例
⏰ 1. 時系列データとは
時系列データの概要
時系列データ(Time Series Data)とは、時間の経過とともに記録されたデータのことです。株価、売上、気温、アクセス数など、「いつ」「どのくらいだったか」を記録したデータはすべて時系列データです。
時系列データの最大の特徴は、データの順番に意味があることです。たとえば、売上データをランダムに並べ替えると、「先月に比べて増えた」といった分析ができなくなります。
💡 時系列データを身近な例で考えると
時系列データは「日記」のようなものです。毎日の出来事を日付順に記録することで、「先週に比べて体調が良くなった」「去年の同じ時期にも風邪を引いていた」といったパターンが見えてきます。
データ分析でも同じで、時系列データを可視化することで、トレンド(傾向)、季節性(周期)、異常値などを発見できます。
📊 時系列データの分析目的
| 分析目的 |
説明 |
活用例 |
| トレンド分析 |
長期的な傾向を把握 |
売上が年々増加しているか確認 |
| 季節性の発見 |
周期的なパターンを検出 |
夏に売れる商品を特定 |
| 異常検知 |
通常とは異なる値を発見 |
不正アクセスや機器故障を検出 |
| 予測 |
将来の値を推定 |
来月の売上を予測して在庫を調整 |
| 比較 |
複数の時系列の関係性分析 |
広告費と売上の関係を分析 |
📝 時系列データの例
| 頻度 |
データ例 |
分析のポイント |
| 秒・分単位 |
センサーデータ、株価ティック |
リアルタイム監視、異常検知 |
| 時間単位 |
電力消費、交通量、気温 |
1日の中のパターン分析 |
| 日次 |
株価終値、売上、訪問者数 |
週ごとのパターン、曜日効果 |
| 月次 |
月間売上高、在庫数 |
季節性、年間トレンド |
| 年次 |
GDP、人口、年間利益 |
長期トレンド、構造変化 |
💡 時系列可視化の基本ルール
| ルール |
説明 |
理由 |
| X軸は時間 |
常に日付・時刻を横軸に |
時間の流れを直感的に理解 |
| Y軸は観測値 |
価格、量などを縦軸に |
値の変化を視覚的に表現 |
| 線グラフが基本 |
連続的な変化を線で表現 |
データの連続性を示す |
| 色分けで比較 |
複数系列は色で区別 |
異なるデータを同時に比較 |
📅 2. pandasでの日付データ処理
なぜpandasを使うのか
時系列データを扱うには、日付の計算(1週間後は何日?)や期間の集計(月ごとの合計は?)が必要です。pandasには、これらを簡単に行うための機能が豊富に用意されています。
日付の連続データを作成する
まず、pd.date_range()を使って、日付の連続データを作成してみましょう。
# ライブラリを読み込む
import pandas as pd
import numpy as np
📝 インポートの意味
| コード |
意味 |
なぜ必要か |
| import pandas as pd |
pandasをpdとして読み込み |
日付データの処理に使用 |
| import numpy as np |
numpyをnpとして読み込み |
ランダムデータの生成に使用 |
# 日付の連続データを作成
dates = pd.date_range(
start=’2024-01-01′, # 開始日
end=’2024-12-31′, # 終了日
freq=’D’ # 頻度(D = 日次)
)
print(f”日数: {len(dates)}日”)
print(f”最初の5日:”)
print(dates[:5])
【実行結果】
日数: 366日
最初の5日:
DatetimeIndex([‘2024-01-01’, ‘2024-01-02’, ‘2024-01-03’, ‘2024-01-04’,
‘2024-01-05′],
dtype=’datetime64[ns]’, freq=’D’)
📝 pd.date_range()のパラメータ
| パラメータ |
意味 |
設定例 |
| start |
開始日 |
‘2024-01-01’ |
| end |
終了日 |
‘2024-12-31’ |
| freq |
頻度(間隔) |
‘D’(日次)、’W’(週次)、’M’(月次) |
| periods |
生成する日数 |
periods=365(endの代わりに使用可) |
サンプルの売上データを作成する
日付データができたら、それに対応する売上データを作成します。ここではランダムな数値を使いますが、実際の分析ではCSVファイルなどから読み込みます。
# ランダムな売上データを生成
np.random.seed(42) # 乱数の固定(再現性のため)
sales = np.random.randint(100, 500, size=len(dates))
# DataFrameに変換(日付をインデックスに設定)
df = pd.DataFrame({
‘売上’: sales
}, index=dates)
print(“データの先頭:”)
print(df.head())
【実行結果】
データの先頭:
売上
2024-01-01 202
2024-01-02 286
2024-01-03 479
2024-01-04 410
2024-01-05 144
📝 コードの意味
| コード |
意味 |
なぜ必要か |
| np.random.seed(42) |
乱数の種を固定 |
毎回同じ結果を再現するため |
| np.random.randint(100, 500, size=…) |
100〜499の整数をランダム生成 |
サンプルデータを作成するため |
| index=dates |
日付をDataFrameのインデックスに |
日付でデータを検索・集計するため |
期間ごとの集計(resample)
日次データを月次や週次に集計するには、resample()メソッドを使います。これは時系列データ特有の強力な機能です。
# 月ごとの合計を計算
月次売上 = df.resample(‘M’).sum()
print(“月次売上:”)
print(月次売上.head())
【実行結果】
月次売上:
売上
2024-01-31 9234
2024-02-29 8567
2024-03-31 9102
2024-04-30 8889
2024-05-31 9345
# 週ごとの平均を計算
週次平均 = df.resample(‘W’).mean()
print(“週次平均:”)
print(週次平均.head())
# 特定期間のデータを抽出
Q1売上 = df[‘2024-01′:’2024-03’] # 1月〜3月
print(f”第1四半期の合計売上: {Q1売上[‘売上’].sum():,}円”)
💡 resample()の頻度指定一覧
| コード |
頻度 |
使用例 |
| ‘D’ |
日次(Day) |
df.resample(‘D’).sum() |
| ‘W’ |
週次(Week) |
df.resample(‘W’).mean() |
| ‘M’ |
月次(Month) |
df.resample(‘M’).sum() |
| ‘Q’ |
四半期(Quarter) |
df.resample(‘Q’).sum() |
| ‘Y’ |
年次(Year) |
df.resample(‘Y’).sum() |
| ‘H’ |
時間(Hour) |
df.resample(‘H’).mean() |
Matplotlibで時系列グラフを作成
まずは基本のMatplotlibで時系列グラフを作成してみましょう。
# =========================================
# 【実践】基本的な時系列グラフ(Matplotlib)
# =========================================
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# データ作成
dates = pd.date_range(‘2024-01-01’, ‘2024-12-31′, freq=’D’)
np.random.seed(42)
df = pd.DataFrame({
‘売上’: np.random.randint(100, 500, size=len(dates))
}, index=dates)
# グラフ作成
plt.figure(figsize=(12, 5))
plt.plot(df.index, df[‘売上’], linewidth=1, alpha=0.7)
plt.title(‘2024年 日次売上推移’, fontsize=16, fontweight=’bold’)
plt.xlabel(‘日付’, fontsize=12)
plt.ylabel(‘売上(円)’, fontsize=12)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
📊 3. Plotlyでのインタラクティブ時系列
なぜPlotlyを使うのか
Matplotlibは静的なグラフを作成しますが、Plotlyを使うとインタラクティブなグラフが作れます。マウスホバーで値を確認したり、ズームしたりできるため、時系列データの分析に非常に便利です。
基本的なインタラクティブ時系列グラフ
コードが長いので、スマートフォンでは横スクロールして確認してください。
# =========================================
# 【実践】インタラクティブ時系列グラフ(Plotly)
# =========================================
import plotly.graph_objects as go
import pandas as pd
import numpy as np
# データ作成
dates = pd.date_range(‘2024-01-01’, ‘2024-12-31′, freq=’D’)
np.random.seed(42)
df = pd.DataFrame({
‘売上’: np.random.randint(100, 500, size=len(dates))
}, index=dates)
# Plotlyグラフを作成
fig = go.Figure()
# 折れ線を追加
fig.add_trace(go.Scatter(
x=df.index,
y=df[‘売上’],
mode=’lines’,
name=’日次売上’,
line=dict(color=’#3498DB’, width=2),
hovertemplate=’%{x|%Y-%m-%d}
売上: %{y:,}円‘
))
# レイアウトを設定
fig.update_layout(
title=’📈 2024年 日次売上推移(インタラクティブ)’,
xaxis_title=’日付’,
yaxis_title=’売上(円)’,
hovermode=’x unified’,
height=500,
font=dict(size=12)
)
fig.show()
📝 Plotlyのコードの意味
| コード |
意味 |
なぜ必要か |
| go.Figure() |
空のグラフを作成 |
グラフの入れ物を用意 |
| fig.add_trace() |
グラフに線やマーカーを追加 |
データを可視化するため |
| go.Scatter() |
折れ線グラフまたは散布図 |
時系列は折れ線が基本 |
| hovertemplate |
ホバー時の表示形式 |
マウスを当てたとき見やすくする |
| hovermode=’x unified’ |
同じX座標の全データを表示 |
複数系列の比較に便利 |
複数店舗の売上を比較する
複数の時系列を重ねて表示し、移動平均線を追加することで、トレンドの比較が容易になります。
コードが長いので、スマートフォンでは横スクロールして確認してください。
# =========================================
# 【実践】複数店舗の売上比較(移動平均付き)
# =========================================
import plotly.graph_objects as go
import pandas as pd
import numpy as np
# 複数店舗のデータを作成
dates = pd.date_range(‘2024-01-01’, ‘2024-12-31′, freq=’D’)
np.random.seed(42)
df = pd.DataFrame({
‘東京店’: np.random.randint(200, 600, size=len(dates)),
‘大阪店’: np.random.randint(150, 500, size=len(dates)),
‘名古屋店’: np.random.randint(100, 400, size=len(dates))
}, index=dates)
# 7日移動平均を計算
for col in df.columns:
df[f'{col}_MA7′] = df[col].rolling(window=7).mean()
# グラフ作成
fig = go.Figure()
# 各店舗の実データと移動平均
colors = [‘#E74C3C’, ‘#3498DB’, ‘#2ECC71’]
for i, col in enumerate([‘東京店’, ‘大阪店’, ‘名古屋店’]):
# 実データ(薄く表示)
fig.add_trace(go.Scatter(
x=df.index,
y=df[col],
mode=’lines’,
name=col,
line=dict(color=colors[i], width=1),
opacity=0.5
))
# 移動平均線(太く表示)
fig.add_trace(go.Scatter(
x=df.index,
y=df[f'{col}_MA7′],
mode=’lines’,
name=f'{col}(7日移動平均)’,
line=dict(color=colors[i], width=3)
))
fig.update_layout(
title=’📊 店舗別売上比較(7日移動平均付き)’,
xaxis_title=’日付’,
yaxis_title=’売上(円)’,
hovermode=’x unified’,
height=600,
legend=dict(orientation=’h’, yanchor=’bottom’, y=1.02, xanchor=’right’, x=1)
)
fig.show()
💡 移動平均とは
移動平均(Moving Average)は、一定期間のデータの平均値を連続的に計算したものです。日々の変動(ノイズ)を滑らかにして、トレンドを見やすくします。
| 期間 |
特徴 |
用途 |
| 短期(5〜7日) |
元データに近い動き |
短期的な変動を把握 |
| 中期(20〜30日) |
滑らかな曲線 |
月次トレンドの把握 |
| 長期(50〜200日) |
大きな傾向のみ |
長期トレンドの把握 |
📉 4. ローソク足チャート(株価データ)
ローソク足チャートとは
ローソク足チャートは、株価や為替レートを表示するための特殊なグラフです。1本のローソクで、始値、終値、高値、安値の4つの値を同時に表現できます。
🕯️ ローソク足の読み方
| 要素 |
意味 |
読み取れること |
| 実体(ボディ) |
始値と終値の差 |
その日の値動きの大きさ |
| 上ヒゲ |
高値までの距離 |
一時的に上がったが戻った |
| 下ヒゲ |
安値までの距離 |
一時的に下がったが戻った |
| 緑色(陽線) |
終値 > 始値 |
上昇した日 |
| 赤色(陰線) |
終値 < 始値 |
下落した日 |
【ローソク足の図解】
高値 ─── 上ヒゲ ───┐
│
┌─────────────────┐ │ 陽線(緑): 終値 > 始値
│ 終値 │ │ 陰線(赤): 終値 < 始値
│ (実体) │ │
│ 始値 │ │
└─────────────────┘ │
│
安値 ─── 下ヒゲ ───┘
ローソク足チャートを作成する
Plotlyのgo.Candlestick()を使ってローソク足チャートを作成します。まず、株価データを模擬的に生成します。
コードが長いので、スマートフォンでは横スクロールして確認してください。
# =========================================
# 【実践】ローソク足チャート
# =========================================
import plotly.graph_objects as go
import pandas as pd
import numpy as np
# 株価データを模擬的に生成
dates = pd.date_range(‘2024-01-01’, ‘2024-12-31′, freq=’D’)
np.random.seed(42)
# ランダムウォークで株価を生成
open_price = 10000
prices = [open_price]
for _ in range(len(dates)-1):
change = np.random.randn() * 100
prices.append(prices[-1] + change)
# DataFrameに変換
df = pd.DataFrame(index=dates)
df[‘始値’] = prices
df[‘終値’] = df[‘始値’] + np.random.randn(len(df)) * 50
df[‘高値’] = df[[‘始値’, ‘終値’]].max(axis=1) + np.abs(np.random.randn(len(df)) * 30)
df[‘安値’] = df[[‘始値’, ‘終値’]].min(axis=1) – np.abs(np.random.randn(len(df)) * 30)
# ローソク足チャートを作成
fig = go.Figure(data=[go.Candlestick(
x=df.index,
open=df[‘始値’],
high=df[‘高値’],
low=df[‘安値’],
close=df[‘終値’],
name=’株価’
)])
fig.update_layout(
title=’📊 株価チャート(ローソク足)’,
yaxis_title=’価格(円)’,
xaxis_rangeslider_visible=False,
height=600
)
fig.show()
移動平均線を追加する
株価チャートには、トレンドを把握するために移動平均線を重ねるのが一般的です。短期(5日)、中期(25日)、長期(75日)の3本を追加してみましょう。
コードが長いので、スマートフォンでは横スクロールして確認してください。
# =========================================
# 【実践】株価チャート + 移動平均線
# =========================================
import plotly.graph_objects as go
import pandas as pd
import numpy as np
# 株価データを生成(前のコードと同じ)
dates = pd.date_range(‘2024-01-01’, ‘2024-12-31′, freq=’D’)
np.random.seed(42)
open_price = 10000
prices = [open_price]
for _ in range(len(dates)-1):
change = np.random.randn() * 100
prices.append(prices[-1] + change)
df = pd.DataFrame(index=dates)
df[‘始値’] = prices
df[‘終値’] = df[‘始値’] + np.random.randn(len(df)) * 50
df[‘高値’] = df[[‘始値’, ‘終値’]].max(axis=1) + np.abs(np.random.randn(len(df)) * 30)
df[‘安値’] = df[[‘始値’, ‘終値’]].min(axis=1) – np.abs(np.random.randn(len(df)) * 30)
# 移動平均線を計算
df[‘MA5’] = df[‘終値’].rolling(window=5).mean() # 5日移動平均
df[‘MA25’] = df[‘終値’].rolling(window=25).mean() # 25日移動平均
df[‘MA75’] = df[‘終値’].rolling(window=75).mean() # 75日移動平均
# グラフ作成
fig = go.Figure()
# ローソク足
fig.add_trace(go.Candlestick(
x=df.index,
open=df[‘始値’],
high=df[‘高値’],
low=df[‘安値’],
close=df[‘終値’],
name=’株価’
))
# 移動平均線を追加
fig.add_trace(go.Scatter(
x=df.index, y=df[‘MA5′],
mode=’lines’, name=’5日移動平均’,
line=dict(color=’orange’, width=1)
))
fig.add_trace(go.Scatter(
x=df.index, y=df[‘MA25′],
mode=’lines’, name=’25日移動平均’,
line=dict(color=’blue’, width=2)
))
fig.add_trace(go.Scatter(
x=df.index, y=df[‘MA75′],
mode=’lines’, name=’75日移動平均’,
line=dict(color=’red’, width=2)
))
fig.update_layout(
title=’📈 株価チャート + 移動平均線’,
yaxis_title=’価格(円)’,
xaxis_rangeslider_visible=False,
height=600,
hovermode=’x unified’
)
fig.show()
🎛️ 5. レンジスライダーとズーム機能
レンジスライダーとは
レンジスライダーは、グラフの下部に表示される操作バーで、表示期間を自由に変更できます。長期間のデータを分析するときに非常に便利です。
さらに、期間選択ボタンを追加すると、「1ヶ月」「3ヶ月」「1年」などをワンクリックで切り替えられます。
コードが長いので、スマートフォンでは横スクロールして確認してください。
# =========================================
# 【実践】レンジスライダー付きグラフ
# =========================================
import plotly.graph_objects as go
import pandas as pd
import numpy as np
# 5年分のデータを作成
dates = pd.date_range(‘2020-01-01’, ‘2024-12-31′, freq=’D’)
np.random.seed(42)
df = pd.DataFrame({
‘売上’: np.random.randint(100, 500, size=len(dates))
}, index=dates)
# グラフ作成
fig = go.Figure()
fig.add_trace(go.Scatter(
x=df.index,
y=df[‘売上’],
mode=’lines’,
name=’日次売上’,
line=dict(color=’#3498DB’, width=1)
))
fig.update_layout(
title=’📊 売上推移(レンジスライダー付き)’,
xaxis_title=’日付’,
yaxis_title=’売上(円)’,
height=600,
xaxis=dict(
rangeselector=dict(
buttons=list([
dict(count=1, label=’1ヶ月’, step=’month’, stepmode=’backward’),
dict(count=3, label=’3ヶ月’, step=’month’, stepmode=’backward’),
dict(count=6, label=’6ヶ月’, step=’month’, stepmode=’backward’),
dict(count=1, label=’1年’, step=’year’, stepmode=’backward’),
dict(step=’all’, label=’全期間’)
])
),
rangeslider=dict(visible=True),
type=’date’
)
)
fig.show()
💡 レンジスライダーの操作方法
| 操作 |
方法 |
効果 |
| 期間選択 |
上部のボタンをクリック |
1ヶ月、3ヶ月などに即座に切り替え |
| 範囲変更 |
スライダーの端をドラッグ |
表示期間を細かく調整 |
| スクロール |
スライダーの中央をドラッグ |
同じ期間幅で時間を移動 |
| ズーム |
グラフ上でドラッグして範囲選択 |
選択した範囲を拡大表示 |
複数のKPIを同時に表示する
サブプロットを使うと、複数の指標を縦に並べて表示できます。X軸(時間軸)を共有することで、指標間の関係を分析しやすくなります。
コードが長いので、スマートフォンでは横スクロールして確認してください。
# =========================================
# 【実践】ECサイト KPIダッシュボード
# =========================================
from plotly.subplots import make_subplots
import plotly.graph_objects as go
import pandas as pd
import numpy as np
# データ作成
dates = pd.date_range(‘2024-01-01’, ‘2024-12-31′, freq=’D’)
np.random.seed(42)
df = pd.DataFrame({
‘売上’: np.random.randint(100, 500, size=len(dates)),
‘訪問者数’: np.random.randint(50, 200, size=len(dates))
}, index=dates)
# コンバージョン率を計算
df[‘CVR’] = (df[‘売上’] / df[‘訪問者数’] * 100).round(2)
# サブプロット作成(3行1列)
fig = make_subplots(
rows=3, cols=1,
subplot_titles=(‘売上推移’, ‘訪問者数推移’, ‘コンバージョン率’),
vertical_spacing=0.08,
shared_xaxes=True # X軸を共有
)
# 売上グラフ
fig.add_trace(
go.Scatter(x=df.index, y=df[‘売上’], name=’売上’, line=dict(color=’#2ECC71′)),
row=1, col=1
)
# 訪問者数グラフ
fig.add_trace(
go.Scatter(x=df.index, y=df[‘訪問者数’], name=’訪問者数’, line=dict(color=’#3498DB’)),
row=2, col=1
)
# CVRグラフ
fig.add_trace(
go.Scatter(x=df.index, y=df[‘CVR’], name=’CVR’, line=dict(color=’#E74C3C’)),
row=3, col=1
)
fig.update_layout(
height=900,
title_text=’📊 ECサイト KPI ダッシュボード’,
showlegend=False,
hovermode=’x unified’
)
# Y軸ラベル
fig.update_yaxes(title_text=’売上(円)’, row=1, col=1)
fig.update_yaxes(title_text=’訪問者数(人)’, row=2, col=1)
fig.update_yaxes(title_text=’CVR(%)’, row=3, col=1)
fig.show()
💼 6. 実務での活用例
例1: 売上のトレンド分析
線形回帰を使って、売上の長期的なトレンドを可視化します。「年間でどのくらい成長しているか」を数値で把握できます。
コードが長いので、スマートフォンでは横スクロールして確認してください。
# =========================================
# 【実践】売上トレンド分析
# =========================================
import plotly.graph_objects as go
import pandas as pd
import numpy as np
from scipy import stats
# 売上データ(上昇トレンド + 季節変動 + ノイズ)
dates = pd.date_range(‘2022-01-01’, ‘2024-12-31′, freq=’D’)
trend = np.linspace(100, 400, len(dates)) # 上昇トレンド
seasonal = 50 * np.sin(2 * np.pi * np.arange(len(dates)) / 365) # 季節変動
noise = np.random.randn(len(dates)) * 30 # ノイズ
sales = trend + seasonal + noise
df = pd.DataFrame({‘売上’: sales}, index=dates)
# 線形回帰でトレンドラインを計算
x = np.arange(len(df))
slope, intercept, r_value, p_value, std_err = stats.linregress(x, df[‘売上’])
trendline = slope * x + intercept
# グラフ作成
fig = go.Figure()
# 実データ
fig.add_trace(go.Scatter(
x=df.index, y=df[‘売上’],
mode=’lines’, name=’実績売上’,
line=dict(color=’lightblue’, width=1), opacity=0.7
))
# トレンドライン
fig.add_trace(go.Scatter(
x=df.index, y=trendline,
mode=’lines’, name=’トレンドライン’,
line=dict(color=’red’, width=3, dash=’dash’)
))
# 30日移動平均
fig.add_trace(go.Scatter(
x=df.index, y=df[‘売上’].rolling(window=30).mean(),
mode=’lines’, name=’30日移動平均’,
line=dict(color=’green’, width=2)
))
fig.update_layout(
title=’📈 売上トレンド分析(2022-2024)’,
xaxis_title=’日付’, yaxis_title=’売上(万円)’,
height=600, hovermode=’x unified’
)
# 成長率を注釈で追加
fig.add_annotation(
x=df.index[-1], y=trendline[-1],
text=f’年間成長率: {(slope * 365):.1f}万円/年’,
showarrow=True, arrowhead=2, bgcolor=’yellow’, opacity=0.8
)
fig.show()
例2: 異常検知(外れ値の可視化)
3シグマ法を使って、通常とは異なる値(異常値)を検出し、視覚的に強調表示します。品質管理やセキュリティ監視に活用できます。
コードが長いので、スマートフォンでは横スクロールして確認してください。
# =========================================
# 【実践】異常検知(3シグマ法)
# =========================================
import plotly.graph_objects as go
import pandas as pd
import numpy as np
# データ作成(異常値を含む)
dates = pd.date_range(‘2024-01-01’, ‘2024-12-31′, freq=’D’)
np.random.seed(42)
sales = np.random.randint(200, 400, size=len(dates))
# ランダムに異常値を追加
anomaly_indices = np.random.choice(len(sales), size=10, replace=False)
sales[anomaly_indices] = np.random.randint(600, 900, size=10)
df = pd.DataFrame({‘売上’: sales}, index=dates)
# 異常値検出(3シグマ法)
mean = df[‘売上’].mean()
std = df[‘売上’].std()
upper_limit = mean + 3 * std # 上限閾値
lower_limit = mean – 3 * std # 下限閾値
df[‘異常’] = (df[‘売上’] > upper_limit) | (df[‘売上’] < lower_limit)
# グラフ作成
fig = go.Figure()
# 正常データ(青い点)
normal_df = df[~df['異常']]
fig.add_trace(go.Scatter(
x=normal_df.index, y=normal_df['売上'],
mode='markers', name='正常値',
marker=dict(color='blue', size=5)
))
# 異常データ(赤い×)
anomaly_df = df[df['異常']]
fig.add_trace(go.Scatter(
x=anomaly_df.index, y=anomaly_df['売上'],
mode='markers', name='異常値',
marker=dict(color='red', size=12, symbol='x')
))
# 閾値ライン
fig.add_hline(y=upper_limit, line_dash='dash', line_color='red',
annotation_text='上限閾値')
fig.add_hline(y=mean, line_dash='dot', line_color='green',
annotation_text='平均値')
fig.add_hline(y=lower_limit, line_dash='dash', line_color='red',
annotation_text='下限閾値')
fig.update_layout(
title='🚨 売上異常検知(3シグマ法)',
xaxis_title='日付', yaxis_title='売上(円)',
height=600, hovermode='x unified'
)
fig.show()
print(f"異常値検出数: {df['異常'].sum()}件")
【3シグマ法とは】
統計学の「正規分布」を利用した異常検知の手法です。
・平均値(μ)から標準偏差(σ)の3倍以内に、
データの約99.7%が収まる
・3シグマを超える値は「異常」と判定
上限閾値 = 平均 + 3 × 標準偏差
下限閾値 = 平均 – 3 × 標準偏差
→ この範囲外のデータを異常値として検出!
📝 STEP 26 のまとめ
✅ このステップで学んだこと
| トピック |
重要ポイント |
| 時系列データ |
時間順に並んだデータ、順序に意味がある |
| DatetimeIndex |
pd.date_range()で日付範囲を作成 |
| resample() |
日次→月次などの期間集計 |
| ローソク足チャート |
始値・終値・高値・安値を1本で表現 |
| 移動平均線 |
rolling().mean()でトレンドを把握 |
| レンジスライダー |
rangeslider、rangeselectorで期間操作 |
| 異常検知 |
3シグマ法で外れ値を検出・可視化 |
💡 最重要ポイント
時系列データの可視化は、トレンドや季節性、異常値を発見するために不可欠です。
移動平均でノイズを除去し、レンジスライダーで詳細な期間分析が可能になります。ローソク足チャートは金融データに、異常検知は品質管理やセキュリティに活用できます。
次のステップでは、ネットワーク図でつながりのあるデータを可視化する方法を学びます!
📝 実践演習
演習 1
基礎
2024年1年間の日次データを作成し、Matplotlibで折れ線グラフを表示してください。
【解答コード】
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
dates = pd.date_range(‘2024-01-01’, ‘2024-12-31′, freq=’D’)
df = pd.DataFrame({
‘値’: np.random.randint(100, 500, size=len(dates))
}, index=dates)
plt.figure(figsize=(12, 5))
plt.plot(df.index, df[‘値’])
plt.title(‘2024年データ推移’)
plt.xlabel(‘日付’)
plt.ylabel(‘値’)
plt.grid(True)
plt.show()
ポイント:pd.date_range()で日付を生成し、それをDataFrameのindexに設定します。
演習 2
応用
株価データを作成し、ローソク足チャートと5日移動平均線を表示してください。
【解答コード】
import plotly.graph_objects as go
import pandas as pd
import numpy as np
dates = pd.date_range(‘2024-01-01’, ‘2024-12-31′, freq=’D’)
df = pd.DataFrame(index=dates)
df[‘終値’] = 10000 + np.random.randn(len(df)).cumsum() * 50
df[‘始値’] = df[‘終値’] + np.random.randn(len(df)) * 30
df[‘高値’] = df[[‘始値’, ‘終値’]].max(axis=1) + np.abs(np.random.randn(len(df)) * 20)
df[‘安値’] = df[[‘始値’, ‘終値’]].min(axis=1) – np.abs(np.random.randn(len(df)) * 20)
df[‘MA5’] = df[‘終値’].rolling(5).mean()
fig = go.Figure()
fig.add_trace(go.Candlestick(
x=df.index, open=df[‘始値’], high=df[‘高値’],
low=df[‘安値’], close=df[‘終値’], name=’株価’
))
fig.add_trace(go.Scatter(
x=df.index, y=df[‘MA5′], mode=’lines’,
name=’5日移動平均’, line=dict(color=’orange’, width=2)
))
fig.update_layout(title=’株価チャート’, height=600)
fig.show()
ポイント:go.Candlestick()でローソク足を作成し、rolling(5).mean()で5日移動平均を計算します。
演習 3
発展
2つの店舗の売上を比較し、レンジスライダー付きで表示してください。7日移動平均も追加してください。
【解答コード】
import plotly.graph_objects as go
import pandas as pd
import numpy as np
dates = pd.date_range(‘2024-01-01’, ‘2024-12-31′, freq=’D’)
df = pd.DataFrame({
‘A店’: np.random.randint(200, 500, size=len(dates)),
‘B店’: np.random.randint(150, 450, size=len(dates))
}, index=dates)
df[‘A店_MA7’] = df[‘A店’].rolling(7).mean()
df[‘B店_MA7’] = df[‘B店’].rolling(7).mean()
fig = go.Figure()
fig.add_trace(go.Scatter(x=df.index, y=df[‘A店’], mode=’lines’, name=’A店’, opacity=0.5))
fig.add_trace(go.Scatter(x=df.index, y=df[‘A店_MA7′], mode=’lines’, name=’A店(MA7)’, line=dict(width=3)))
fig.add_trace(go.Scatter(x=df.index, y=df[‘B店’], mode=’lines’, name=’B店’, opacity=0.5))
fig.add_trace(go.Scatter(x=df.index, y=df[‘B店_MA7′], mode=’lines’, name=’B店(MA7)’, line=dict(width=3)))
fig.update_layout(
title=’店舗別売上比較’,
xaxis=dict(rangeslider=dict(visible=True), type=’date’),
height=600
)
fig.show()
ポイント:xaxis=dict(rangeslider=dict(visible=True))でレンジスライダーを表示します。
❓ よくある質問
Q1: 移動平均の期間はどう決めればいいですか?
データの特性と分析目的によります。短期(5〜7日)は短期トレンドとノイズ除去に、中期(20〜30日)は月次トレンドに、長期(50〜200日)は長期トレンドと構造変化の把握に適しています。一般的には、複数の期間を組み合わせて表示すると効果的です。
Q2: 欠損値(歯抜けデータ)がある場合はどうすればいいですか?
いくつかの方法があります。df.interpolate()で線形補間(前後の値から推定)、df.ffill()で前方埋め(前の値で埋める)、df.bfill()で後方埋め(後の値で埋める)、df.dropna()で欠損行を削除、などがあります。データの性質と分析目的に応じて選択してください。
Q3: 時系列データの予測はできますか?
はい、できます。Pythonではstatsmodels(ARIMA、指数平滑法)やProphet(Facebook開発)というライブラリを使って時系列予測が可能です。このコースでは可視化に焦点を当てていますが、予測結果を可視化することも非常に重要です。
Q4: 季節性を分析するにはどうすればいいですか?
季節分解(Seasonal Decomposition)が有効です。statsmodelsのseasonal_decompose()を使うと、データをトレンド、季節性、残差(ノイズ)に分解できます。これにより、「毎年12月に売上が上がる」といったパターンを数値的に確認できます。
Q5: 異常検知で3シグマ以外の方法はありますか?
はい、複数の方法があります。IQR法(四分位範囲を使用)、Isolation Forest(機械学習)、Local Outlier Factor(密度ベース)などがあります。データの分布や異常の性質に応じて使い分けます。3シグマ法は正規分布を仮定しているため、データが正規分布に従わない場合は他の方法が適切なことがあります。
artnasekai
#artnasekai #学習メモ