aiwf 0.3.22 → 0.3.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/package.json +3 -2
  2. package/src/cli/index.js +39 -336
  3. package/src/lib/installer.js +294 -90
  4. package/src/utils/messages.js +24 -0
  5. package/src/DEPENDENCY_MAP.md +0 -90
  6. package/src/cli/cache-cli.js +0 -459
  7. package/src/cli/checkpoint-cli.js +0 -417
  8. package/src/cli/language-cli.js +0 -286
  9. package/src/cli/sprint-cli.js +0 -287
  10. package/src/commands/ai-tool.js +0 -383
  11. package/src/commands/compress.js +0 -60
  12. package/src/commands/create-project.js +0 -160
  13. package/src/commands/evaluate.js +0 -459
  14. package/src/commands/persona.js +0 -309
  15. package/src/commands/sprint-task.js +0 -262
  16. package/src/commands/token.js +0 -312
  17. package/src/lib/ai-persona-manager.js +0 -711
  18. package/src/lib/cache-system.js +0 -332
  19. package/src/lib/context-engine.js +0 -568
  20. package/src/lib/github-integration.js +0 -402
  21. package/src/lib/memory-profiler.js +0 -471
  22. package/src/lib/metrics-collector.js +0 -885
  23. package/src/lib/offline-detector.js +0 -386
  24. package/src/lib/resource-loader-enhanced.js +0 -399
  25. package/src/lib/resource-loader.js +0 -250
  26. package/src/lib/resources/commands/ai-persona.js +0 -602
  27. package/src/lib/resources/commands/compress-context.js +0 -389
  28. package/src/lib/resources/commands/evaluate.js +0 -246
  29. package/src/lib/resources/commands/persona-context-apply.js +0 -562
  30. package/src/lib/resources/commands/token-tracking.js +0 -443
  31. package/src/lib/resources/config/commit-patterns.js +0 -103
  32. package/src/lib/resources/config/language.json +0 -6
  33. package/src/lib/resources/personas/PERSONA_INDEX.md +0 -57
  34. package/src/lib/resources/personas/analyst.json +0 -44
  35. package/src/lib/resources/personas/architect/best_practices.md +0 -136
  36. package/src/lib/resources/personas/architect/knowledge_base.md +0 -377
  37. package/src/lib/resources/personas/architect.json +0 -44
  38. package/src/lib/resources/personas/backend/best_practices.md +0 -766
  39. package/src/lib/resources/personas/backend/knowledge_base.md +0 -1070
  40. package/src/lib/resources/personas/data_analyst/best_practices.md +0 -594
  41. package/src/lib/resources/personas/data_analyst/knowledge_base.md +0 -1057
  42. package/src/lib/resources/personas/developer.json +0 -44
  43. package/src/lib/resources/personas/developer.md +0 -37
  44. package/src/lib/resources/personas/evaluation_criteria.json +0 -137
  45. package/src/lib/resources/personas/frontend/best_practices.md +0 -445
  46. package/src/lib/resources/personas/frontend/knowledge_base.md +0 -729
  47. package/src/lib/resources/personas/persona-index.json +0 -31
  48. package/src/lib/resources/personas/reviewer.json +0 -44
  49. package/src/lib/resources/personas/security/best_practices.md +0 -307
  50. package/src/lib/resources/personas/security/knowledge_base.md +0 -498
  51. package/src/lib/resources/personas/tester.json +0 -44
  52. package/src/lib/resources/templates/README.md +0 -78
  53. package/src/lib/resources/templates/api-server/config.json +0 -64
  54. package/src/lib/resources/templates/api-server/template/.aiwf/config.json +0 -56
  55. package/src/lib/resources/templates/api-server/template/.aiwf/feature-ledger.json +0 -42
  56. package/src/lib/resources/templates/api-server/template/.aiwf/personas/backend-engineer.json +0 -40
  57. package/src/lib/resources/templates/api-server/template/.aiwf/scripts/cli.js +0 -111
  58. package/src/lib/resources/templates/api-server/template/.env.example +0 -29
  59. package/src/lib/resources/templates/api-server/template/.eslintrc.json +0 -23
  60. package/src/lib/resources/templates/api-server/template/README.md +0 -171
  61. package/src/lib/resources/templates/api-server/template/jest.config.js +0 -26
  62. package/src/lib/resources/templates/api-server/template/nodemon.json +0 -9
  63. package/src/lib/resources/templates/api-server/template/package.json +0 -61
  64. package/src/lib/resources/templates/api-server/template/src/app.ts +0 -60
  65. package/src/lib/resources/templates/api-server/template/src/config/swagger.ts +0 -38
  66. package/src/lib/resources/templates/api-server/template/src/controllers/aiwfController.ts +0 -54
  67. package/src/lib/resources/templates/api-server/template/src/controllers/authController.ts +0 -128
  68. package/src/lib/resources/templates/api-server/template/src/controllers/statusController.ts +0 -28
  69. package/src/lib/resources/templates/api-server/template/src/index.ts +0 -28
  70. package/src/lib/resources/templates/api-server/template/src/middleware/aiwfMiddleware.ts +0 -50
  71. package/src/lib/resources/templates/api-server/template/src/middleware/authMiddleware.ts +0 -41
  72. package/src/lib/resources/templates/api-server/template/src/middleware/errorHandler.ts +0 -42
  73. package/src/lib/resources/templates/api-server/template/src/middleware/notFoundHandler.ts +0 -14
  74. package/src/lib/resources/templates/api-server/template/src/middleware/requestLogger.ts +0 -20
  75. package/src/lib/resources/templates/api-server/template/src/routes/aiwf.ts +0 -31
  76. package/src/lib/resources/templates/api-server/template/src/routes/index.ts +0 -13
  77. package/src/lib/resources/templates/api-server/template/src/routes/v1/index.ts +0 -67
  78. package/src/lib/resources/templates/api-server/template/src/utils/logger.ts +0 -37
  79. package/src/lib/resources/templates/api-server/template/tests/app.test.ts +0 -40
  80. package/src/lib/resources/templates/api-server/template/tsconfig.json +0 -43
  81. package/src/lib/resources/templates/npm-library/config.json +0 -61
  82. package/src/lib/resources/templates/npm-library/template/LICENSE +0 -21
  83. package/src/lib/resources/templates/npm-library/template/README.md +0 -201
  84. package/src/lib/resources/templates/npm-library/template/package.json +0 -78
  85. package/src/lib/resources/templates/web-app/config.json +0 -53
  86. package/src/lib/resources/templates/web-app/template/.aiwf/config.json +0 -54
  87. package/src/lib/resources/templates/web-app/template/.aiwf/feature-ledger.json +0 -37
  88. package/src/lib/resources/templates/web-app/template/.aiwf/personas/fullstack-developer.json +0 -40
  89. package/src/lib/resources/templates/web-app/template/.aiwf/scripts/cli.js +0 -110
  90. package/src/lib/resources/templates/web-app/template/.eslintrc.cjs +0 -20
  91. package/src/lib/resources/templates/web-app/template/README.md +0 -151
  92. package/src/lib/resources/templates/web-app/template/index.html +0 -14
  93. package/src/lib/resources/templates/web-app/template/package.json +0 -44
  94. package/src/lib/resources/templates/web-app/template/postcss.config.js +0 -6
  95. package/src/lib/resources/templates/web-app/template/public/vite.svg +0 -1
  96. package/src/lib/resources/templates/web-app/template/src/App.tsx +0 -21
  97. package/src/lib/resources/templates/web-app/template/src/components/Layout.tsx +0 -57
  98. package/src/lib/resources/templates/web-app/template/src/components/aiwf/ContextStatus.tsx +0 -107
  99. package/src/lib/resources/templates/web-app/template/src/components/aiwf/TokenUsage.tsx +0 -71
  100. package/src/lib/resources/templates/web-app/template/src/index.css +0 -60
  101. package/src/lib/resources/templates/web-app/template/src/main.tsx +0 -10
  102. package/src/lib/resources/templates/web-app/template/src/pages/AiwfDashboard.tsx +0 -57
  103. package/src/lib/resources/templates/web-app/template/src/pages/HomePage.tsx +0 -89
  104. package/src/lib/resources/templates/web-app/template/src/pages/NotFound.tsx +0 -25
  105. package/src/lib/resources/templates/web-app/template/src/stores/aiwfStore.ts +0 -126
  106. package/src/lib/resources/templates/web-app/template/src/types/global.d.ts +0 -9
  107. package/src/lib/resources/templates/web-app/template/src/vite-env.d.ts +0 -1
  108. package/src/lib/resources/templates/web-app/template/tailwind.config.js +0 -30
  109. package/src/lib/resources/templates/web-app/template/tsconfig.json +0 -37
  110. package/src/lib/resources/templates/web-app/template/tsconfig.node.json +0 -10
  111. package/src/lib/resources/templates/web-app/template/vite.config.ts +0 -23
  112. package/src/lib/resources/utils/background-monitor.js +0 -223
  113. package/src/lib/resources/utils/compression-metrics.js +0 -1031
  114. package/src/lib/resources/utils/compression-strategies.js +0 -557
  115. package/src/lib/resources/utils/content-normalizer.js +0 -455
  116. package/src/lib/resources/utils/context-compressor.js +0 -583
  117. package/src/lib/resources/utils/context-rule-parser.js +0 -180
  118. package/src/lib/resources/utils/context-token-monitor.js +0 -463
  119. package/src/lib/resources/utils/context-update-manager.js +0 -502
  120. package/src/lib/resources/utils/git-utils.js +0 -220
  121. package/src/lib/resources/utils/importance-classifier.js +0 -645
  122. package/src/lib/resources/utils/information-filter.js +0 -710
  123. package/src/lib/resources/utils/persona-aware-compressor.js +0 -598
  124. package/src/lib/resources/utils/prompt-injector.js +0 -242
  125. package/src/lib/resources/utils/simplified-evaluator.js +0 -119
  126. package/src/lib/resources/utils/text-summarizer.js +0 -492
  127. package/src/lib/resources/utils/token-counter.js +0 -177
  128. package/src/lib/resources/utils/token-monitor.js +0 -484
  129. package/src/lib/resources/utils/token-reporter.js +0 -452
  130. package/src/lib/resources/utils/token-storage.js +0 -433
  131. package/src/lib/resources/utils/token-tracker.js +0 -283
  132. package/src/lib/state/priority-calculator.js +0 -217
  133. package/src/lib/state/state-index.js +0 -155
  134. package/src/lib/state/task-scanner.js +0 -328
  135. package/src/lib/task-analyzer.js +0 -599
  136. package/src/lib/template-cache-system.js +0 -559
  137. package/src/lib/template-downloader.js +0 -467
  138. package/src/lib/template-version-manager.js +0 -491
  139. package/src/lib/token-optimizer.js +0 -517
  140. package/src/utils/engineering-guard.js +0 -399
