Spaces:
Sleeping
Sleeping
Yoon-gu Hwang
Claude
commited on
Commit
ยท
befeb85
1
Parent(s):
93ec097
Change to continuous data with line graph visualization
Browse files- Generate continuous time-series data with sine wave patterns
- Show actual data points using line graphs
- Add drift point markers with red dashed lines
- Update analyzer to work with continuous data
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- analyzer.py +28 -56
- drift_simulator.py +31 -30
- visualizer.py +54 -108
analyzer.py
CHANGED
|
@@ -11,21 +11,11 @@ def analyze_drift(X: np.ndarray, y: np.ndarray, drift_points: np.ndarray, drift_
|
|
| 11 |
"drift_locations": drift_points.tolist() if len(drift_points) > 0 else [],
|
| 12 |
}
|
| 13 |
|
| 14 |
-
#
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
analysis["min_y"] = float(np.min(y))
|
| 20 |
-
analysis["max_y"] = float(np.max(y))
|
| 21 |
-
else:
|
| 22 |
-
# ์ด์ง ๋ถ๋ฅ ๋ถ์
|
| 23 |
-
class_0_count = int(np.sum(y == 0))
|
| 24 |
-
class_1_count = int(np.sum(y == 1))
|
| 25 |
-
analysis["class_0_count"] = class_0_count
|
| 26 |
-
analysis["class_1_count"] = class_1_count
|
| 27 |
-
analysis["class_0_ratio"] = float(class_0_count / len(y))
|
| 28 |
-
analysis["class_1_ratio"] = float(class_1_count / len(y))
|
| 29 |
|
| 30 |
# ์ธ๊ทธ๋จผํธ๋ณ ๋ถ์
|
| 31 |
segments = []
|
|
@@ -36,31 +26,26 @@ def analyze_drift(X: np.ndarray, y: np.ndarray, drift_points: np.ndarray, drift_
|
|
| 36 |
end = segment_boundaries[i + 1]
|
| 37 |
|
| 38 |
segment_y = y[start:end]
|
|
|
|
| 39 |
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
"end_idx": int(end),
|
| 46 |
-
"mean": float(np.mean(segment_y)),
|
| 47 |
-
"std": float(np.std(segment_y))
|
| 48 |
-
})
|
| 49 |
else:
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
"class_1_ratio": float(class_1_count / total) if total > 0 else 0.0
|
| 63 |
-
})
|
| 64 |
|
| 65 |
analysis["segments"] = segments
|
| 66 |
|
|
@@ -80,32 +65,19 @@ def format_analysis_summary(analysis: Dict) -> str:
|
|
| 80 |
**์ ์ฒด ๋ฐ์ดํฐ:**
|
| 81 |
- ์ด ์ํ ์: {analysis['total_samples']}
|
| 82 |
- ๋๋ฆฌํํธ ๋ฐ์ ํ์: {analysis['num_drift_points']}
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
if drift_type == "incremental":
|
| 86 |
-
summary += f"""- ํ๊ท ๊ฐ: {analysis['mean_y']:.2f}
|
| 87 |
- ํ์คํธ์ฐจ: {analysis['std_y']:.2f}
|
| 88 |
- ๋ฒ์: [{analysis['min_y']:.2f}, {analysis['max_y']:.2f}]
|
| 89 |
-
"""
|
| 90 |
-
else:
|
| 91 |
-
summary += f"""- Class 0 (ํ๋์): {analysis['class_0_count']} ์ํ ({analysis['class_0_ratio']*100:.1f}%)
|
| 92 |
-
- Class 1 (์ด๋ก์): {analysis['class_1_count']} ์ํ ({analysis['class_1_ratio']*100:.1f}%)
|
| 93 |
-
"""
|
| 94 |
|
| 95 |
-
|
|
|
|
| 96 |
|
| 97 |
for seg in analysis['segments']:
|
| 98 |
-
|
| 99 |
-
summary += f"""
|
| 100 |
**์ธ๊ทธ๋จผํธ {seg['segment_id'] + 1}** (์ํ {seg['start_idx']}-{seg['end_idx']})
|
| 101 |
- ํ๊ท : {seg['mean']:.2f}
|
| 102 |
- ํ์คํธ์ฐจ: {seg['std']:.2f}
|
| 103 |
-
|
| 104 |
-
else:
|
| 105 |
-
summary += f"""
|
| 106 |
-
**์ธ๊ทธ๋จผํธ {seg['segment_id'] + 1}** (์ํ {seg['start_idx']}-{seg['end_idx']})
|
| 107 |
-
- Class 0: {seg['class_0_count']} ์ํ ({seg['class_0_ratio']*100:.1f}%)
|
| 108 |
-
- Class 1: {seg['class_1_count']} ์ํ ({seg['class_1_ratio']*100:.1f}%)
|
| 109 |
"""
|
| 110 |
|
| 111 |
return summary
|
|
|
|
| 11 |
"drift_locations": drift_points.tolist() if len(drift_points) > 0 else [],
|
| 12 |
}
|
| 13 |
|
| 14 |
+
# ์ ์ฒด ํต๊ณ (๋ชจ๋ drift type์ ์ฐ์ ๊ฐ์ผ๋ก ์ฒ๋ฆฌ)
|
| 15 |
+
analysis["mean_y"] = float(np.mean(y))
|
| 16 |
+
analysis["std_y"] = float(np.std(y))
|
| 17 |
+
analysis["min_y"] = float(np.min(y))
|
| 18 |
+
analysis["max_y"] = float(np.max(y))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
|
| 20 |
# ์ธ๊ทธ๋จผํธ๋ณ ๋ถ์
|
| 21 |
segments = []
|
|
|
|
| 26 |
end = segment_boundaries[i + 1]
|
| 27 |
|
| 28 |
segment_y = y[start:end]
|
| 29 |
+
segment_X = X[start:end]
|
| 30 |
|
| 31 |
+
# ์ ํ ํ๊ท ๊ณ์ ๊ณ์ฐ
|
| 32 |
+
if len(segment_X) > 1:
|
| 33 |
+
coeffs = np.polyfit(segment_X, segment_y, 1)
|
| 34 |
+
slope = float(coeffs[0])
|
| 35 |
+
intercept = float(coeffs[1])
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
else:
|
| 37 |
+
slope = 0.0
|
| 38 |
+
intercept = float(segment_y[0]) if len(segment_y) > 0 else 0.0
|
| 39 |
+
|
| 40 |
+
segments.append({
|
| 41 |
+
"segment_id": i,
|
| 42 |
+
"start_idx": int(start),
|
| 43 |
+
"end_idx": int(end),
|
| 44 |
+
"mean": float(np.mean(segment_y)),
|
| 45 |
+
"std": float(np.std(segment_y)),
|
| 46 |
+
"slope": slope,
|
| 47 |
+
"intercept": intercept
|
| 48 |
+
})
|
|
|
|
|
|
|
| 49 |
|
| 50 |
analysis["segments"] = segments
|
| 51 |
|
|
|
|
| 65 |
**์ ์ฒด ๋ฐ์ดํฐ:**
|
| 66 |
- ์ด ์ํ ์: {analysis['total_samples']}
|
| 67 |
- ๋๋ฆฌํํธ ๋ฐ์ ํ์: {analysis['num_drift_points']}
|
| 68 |
+
- ํ๊ท ๊ฐ: {analysis['mean_y']:.2f}
|
|
|
|
|
|
|
|
|
|
| 69 |
- ํ์คํธ์ฐจ: {analysis['std_y']:.2f}
|
| 70 |
- ๋ฒ์: [{analysis['min_y']:.2f}, {analysis['max_y']:.2f}]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
|
| 72 |
+
**์ธ๊ทธ๋จผํธ๋ณ ๋ถ์:**
|
| 73 |
+
"""
|
| 74 |
|
| 75 |
for seg in analysis['segments']:
|
| 76 |
+
summary += f"""
|
|
|
|
| 77 |
**์ธ๊ทธ๋จผํธ {seg['segment_id'] + 1}** (์ํ {seg['start_idx']}-{seg['end_idx']})
|
| 78 |
- ํ๊ท : {seg['mean']:.2f}
|
| 79 |
- ํ์คํธ์ฐจ: {seg['std']:.2f}
|
| 80 |
+
- ํธ๋ ๋: y = {seg['slope']:.4f}x + {seg['intercept']:.2f}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
"""
|
| 82 |
|
| 83 |
return summary
|
drift_simulator.py
CHANGED
|
@@ -3,14 +3,14 @@ from typing import Tuple
|
|
| 3 |
|
| 4 |
def generate_sudden_drift(n_samples: int = 1000, drift_point: int = 500) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
|
| 5 |
"""๊ธ๊ฒฉํ ๋๋ฆฌํํธ: t ์์ ์์ ๊ฐ์๊ธฐ ๋ฐ์ดํฐ ๋ถํฌ ๋ณ๊ฒฝ"""
|
| 6 |
-
X = np.arange(n_samples)
|
| 7 |
-
y = np.zeros(n_samples
|
| 8 |
|
| 9 |
-
# Before drift:
|
| 10 |
-
y[:drift_point] = 0
|
| 11 |
|
| 12 |
-
# After drift:
|
| 13 |
-
y[drift_point:] =
|
| 14 |
|
| 15 |
drift_points = np.array([drift_point])
|
| 16 |
return X, y, drift_points
|
|
@@ -18,41 +18,42 @@ def generate_sudden_drift(n_samples: int = 1000, drift_point: int = 500) -> Tupl
|
|
| 18 |
|
| 19 |
def generate_gradual_drift(n_samples: int = 1000, drift_start: int = 300, drift_end: int = 700) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
|
| 20 |
"""์ ์ง์ ๋๋ฆฌํํธ: ๋ ๋ถํฌ๊ฐ ์์ด๋ฉฐ ์ฒ์ฒํ ์ ํ"""
|
| 21 |
-
X = np.arange(n_samples)
|
| 22 |
-
y = np.zeros(n_samples
|
| 23 |
|
| 24 |
-
# Before drift:
|
| 25 |
-
y[:drift_start] = 0
|
| 26 |
|
| 27 |
-
# Gradual transition:
|
| 28 |
transition_length = drift_end - drift_start
|
| 29 |
for i in range(drift_start, drift_end):
|
| 30 |
-
# ์ ์ง์ ์ผ๋ก class 1์ ๋น์จ ์ฆ๊ฐ
|
| 31 |
weight = (i - drift_start) / transition_length
|
| 32 |
-
|
|
|
|
|
|
|
| 33 |
|
| 34 |
-
# After drift:
|
| 35 |
-
y[drift_end:] =
|
| 36 |
|
| 37 |
drift_points = np.array([drift_start, drift_end])
|
| 38 |
return X, y, drift_points
|
| 39 |
|
| 40 |
|
| 41 |
-
def generate_incremental_drift(n_samples: int = 1000, n_steps: int =
|
| 42 |
"""์ฆ๋ถ์ ๋๋ฆฌํํธ: ๊ณ๋จ์์ผ๋ก ์์ ๋ณํ๊ฐ ๋์ """
|
| 43 |
-
X = np.arange(n_samples)
|
| 44 |
-
y = np.zeros(n_samples)
|
| 45 |
|
| 46 |
-
step_size = n_samples // n_steps
|
| 47 |
drift_points = []
|
| 48 |
|
| 49 |
-
for step in range(n_steps):
|
| 50 |
start_idx = step * step_size
|
| 51 |
-
end_idx = (step + 1) * step_size if step < n_steps
|
| 52 |
|
| 53 |
-
# ๊ฐ ๋จ๊ณ๋ง๋ค
|
| 54 |
-
|
| 55 |
-
y[start_idx:end_idx] =
|
| 56 |
|
| 57 |
if step > 0:
|
| 58 |
drift_points.append(start_idx)
|
|
@@ -62,8 +63,8 @@ def generate_incremental_drift(n_samples: int = 1000, n_steps: int = 10) -> Tupl
|
|
| 62 |
|
| 63 |
def generate_recurring_drift(n_samples: int = 1000, cycle_length: int = 250) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
|
| 64 |
"""๋ฐ๋ณต์ ๋๋ฆฌํํธ: ์ด์ ๋ถํฌ๊ฐ ์ฃผ๊ธฐ์ ์ผ๋ก ์ฌ๋ฑ์ฅ"""
|
| 65 |
-
X = np.arange(n_samples)
|
| 66 |
-
y = np.zeros(n_samples
|
| 67 |
|
| 68 |
drift_points = []
|
| 69 |
|
|
@@ -71,11 +72,11 @@ def generate_recurring_drift(n_samples: int = 1000, cycle_length: int = 250) ->
|
|
| 71 |
cycle_pos = i % cycle_length
|
| 72 |
|
| 73 |
if cycle_pos < cycle_length // 2:
|
| 74 |
-
# Concept A:
|
| 75 |
-
y[i] = 0
|
| 76 |
else:
|
| 77 |
-
# Concept B:
|
| 78 |
-
y[i] =
|
| 79 |
|
| 80 |
if cycle_pos == cycle_length // 2:
|
| 81 |
drift_points.append(i)
|
|
|
|
| 3 |
|
| 4 |
def generate_sudden_drift(n_samples: int = 1000, drift_point: int = 500) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
|
| 5 |
"""๊ธ๊ฒฉํ ๋๋ฆฌํํธ: t ์์ ์์ ๊ฐ์๊ธฐ ๋ฐ์ดํฐ ๋ถํฌ ๋ณ๊ฒฝ"""
|
| 6 |
+
X = np.arange(n_samples)
|
| 7 |
+
y = np.zeros(n_samples)
|
| 8 |
|
| 9 |
+
# Before drift: y = 2 + sin(X/50) + noise
|
| 10 |
+
y[:drift_point] = 2 + np.sin(X[:drift_point] / 50) + np.random.normal(0, 0.3, drift_point)
|
| 11 |
|
| 12 |
+
# After drift: y = 5 - sin(X/50) + noise (์์ ํ ๋ค๋ฅธ ํจํด)
|
| 13 |
+
y[drift_point:] = 5 - np.sin(X[drift_point:] / 50) + np.random.normal(0, 0.3, n_samples - drift_point)
|
| 14 |
|
| 15 |
drift_points = np.array([drift_point])
|
| 16 |
return X, y, drift_points
|
|
|
|
| 18 |
|
| 19 |
def generate_gradual_drift(n_samples: int = 1000, drift_start: int = 300, drift_end: int = 700) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
|
| 20 |
"""์ ์ง์ ๋๋ฆฌํํธ: ๋ ๋ถํฌ๊ฐ ์์ด๋ฉฐ ์ฒ์ฒํ ์ ํ"""
|
| 21 |
+
X = np.arange(n_samples)
|
| 22 |
+
y = np.zeros(n_samples)
|
| 23 |
|
| 24 |
+
# Before drift: y = 2 + sin(X/50) + noise
|
| 25 |
+
y[:drift_start] = 2 + np.sin(X[:drift_start] / 50) + np.random.normal(0, 0.3, drift_start)
|
| 26 |
|
| 27 |
+
# Gradual transition: ์ ์ง์ ์ผ๋ก ๋ณํ
|
| 28 |
transition_length = drift_end - drift_start
|
| 29 |
for i in range(drift_start, drift_end):
|
|
|
|
| 30 |
weight = (i - drift_start) / transition_length
|
| 31 |
+
old_concept = 2 + np.sin(X[i] / 50) + np.random.normal(0, 0.3)
|
| 32 |
+
new_concept = 5 - np.sin(X[i] / 50) + np.random.normal(0, 0.3)
|
| 33 |
+
y[i] = (1 - weight) * old_concept + weight * new_concept
|
| 34 |
|
| 35 |
+
# After drift: y = 5 - sin(X/50) + noise
|
| 36 |
+
y[drift_end:] = 5 - np.sin(X[drift_end:] / 50) + np.random.normal(0, 0.3, n_samples - drift_end)
|
| 37 |
|
| 38 |
drift_points = np.array([drift_start, drift_end])
|
| 39 |
return X, y, drift_points
|
| 40 |
|
| 41 |
|
| 42 |
+
def generate_incremental_drift(n_samples: int = 1000, n_steps: int = 5) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
|
| 43 |
"""์ฆ๋ถ์ ๋๋ฆฌํํธ: ๊ณ๋จ์์ผ๋ก ์์ ๋ณํ๊ฐ ๋์ """
|
| 44 |
+
X = np.arange(n_samples)
|
| 45 |
+
y = np.zeros(n_samples)
|
| 46 |
|
| 47 |
+
step_size = n_samples // (n_steps + 1)
|
| 48 |
drift_points = []
|
| 49 |
|
| 50 |
+
for step in range(n_steps + 1):
|
| 51 |
start_idx = step * step_size
|
| 52 |
+
end_idx = (step + 1) * step_size if step < n_steps else n_samples
|
| 53 |
|
| 54 |
+
# ๊ฐ ๋จ๊ณ๋ง๋ค ํ๊ท ์ด ์กฐ๊ธ์ฉ ๋ณํ
|
| 55 |
+
mean_shift = 2 + (step / n_steps) * 3 # 2์์ 5๋ก ์ ์ง์ ๋ณํ
|
| 56 |
+
y[start_idx:end_idx] = mean_shift + np.sin(X[start_idx:end_idx] / 50) + np.random.normal(0, 0.3, end_idx - start_idx)
|
| 57 |
|
| 58 |
if step > 0:
|
| 59 |
drift_points.append(start_idx)
|
|
|
|
| 63 |
|
| 64 |
def generate_recurring_drift(n_samples: int = 1000, cycle_length: int = 250) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
|
| 65 |
"""๋ฐ๋ณต์ ๋๋ฆฌํํธ: ์ด์ ๋ถํฌ๊ฐ ์ฃผ๊ธฐ์ ์ผ๋ก ์ฌ๋ฑ์ฅ"""
|
| 66 |
+
X = np.arange(n_samples)
|
| 67 |
+
y = np.zeros(n_samples)
|
| 68 |
|
| 69 |
drift_points = []
|
| 70 |
|
|
|
|
| 72 |
cycle_pos = i % cycle_length
|
| 73 |
|
| 74 |
if cycle_pos < cycle_length // 2:
|
| 75 |
+
# Concept A: y = 2 + sin(X/50) + noise
|
| 76 |
+
y[i] = 2 + np.sin(X[i] / 50) + np.random.normal(0, 0.3)
|
| 77 |
else:
|
| 78 |
+
# Concept B: y = 5 - sin(X/50) + noise
|
| 79 |
+
y[i] = 5 - np.sin(X[i] / 50) + np.random.normal(0, 0.3)
|
| 80 |
|
| 81 |
if cycle_pos == cycle_length // 2:
|
| 82 |
drift_points.append(i)
|
visualizer.py
CHANGED
|
@@ -7,59 +7,30 @@ def create_drift_visualization(X: np.ndarray, y: np.ndarray, drift_points: np.nd
|
|
| 7 |
|
| 8 |
fig = go.Figure()
|
| 9 |
|
| 10 |
-
#
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
customdata=y
|
| 35 |
-
))
|
| 36 |
-
else:
|
| 37 |
-
# ์ด์ง ๋ถ๋ฅ (0: ํ๋์, 1: ์ด๋ก์)
|
| 38 |
-
# Class 0 (ํ๋์)
|
| 39 |
-
class_0_mask = y == 0
|
| 40 |
-
if np.any(class_0_mask):
|
| 41 |
-
fig.add_trace(go.Scatter(
|
| 42 |
-
x=X[class_0_mask],
|
| 43 |
-
y=np.ones(np.sum(class_0_mask)),
|
| 44 |
-
mode='markers',
|
| 45 |
-
marker=dict(color='rgb(65, 105, 225)', size=10, symbol='square', line=dict(width=0)),
|
| 46 |
-
name='Class 0',
|
| 47 |
-
showlegend=True,
|
| 48 |
-
hovertemplate='Time: %{x}<br>Class: 0<extra></extra>'
|
| 49 |
-
))
|
| 50 |
-
|
| 51 |
-
# Class 1 (์ด๋ก์)
|
| 52 |
-
class_1_mask = y == 1
|
| 53 |
-
if np.any(class_1_mask):
|
| 54 |
-
fig.add_trace(go.Scatter(
|
| 55 |
-
x=X[class_1_mask],
|
| 56 |
-
y=np.ones(np.sum(class_1_mask)),
|
| 57 |
-
mode='markers',
|
| 58 |
-
marker=dict(color='rgb(50, 205, 50)', size=10, symbol='square', line=dict(width=0)),
|
| 59 |
-
name='Class 1',
|
| 60 |
-
showlegend=True,
|
| 61 |
-
hovertemplate='Time: %{x}<br>Class: 1<extra></extra>'
|
| 62 |
-
))
|
| 63 |
|
| 64 |
# ๋ ์ด์์ ์ค์
|
| 65 |
title_map = {
|
|
@@ -77,11 +48,11 @@ def create_drift_visualization(X: np.ndarray, y: np.ndarray, drift_points: np.nd
|
|
| 77 |
font=dict(size=20)
|
| 78 |
),
|
| 79 |
xaxis_title="Time",
|
| 80 |
-
yaxis_title="
|
| 81 |
hovermode='closest',
|
| 82 |
template='plotly_white',
|
| 83 |
-
height=
|
| 84 |
-
showlegend=
|
| 85 |
legend=dict(
|
| 86 |
yanchor="top",
|
| 87 |
y=0.99,
|
|
@@ -89,13 +60,14 @@ def create_drift_visualization(X: np.ndarray, y: np.ndarray, drift_points: np.nd
|
|
| 89 |
x=0.99
|
| 90 |
),
|
| 91 |
xaxis=dict(
|
| 92 |
-
showgrid=
|
| 93 |
-
|
|
|
|
| 94 |
),
|
| 95 |
yaxis=dict(
|
| 96 |
-
showgrid=
|
| 97 |
-
|
| 98 |
-
|
| 99 |
),
|
| 100 |
plot_bgcolor='white'
|
| 101 |
)
|
|
@@ -121,57 +93,31 @@ def create_comparison_visualization(drift_data_dict: dict) -> go.Figure:
|
|
| 121 |
if drift_type in drift_data_dict:
|
| 122 |
X, y, drift_points = drift_data_dict[drift_type]
|
| 123 |
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
|
|
|
|
|
|
| 141 |
row=row, col=col
|
| 142 |
)
|
| 143 |
-
else:
|
| 144 |
-
# ์ด์ง ๋ถ๋ฅ
|
| 145 |
-
class_0_mask = y == 0
|
| 146 |
-
class_1_mask = y == 1
|
| 147 |
-
|
| 148 |
-
if np.any(class_0_mask):
|
| 149 |
-
fig.add_trace(
|
| 150 |
-
go.Scatter(
|
| 151 |
-
x=X[class_0_mask],
|
| 152 |
-
y=np.ones(np.sum(class_0_mask)),
|
| 153 |
-
mode='markers',
|
| 154 |
-
marker=dict(color='rgb(65, 105, 225)', size=5, symbol='square', line=dict(width=0)),
|
| 155 |
-
showlegend=False
|
| 156 |
-
),
|
| 157 |
-
row=row, col=col
|
| 158 |
-
)
|
| 159 |
-
|
| 160 |
-
if np.any(class_1_mask):
|
| 161 |
-
fig.add_trace(
|
| 162 |
-
go.Scatter(
|
| 163 |
-
x=X[class_1_mask],
|
| 164 |
-
y=np.ones(np.sum(class_1_mask)),
|
| 165 |
-
mode='markers',
|
| 166 |
-
marker=dict(color='rgb(50, 205, 50)', size=5, symbol='square', line=dict(width=0)),
|
| 167 |
-
showlegend=False
|
| 168 |
-
),
|
| 169 |
-
row=row, col=col
|
| 170 |
-
)
|
| 171 |
|
| 172 |
# ๋ ์ด์์ ์ค์
|
| 173 |
-
fig.update_xaxes(title_text="Time", showgrid=
|
| 174 |
-
fig.update_yaxes(title_text="
|
| 175 |
fig.update_layout(
|
| 176 |
height=800,
|
| 177 |
title_text="Concept Drift Types Comparison",
|
|
|
|
| 7 |
|
| 8 |
fig = go.Figure()
|
| 9 |
|
| 10 |
+
# ๋ฉ์ธ ๋ผ์ธ ๊ทธ๋ํ
|
| 11 |
+
fig.add_trace(go.Scatter(
|
| 12 |
+
x=X,
|
| 13 |
+
y=y,
|
| 14 |
+
mode='lines+markers',
|
| 15 |
+
name='Data',
|
| 16 |
+
line=dict(color='rgb(100, 140, 200)', width=2),
|
| 17 |
+
marker=dict(size=4, color='rgb(100, 140, 200)'),
|
| 18 |
+
hovertemplate='Time: %{x}<br>Value: %{y:.2f}<extra></extra>'
|
| 19 |
+
))
|
| 20 |
+
|
| 21 |
+
# ๋๋ฆฌํํธ ๋ฐ์ ์ง์ ํ์
|
| 22 |
+
y_min, y_max = y.min(), y.max()
|
| 23 |
+
y_range = y_max - y_min
|
| 24 |
+
|
| 25 |
+
for i, drift_point in enumerate(drift_points):
|
| 26 |
+
fig.add_vline(
|
| 27 |
+
x=X[drift_point],
|
| 28 |
+
line_dash="dash",
|
| 29 |
+
line_color="red",
|
| 30 |
+
line_width=2,
|
| 31 |
+
annotation_text=f"Drift {i+1}",
|
| 32 |
+
annotation_position="top"
|
| 33 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
|
| 35 |
# ๋ ์ด์์ ์ค์
|
| 36 |
title_map = {
|
|
|
|
| 48 |
font=dict(size=20)
|
| 49 |
),
|
| 50 |
xaxis_title="Time",
|
| 51 |
+
yaxis_title="Value",
|
| 52 |
hovermode='closest',
|
| 53 |
template='plotly_white',
|
| 54 |
+
height=500,
|
| 55 |
+
showlegend=True,
|
| 56 |
legend=dict(
|
| 57 |
yanchor="top",
|
| 58 |
y=0.99,
|
|
|
|
| 60 |
x=0.99
|
| 61 |
),
|
| 62 |
xaxis=dict(
|
| 63 |
+
showgrid=True,
|
| 64 |
+
gridwidth=1,
|
| 65 |
+
gridcolor='LightGray'
|
| 66 |
),
|
| 67 |
yaxis=dict(
|
| 68 |
+
showgrid=True,
|
| 69 |
+
gridwidth=1,
|
| 70 |
+
gridcolor='LightGray'
|
| 71 |
),
|
| 72 |
plot_bgcolor='white'
|
| 73 |
)
|
|
|
|
| 93 |
if drift_type in drift_data_dict:
|
| 94 |
X, y, drift_points = drift_data_dict[drift_type]
|
| 95 |
|
| 96 |
+
# ๋ผ์ธ ๊ทธ๋ํ ์ถ๊ฐ
|
| 97 |
+
fig.add_trace(
|
| 98 |
+
go.Scatter(
|
| 99 |
+
x=X,
|
| 100 |
+
y=y,
|
| 101 |
+
mode='lines',
|
| 102 |
+
line=dict(color='rgb(100, 140, 200)', width=1),
|
| 103 |
+
showlegend=False
|
| 104 |
+
),
|
| 105 |
+
row=row, col=col
|
| 106 |
+
)
|
| 107 |
+
|
| 108 |
+
# ๋๋ฆฌํํธ ์ง์ ํ์
|
| 109 |
+
for drift_point in drift_points:
|
| 110 |
+
fig.add_vline(
|
| 111 |
+
x=X[drift_point],
|
| 112 |
+
line_dash="dash",
|
| 113 |
+
line_color="red",
|
| 114 |
+
line_width=1,
|
| 115 |
row=row, col=col
|
| 116 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
|
| 118 |
# ๋ ์ด์์ ์ค์
|
| 119 |
+
fig.update_xaxes(title_text="Time", showgrid=True, gridcolor='LightGray')
|
| 120 |
+
fig.update_yaxes(title_text="Value", showgrid=True, gridcolor='LightGray')
|
| 121 |
fig.update_layout(
|
| 122 |
height=800,
|
| 123 |
title_text="Concept Drift Types Comparison",
|