@@ -1,594 +0,0 @@
1
- # Data Analyst 페르소나 Best Practices
2
-
3
- ## 개요
4
- Data Analyst 페르소나는 데이터 분석, 시각화, 인사이트 도출에 중점을 둡니다. 정확성, 해석 가능성, 실행 가능한 인사이트를 최우선으로 고려합니다.
5
-
6
- ## 핵심 원칙
7
-
8
- ### 1. 데이터 품질 우선
9
- - 데이터 정합성 검증
10
- - 이상치 탐지 및 처리
11
- - 결측치 처리 전략
12
- - 데이터 버전 관리
13
-
14
- ### 2. 재현 가능한 분석
15
- ```python
16
- # 분석 환경 설정
17
- import pandas as pd
18
- import numpy as np
19
- import matplotlib.pyplot as plt
20
- import seaborn as sns
21
- from datetime import datetime
22
-
23
- # 재현성을 위한 시드 설정
24
- np.random.seed(42)
25
-
26
- # 분석 메타데이터 기록
27
- analysis_metadata = {
28
- 'analyst': 'data_analyst_persona',
29
- 'date': datetime.now().isoformat(),
30
- 'version': '1.0.0',
31
- 'purpose': 'User behavior analysis',
32
- 'data_sources': ['user_events.csv', 'transactions.csv']
33
- }
34
-
35
- # 데이터 로딩 및 전처리 파이프라인
36
- class DataPipeline:
37
- def __init__(self, config):
38
- self.config = config
39
- self.raw_data = None
40
- self.processed_data = None
41
-
42
- def load_data(self):
43
- """데이터 로딩 with 에러 처리"""
44
- try:
45
- self.raw_data = pd.read_csv(
46
- self.config['data_path'],
47
- parse_dates=self.config.get('date_columns', []),
48
- encoding='utf-8'
49
- )
50
- self.log_data_info()
51
- except Exception as e:
52
- print(f"데이터 로딩 실패: {e}")
53
- raise
54
-
55
- def log_data_info(self):
56
- """데이터 기본 정보 로깅"""
57
- print(f"데이터 shape: {self.raw_data.shape}")
58
- print(f"메모리 사용량: {self.raw_data.memory_usage().sum() / 1024**2:.2f} MB")
59
- print(f"결측치 현황:\n{self.raw_data.isnull().sum()}")
60
- ```
61
-
62
- ### 3. 명확한 시각화 원칙
63
- ```python
64
- # 시각화 스타일 가이드
65
- class VisualizationStyle:
66
- # 색상 팔레트 정의
67
- COLORS = {
68
- 'primary': '#1f77b4',
69
- 'secondary': '#ff7f0e',
70
- 'success': '#2ca02c',
71
- 'danger': '#d62728',
72
- 'warning': '#ff9800',
73
- 'info': '#17a2b8'
74
- }
75
-
76
- @staticmethod
77
- def setup_plot_style():
78
- """일관된 플롯 스타일 설정"""
79
- plt.style.use('seaborn-v0_8-whitegrid')
80
- plt.rcParams.update({
81
- 'figure.figsize': (10, 6),
82
- 'font.size': 12,
83
- 'axes.labelsize': 14,
84
- 'axes.titlesize': 16,
85
- 'legend.fontsize': 12,
86
- 'figure.dpi': 100
87
- })
88
-
89
- @staticmethod
90
- def add_value_labels(ax, bars, format_string='{:.1f}'):
91
- """막대 그래프에 값 레이블 추가"""
92
- for bar in bars:
93
- height = bar.get_height()
94
- ax.annotate(format_string.format(height),
95
- xy=(bar.get_x() + bar.get_width() / 2, height),
96
- xytext=(0, 3),
97
- textcoords="offset points",
98
- ha='center', va='bottom')
99
- ```
100
-
101
- ## 데이터 분석 워크플로우
102
-
103
- ### 1. 탐색적 데이터 분석 (EDA)
104
- ```python
105
- class ExploratoryDataAnalysis:
106
- def __init__(self, df):
107
- self.df = df
108
-
109
- def generate_summary_report(self):
110
- """종합 요약 리포트 생성"""
111
- report = {
112
- 'basic_info': self.get_basic_info(),
113
- 'numeric_summary': self.get_numeric_summary(),
114
- 'categorical_summary': self.get_categorical_summary(),
115
- 'correlation_analysis': self.get_correlations(),
116
- 'missing_data': self.analyze_missing_data()
117
- }
118
- return report
119
-
120
- def get_basic_info(self):
121
- """기본 정보 추출"""
122
- return {
123
- 'shape': self.df.shape,
124
- 'columns': list(self.df.columns),
125
- 'dtypes': self.df.dtypes.to_dict(),
126
- 'memory_usage': self.df.memory_usage(deep=True).sum() / 1024**2,
127
- 'duplicates': self.df.duplicated().sum()
128
- }
129
-
130
- def get_numeric_summary(self):
131
- """수치형 변수 요약"""
132
- numeric_cols = self.df.select_dtypes(include=[np.number]).columns
133
- summary = {}
134
-
135
- for col in numeric_cols:
136
- summary[col] = {
137
- 'mean': self.df[col].mean(),
138
- 'median': self.df[col].median(),
139
- 'std': self.df[col].std(),
140
- 'min': self.df[col].min(),
141
- 'max': self.df[col].max(),
142
- 'q1': self.df[col].quantile(0.25),
143
- 'q3': self.df[col].quantile(0.75),
144
- 'skewness': self.df[col].skew(),
145
- 'kurtosis': self.df[col].kurtosis(),
146
- 'outliers': self.detect_outliers(self.df[col])
147
- }
148
-
149
- return summary
150
-
151
- def detect_outliers(self, series, method='iqr'):
152
- """이상치 탐지"""
153
- if method == 'iqr':
154
- Q1 = series.quantile(0.25)
155
- Q3 = series.quantile(0.75)
156
- IQR = Q3 - Q1
157
- lower_bound = Q1 - 1.5 * IQR
158
- upper_bound = Q3 + 1.5 * IQR
159
- outliers = series[(series < lower_bound) | (series > upper_bound)]
160
- return {
161
- 'count': len(outliers),
162
- 'percentage': len(outliers) / len(series) * 100,
163
- 'indices': outliers.index.tolist()
164
- }
165
- ```
166
-
167
- ### 2. 통계 분석
168
- ```python
169
- class StatisticalAnalysis:
170
- def __init__(self, data):
171
- self.data = data
172
-
173
- def hypothesis_test(self, group1, group2, test_type='t-test', alpha=0.05):
174
- """가설 검정 수행"""
175
- from scipy import stats
176
-
177
- # 정규성 검정
178
- _, p_value1 = stats.normaltest(group1)
179
- _, p_value2 = stats.normaltest(group2)
180
-
181
- is_normal = p_value1 > alpha and p_value2 > alpha
182
-
183
- if test_type == 't-test' and is_normal:
184
- # 등분산 검정
185
- _, p_levene = stats.levene(group1, group2)
186
- equal_var = p_levene > alpha
187
-
188
- # t-검정
189
- statistic, p_value = stats.ttest_ind(
190
- group1, group2, equal_var=equal_var
191
- )
192
- test_name = f"{'Welch' if not equal_var else 'Student'}'s t-test"
193
- else:
194
- # 비모수 검정
195
- statistic, p_value = stats.mannwhitneyu(
196
- group1, group2, alternative='two-sided'
197
- )
198
- test_name = "Mann-Whitney U test"
199
-
200
- return {
201
- 'test': test_name,
202
- 'statistic': statistic,
203
- 'p_value': p_value,
204
- 'significant': p_value < alpha,
205
- 'effect_size': self.calculate_effect_size(group1, group2)
206
- }
207
-
208
- def calculate_effect_size(self, group1, group2):
209
- """효과 크기 계산 (Cohen's d)"""
210
- mean_diff = np.mean(group1) - np.mean(group2)
211
- pooled_std = np.sqrt(
212
- (np.std(group1, ddof=1) ** 2 + np.std(group2, ddof=1) ** 2) / 2
213
- )
214
- cohen_d = mean_diff / pooled_std
215
-
216
- return {
217
- 'cohen_d': cohen_d,
218
- 'interpretation': self.interpret_cohen_d(cohen_d)
219
- }
220
-
221
- @staticmethod
222
- def interpret_cohen_d(d):
223
- """Cohen's d 해석"""
224
- d = abs(d)
225
- if d < 0.2:
226
- return "매우 작은 효과"
227
- elif d < 0.5:
228
- return "작은 효과"
229
- elif d < 0.8:
230
- return "중간 효과"
231
- else:
232
- return "큰 효과"
233
- ```
234
-
235
- ### 3. 예측 모델링
236
- ```python
237
- class PredictiveModeling:
238
- def __init__(self, X, y):
239
- self.X = X
240
- self.y = y
241
- self.models = {}
242
- self.results = {}
243
-
244
- def train_evaluate_models(self, models_list, cv_folds=5):
245
- """여러 모델 학습 및 평가"""
246
- from sklearn.model_selection import cross_validate
247
- from sklearn.metrics import make_scorer
248
-
249
- scoring = {
250
- 'accuracy': 'accuracy',
251
- 'precision': 'precision_weighted',
252
- 'recall': 'recall_weighted',
253
- 'f1': 'f1_weighted',
254
- 'roc_auc': 'roc_auc_ovr_weighted'
255
- }
256
-
257
- for name, model in models_list.items():
258
- print(f"Training {name}...")
259
-
260
- cv_results = cross_validate(
261
- model, self.X, self.y,
262
- cv=cv_folds,
263
- scoring=scoring,
264
- return_train_score=True,
265
- n_jobs=-1
266
- )
267
-
268
- self.models[name] = model
269
- self.results[name] = self.summarize_cv_results(cv_results)
270
-
271
- def summarize_cv_results(self, cv_results):
272
- """교차 검증 결과 요약"""
273
- summary = {}
274
-
275
- for metric in cv_results:
276
- if metric.startswith('test_'):
277
- metric_name = metric.replace('test_', '')
278
- summary[metric_name] = {
279
- 'mean': cv_results[metric].mean(),
280
- 'std': cv_results[metric].std(),
281
- 'values': cv_results[metric].tolist()
282
- }
283
-
284
- return summary
285
-
286
- def feature_importance_analysis(self, model_name):
287
- """특성 중요도 분석"""
288
- model = self.models[model_name]
289
-
290
- if hasattr(model, 'feature_importances_'):
291
- importances = model.feature_importances_
292
- elif hasattr(model, 'coef_'):
293
- importances = np.abs(model.coef_).ravel()
294
- else:
295
- return None
296
-
297
- feature_importance = pd.DataFrame({
298
- 'feature': self.X.columns,
299
- 'importance': importances
300
- }).sort_values('importance', ascending=False)
301
-
302
- return feature_importance
303
- ```
304
-
305
- ## 데이터 시각화 Best Practices
306
-
307
- ### 1. 대시보드 디자인
308
- ```python
309
- class DashboardBuilder:
310
- def __init__(self, data):
311
- self.data = data
312
-
313
- def create_executive_dashboard(self):
314
- """경영진 대시보드 생성"""
315
- fig = plt.figure(figsize=(16, 10))
316
- gs = fig.add_gridspec(3, 3, hspace=0.3, wspace=0.3)
317
-
318
- # KPI 카드
319
- ax1 = fig.add_subplot(gs[0, :])
320
- self.create_kpi_cards(ax1)
321
-
322
- # 시계열 트렌드
323
- ax2 = fig.add_subplot(gs[1, :2])
324
- self.create_trend_chart(ax2)
325
-
326
- # 카테고리별 분포
327
- ax3 = fig.add_subplot(gs[1, 2])
328
- self.create_category_distribution(ax3)
329
-
330
- # 히트맵
331
- ax4 = fig.add_subplot(gs[2, :2])
332
- self.create_correlation_heatmap(ax4)
333
-
334
- # 상위 10 항목
335
- ax5 = fig.add_subplot(gs[2, 2])
336
- self.create_top_items(ax5)
337
-
338
- plt.suptitle('Executive Dashboard', fontsize=20, y=0.98)
339
- return fig
340
-
341
- def create_kpi_cards(self, ax):
342
- """KPI 카드 생성"""
343
- ax.axis('off')
344
-
345
- kpis = [
346
- {'name': 'Total Revenue', 'value': '$1.2M', 'change': '+15%'},
347
- {'name': 'Active Users', 'value': '45.2K', 'change': '+8%'},
348
- {'name': 'Conversion Rate', 'value': '3.4%', 'change': '-2%'},
349
- {'name': 'Avg Order Value', 'value': '$85', 'change': '+12%'}
350
- ]
351
-
352
- for i, kpi in enumerate(kpis):
353
- x = i * 0.25 + 0.125
354
-
355
- # KPI 박스
356
- rect = plt.Rectangle((x - 0.1, 0.2), 0.2, 0.6,
357
- facecolor='lightblue',
358
- edgecolor='darkblue',
359
- linewidth=2)
360
- ax.add_patch(rect)
361
-
362
- # 텍스트
363
- ax.text(x, 0.65, kpi['name'], ha='center', fontsize=12)
364
- ax.text(x, 0.5, kpi['value'], ha='center',
365
- fontsize=18, fontweight='bold')
366
-
367
- # 변화율
368
- color = 'green' if kpi['change'].startswith('+') else 'red'
369
- ax.text(x, 0.35, kpi['change'], ha='center',
370
- fontsize=14, color=color)
371
- ```
372
-
373
- ### 2. 인터랙티브 시각화
374
- ```python
375
- import plotly.graph_objects as go
376
- import plotly.express as px
377
- from plotly.subplots import make_subplots
378
-
379
- class InteractiveVisualizations:
380
- def __init__(self, data):
381
- self.data = data
382
-
383
- def create_interactive_scatter(self, x_col, y_col, color_col=None, size_col=None):
384
- """인터랙티브 산점도 생성"""
385
- fig = px.scatter(
386
- self.data,
387
- x=x_col,
388
- y=y_col,
389
- color=color_col,
390
- size=size_col,
391
- hover_data=self.data.columns,
392
- title=f'{y_col} vs {x_col}',
393
- labels={x_col: x_col.replace('_', ' ').title(),
394
- y_col: y_col.replace('_', ' ').title()}
395
- )
396
-
397
- # 추세선 추가
398
- fig.add_trace(
399
- go.Scatter(
400
- x=self.data[x_col],
401
- y=self.data[y_col].rolling(window=7).mean(),
402
- mode='lines',
403
- name='7-day MA',
404
- line=dict(color='red', dash='dash')
405
- )
406
- )
407
-
408
- fig.update_layout(
409
- hovermode='closest',
410
- template='plotly_white',
411
- font=dict(size=12)
412
- )
413
-
414
- return fig
415
-
416
- def create_animated_timeline(self, date_col, value_col, category_col):
417
- """애니메이션 타임라인 차트"""
418
- # 데이터 준비
419
- df_animated = self.data.sort_values(date_col)
420
-
421
- fig = px.bar(
422
- df_animated,
423
- x=category_col,
424
- y=value_col,
425
- animation_frame=date_col,
426
- animation_group=category_col,
427
- range_y=[0, df_animated[value_col].max() * 1.1],
428
- title=f'{value_col} Timeline by {category_col}'
429
- )
430
-
431
- fig.update_layout(
432
- xaxis=dict(categoryorder='total descending'),
433
- showlegend=False
434
- )
435
-
436
- return fig
437
- ```
438
-
439
- ## 보고서 작성 가이드
440
-
441
- ### 1. 구조화된 인사이트
442
- ```python
443
- class InsightGenerator:
444
- def __init__(self, analysis_results):
445
- self.results = analysis_results
446
-
447
- def generate_insights(self):
448
- """자동 인사이트 생성"""
449
- insights = []
450
-
451
- # 트렌드 인사이트
452
- if 'trend_analysis' in self.results:
453
- trend = self.results['trend_analysis']
454
- if trend['slope'] > 0:
455
- insights.append({
456
- 'type': 'trend',
457
- 'severity': 'positive',
458
- 'message': f"{trend['metric']}이(가) {trend['period']} 동안 "
459
- f"{trend['change_pct']:.1f}% 증가했습니다.",
460
- 'recommendation': "현재 성장 모멘텀을 유지하기 위한 전략 수립 필요"
461
- })
462
-
463
- # 이상치 인사이트
464
- if 'anomalies' in self.results:
465
- anomalies = self.results['anomalies']
466
- if anomalies['count'] > 0:
467
- insights.append({
468
- 'type': 'anomaly',
469
- 'severity': 'warning',
470
- 'message': f"{anomalies['count']}개의 이상치가 발견되었습니다.",
471
- 'recommendation': "이상치 원인 분석 및 대응 방안 마련 필요"
472
- })
473
-
474
- return insights
475
-
476
- def create_executive_summary(self):
477
- """경영진 요약 보고서 생성"""
478
- summary = {
479
- 'overview': self.generate_overview(),
480
- 'key_findings': self.extract_key_findings(),
481
- 'recommendations': self.generate_recommendations(),
482
- 'next_steps': self.suggest_next_steps()
483
- }
484
-
485
- return self.format_summary(summary)
486
- ```
487
-
488
- ### 2. 자동화된 리포팅
489
- ```python
490
- class AutomatedReporting:
491
- def __init__(self, template_path):
492
- self.template_path = template_path
493
-
494
- def generate_report(self, data, analysis_results, output_path):
495
- """자동 리포트 생성"""
496
- from jinja2 import Template
497
- import pdfkit
498
-
499
- # 템플릿 로드
500
- with open(self.template_path, 'r') as f:
501
- template = Template(f.read())
502
-
503
- # 데이터 준비
504
- context = {
505
- 'report_date': datetime.now().strftime('%Y-%m-%d'),
506
- 'summary_stats': self.prepare_summary_stats(data),
507
- 'charts': self.generate_charts(data),
508
- 'insights': analysis_results.get('insights', []),
509
- 'recommendations': analysis_results.get('recommendations', [])
510
- }
511
-
512
- # HTML 생성
513
- html = template.render(**context)
514
-
515
- # PDF 변환
516
- options = {
517
- 'page-size': 'A4',
518
- 'margin-top': '0.75in',
519
- 'margin-right': '0.75in',
520
- 'margin-bottom': '0.75in',
521
- 'margin-left': '0.75in',
522
- 'encoding': "UTF-8",
523
- 'no-outline': None
524
- }
525
-
526
- pdfkit.from_string(html, output_path, options=options)
527
-
528
- return output_path
529
- ```
530
-
531
- ## 데이터 거버넌스
532
-
533
- ### 1. 데이터 품질 모니터링
534
- ```python
535
- class DataQualityMonitor:
536
- def __init__(self, rules):
537
- self.rules = rules
538
- self.violations = []
539
-
540
- def check_data_quality(self, df):
541
- """데이터 품질 검사"""
542
- results = {
543
- 'passed': 0,
544
- 'failed': 0,
545
- 'violations': []
546
- }
547
-
548
- for rule in self.rules:
549
- if rule['type'] == 'completeness':
550
- passed = self.check_completeness(df, rule)
551
- elif rule['type'] == 'uniqueness':
552
- passed = self.check_uniqueness(df, rule)
553
- elif rule['type'] == 'validity':
554
- passed = self.check_validity(df, rule)
555
- elif rule['type'] == 'consistency':
556
- passed = self.check_consistency(df, rule)
557
-
558
- if passed:
559
- results['passed'] += 1
560
- else:
561
- results['failed'] += 1
562
- results['violations'].append(rule)
563
-
564
- return results
565
-
566
- def check_completeness(self, df, rule):
567
- """완전성 검사"""
568
- column = rule['column']
569
- threshold = rule.get('threshold', 0.95)
570
-
571
- completeness = 1 - (df[column].isnull().sum() / len(df))
572
- return completeness >= threshold
573
- ```
574
-
575
- ## 체크리스트
576
-
577
- ### 분석 시작 전
578
- - [ ] 비즈니스 목표 명확화
579
- - [ ] 데이터 소스 확인
580
- - [ ] 데이터 품질 검증
581
- - [ ] 분석 계획 수립
582
-
583
- ### 분석 진행 중
584
- - [ ] 가정 사항 문서화
585
- - [ ] 중간 결과 검증
586
- - [ ] 이해관계자 피드백
587
- - [ ] 분석 재현성 확보
588
-
589
- ### 분석 완료 후
590
- - [ ] 결과 검증
591
- - [ ] 인사이트 도출
592
- - [ ] 시각화 최적화
593
- - [ ] 보고서 작성
594
- - [ ] 권고사항 제시