Spaces:
Sleeping
Sleeping
Manus AI commited on
Commit ·
05f52ea
1
Parent(s): d645a04
Fix: ImportError for 'preprocess_data' by moving the function from core/data_2.py to core/data.py and deleting data_2.py
Browse files- core/data.py +34 -0
- core/data_2.py +0 -325
core/data.py
CHANGED
|
@@ -372,3 +372,37 @@ def sentiment_analysis(ticker, start_date, end_date, api_key):
|
|
| 372 |
except Exception as e:
|
| 373 |
print_log(f"Sentiment analysis failed: {str(e)}", 'ERROR')
|
| 374 |
return f"Sentiment analysis failed: {str(e)}", None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 372 |
except Exception as e:
|
| 373 |
print_log(f"Sentiment analysis failed: {str(e)}", 'ERROR')
|
| 374 |
return f"Sentiment analysis failed: {str(e)}", None
|
| 375 |
+
|
| 376 |
+
|
| 377 |
+
def preprocess_data(df, features, target, window_size, horizon):
|
| 378 |
+
try:
|
| 379 |
+
print_log(f"Starting preprocessing: features={features}, target={target}, window={window_size}, horizon={horizon}")
|
| 380 |
+
|
| 381 |
+
if not isinstance(df.index, pd.DatetimeIndex):
|
| 382 |
+
raise ValueError("DataFrame index must be a DatetimeIndex for preprocessing.")
|
| 383 |
+
|
| 384 |
+
updated_feature_cols = [f for f in features if f in df.columns]
|
| 385 |
+
if not updated_feature_cols:
|
| 386 |
+
raise ValueError("None of the selected features are available in the data.")
|
| 387 |
+
|
| 388 |
+
data = df[updated_feature_cols].values
|
| 389 |
+
|
| 390 |
+
scaler = MinMaxScaler(feature_range=(0, 1))
|
| 391 |
+
scaled_data = scaler.fit_transform(data)
|
| 392 |
+
|
| 393 |
+
X, y = [], []
|
| 394 |
+
for i in range(len(scaled_data) - window_size - horizon + 1):
|
| 395 |
+
X.append(scaled_data[i:(i + window_size), :])
|
| 396 |
+
y.append(scaled_data[i + window_size + horizon - 1, updated_feature_cols.index(target)])
|
| 397 |
+
|
| 398 |
+
X, y = np.array(X), np.array(y)
|
| 399 |
+
|
| 400 |
+
if X.shape[1] != window_size or X.shape[2] != len(updated_feature_cols):
|
| 401 |
+
raise ValueError(f"Shape mismatch in X: expected ({len(scaled_data) - window_size - horizon + 1}, {window_size}, {len(updated_feature_cols)}), got {X.shape}")
|
| 402 |
+
|
| 403 |
+
print_log(f"Preprocessing complete. X shape: {X.shape}, y shape: {y.shape}")
|
| 404 |
+
return X, y, scaler, updated_feature_cols
|
| 405 |
+
except Exception as e:
|
| 406 |
+
print_log(f"Error in preprocess_data: {str(e)}", 'ERROR')
|
| 407 |
+
raise ValueError(f"Failed to preprocess data: {str(e)}")
|
| 408 |
+
|
core/data_2.py
DELETED
|
@@ -1,325 +0,0 @@
|
|
| 1 |
-
import pandas as pd
|
| 2 |
-
import numpy as np
|
| 3 |
-
import yfinance as yf
|
| 4 |
-
import os
|
| 5 |
-
try:
|
| 6 |
-
import talib as ta
|
| 7 |
-
except ImportError:
|
| 8 |
-
ta = None
|
| 9 |
-
from datetime import datetime, timedelta
|
| 10 |
-
from newsapi import NewsApiClient
|
| 11 |
-
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
|
| 12 |
-
from sklearn.preprocessing import MinMaxScaler
|
| 13 |
-
from alpha_vantage.timeseries import TimeSeries
|
| 14 |
-
import time
|
| 15 |
-
import logging
|
| 16 |
-
|
| 17 |
-
# Configure logging
|
| 18 |
-
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
| 19 |
-
|
| 20 |
-
def print_log(message, level='INFO'):
|
| 21 |
-
if level == 'INFO':
|
| 22 |
-
logging.info(message)
|
| 23 |
-
elif level == 'WARNING':
|
| 24 |
-
logging.warning(message)
|
| 25 |
-
elif level == 'ERROR':
|
| 26 |
-
logging.error(message)
|
| 27 |
-
else:
|
| 28 |
-
logging.debug(message)
|
| 29 |
-
|
| 30 |
-
analyzer = SentimentIntensityAnalyzer()
|
| 31 |
-
|
| 32 |
-
def load_data(data_src='yahoo', ticker='AAPL', start='2020-01-01', end='2023-01-01', interval='1d', file_upload=None, alpha_api_key=None):
|
| 33 |
-
try:
|
| 34 |
-
print_log(f"Loading data: source={data_src}, ticker={ticker}, start={start}, end={end}, interval={interval}, file_upload={'set' if file_upload else 'unset'}, alpha_api_key={'set' if alpha_api_key else 'unset'}")
|
| 35 |
-
|
| 36 |
-
start_date = pd.to_datetime(start)
|
| 37 |
-
end_date = pd.to_datetime(end)
|
| 38 |
-
if start_date >= end_date:
|
| 39 |
-
raise ValueError(f"Start date {start} must be before end date {end}")
|
| 40 |
-
if end_date > datetime.now():
|
| 41 |
-
print_log(f"End date {end} is in the future. Using current date as end date.", 'WARNING')
|
| 42 |
-
end_date = datetime.now()
|
| 43 |
-
|
| 44 |
-
df = pd.DataFrame()
|
| 45 |
-
|
| 46 |
-
if data_src == 'csv' and file_upload:
|
| 47 |
-
try:
|
| 48 |
-
file_path = getattr(file_upload, 'name', file_upload)
|
| 49 |
-
print_log(f"Loading CSV from {file_path}")
|
| 50 |
-
df = pd.read_csv(file_path)
|
| 51 |
-
if 'Date' not in df.columns:
|
| 52 |
-
raise ValueError("CSV must contain a 'Date' column")
|
| 53 |
-
df['Date'] = pd.to_datetime(df['Date']).dt.tz_localize(None)
|
| 54 |
-
df = df.set_index('Date')
|
| 55 |
-
if 'Close' not in df.columns and 'value' not in df.columns:
|
| 56 |
-
raise ValueError("CSV must contain 'Close' or 'value' column")
|
| 57 |
-
if 'Close' in df.columns:
|
| 58 |
-
df = df.rename(columns={'Close': 'value'})
|
| 59 |
-
if df.empty:
|
| 60 |
-
raise ValueError(f"CSV data is empty for {ticker}")
|
| 61 |
-
if df['value'].isna().all():
|
| 62 |
-
raise ValueError(f"CSV 'value' column contains only NaNs for {ticker}")
|
| 63 |
-
except Exception as e:
|
| 64 |
-
print_log(f"Failed to load CSV {file_path}: {str(e)}", 'ERROR')
|
| 65 |
-
raise ValueError(f"Failed to load CSV: {str(e)}")
|
| 66 |
-
else:
|
| 67 |
-
# Try Alpha Vantage first for intraday intervals if API key is provided
|
| 68 |
-
if interval in ['1m', '5m', '15m', '30m', '60m'] and alpha_api_key:
|
| 69 |
-
print_log(f"Attempting Alpha Vantage for {ticker}, interval {interval}")
|
| 70 |
-
try:
|
| 71 |
-
ts = TimeSeries(key=alpha_api_key, output_format='pandas')
|
| 72 |
-
df_av, _ = ts.get_intraday(symbol=ticker, interval=interval, outputsize='full')
|
| 73 |
-
if df_av.empty:
|
| 74 |
-
raise ValueError(f"No data returned from Alpha Vantage for {ticker}")
|
| 75 |
-
if '4. close' not in df_av.columns:
|
| 76 |
-
raise ValueError(f"Alpha Vantage data missing '4. close' column for {ticker}")
|
| 77 |
-
df_av = df_av.rename(columns={'4. close': 'value', '1. open': 'Open', '2. high': 'High', '3. low': 'Low', '5. volume': 'Volume'})
|
| 78 |
-
df_av['Date'] = pd.to_datetime(df_av.index)
|
| 79 |
-
df_av = df_av.reset_index(drop=True)
|
| 80 |
-
if df_av['value'].isna().all():
|
| 81 |
-
raise ValueError(f"Alpha Vantage 'value' column contains only NaNs for {ticker}")
|
| 82 |
-
if df_av['value'].empty:
|
| 83 |
-
raise ValueError(f"Alpha Vantage 'value' column is empty for {ticker}")
|
| 84 |
-
df = df_av # Use Alpha Vantage data if successful
|
| 85 |
-
except Exception as e:
|
| 86 |
-
print_log(f"Alpha Vantage failed: {str(e)}. Falling back to Yahoo Finance.", 'WARNING')
|
| 87 |
-
|
| 88 |
-
# If Alpha Vantage failed or not used, try Yahoo Finance
|
| 89 |
-
if df.empty:
|
| 90 |
-
print_log(f"Fetching data for {ticker} from Yahoo Finance")
|
| 91 |
-
try:
|
| 92 |
-
df = yf.download(ticker, start=start_date, end=end_date, interval=interval, progress=False, auto_adjust=False)
|
| 93 |
-
if isinstance(df.columns, pd.MultiIndex):
|
| 94 |
-
df.columns = df.columns.droplevel(1)
|
| 95 |
-
if df.empty:
|
| 96 |
-
raise ValueError(f"No data returned from Yahoo Finance for {ticker}")
|
| 97 |
-
if 'Close' not in df.columns:
|
| 98 |
-
raise ValueError(f"Yahoo Finance data missing 'Close' column for {ticker}")
|
| 99 |
-
df = df.rename(columns={'Close': 'value'})
|
| 100 |
-
if df['value'].isna().all():
|
| 101 |
-
raise ValueError(f"Yahoo Finance 'value' column contains only NaNs for {ticker}")
|
| 102 |
-
if df['value'].empty:
|
| 103 |
-
raise ValueError(f"Yahoo Finance 'value' column is empty for {ticker}")
|
| 104 |
-
except Exception as e:
|
| 105 |
-
print_log(f"Yahoo Finance failed for {ticker}: {str(e)}", 'ERROR')
|
| 106 |
-
raise ValueError(f"Yahoo Finance failed for {ticker}: {str(e)}")
|
| 107 |
-
|
| 108 |
-
if df.empty:
|
| 109 |
-
raise ValueError(f"No data loaded for {ticker} from {data_src}")
|
| 110 |
-
|
| 111 |
-
if not isinstance(df.index, pd.DatetimeIndex):
|
| 112 |
-
df.index = pd.to_datetime(df.index)
|
| 113 |
-
df = df.sort_index()
|
| 114 |
-
|
| 115 |
-
required_cols = ['Open', 'High', 'Low', 'value', 'Volume']
|
| 116 |
-
for col in required_cols:
|
| 117 |
-
if col not in df.columns:
|
| 118 |
-
df[col] = np.nan
|
| 119 |
-
|
| 120 |
-
if 'value' not in df.columns:
|
| 121 |
-
raise ValueError(f"Target column 'value' is missing for {ticker}")
|
| 122 |
-
if df['value'].isna().all():
|
| 123 |
-
raise ValueError(f"Target column 'value' contains only NaNs for {ticker}")
|
| 124 |
-
if df['value'].empty:
|
| 125 |
-
raise ValueError(f"Target column 'value' is empty for {ticker}")
|
| 126 |
-
|
| 127 |
-
print_log(f"Data loaded for {ticker} with date range: {df.index.min()} to {df.index.max()}, shape: {df.shape}")
|
| 128 |
-
return df
|
| 129 |
-
except Exception as e:
|
| 130 |
-
print_log(f"Error in load_data for {ticker}: {str(e)}", 'ERROR')
|
| 131 |
-
raise ValueError(f"Failed to load data for {ticker}: {str(e)}")
|
| 132 |
-
|
| 133 |
-
def add_technical_indicators(df, selected_indicators):
|
| 134 |
-
try:
|
| 135 |
-
print_log(f"Starting add_technical_indicators with indicators: {selected_indicators}")
|
| 136 |
-
if df.empty:
|
| 137 |
-
print_log("DataFrame is empty, skipping technical indicator calculation.", "WARNING")
|
| 138 |
-
return df, []
|
| 139 |
-
|
| 140 |
-
for col in ['Open', 'High', 'Low', 'value', 'Volume']:
|
| 141 |
-
if col not in df.columns:
|
| 142 |
-
df[col] = np.nan
|
| 143 |
-
df[col] = pd.to_numeric(df[col], errors='coerce')
|
| 144 |
-
|
| 145 |
-
df.dropna(subset=['Open', 'High', 'Low', 'value', 'Volume'], inplace=True)
|
| 146 |
-
if df.empty:
|
| 147 |
-
print_log("DataFrame is empty after dropping NaNs for technical indicators.", "WARNING")
|
| 148 |
-
return df, []
|
| 149 |
-
|
| 150 |
-
if ta is None:
|
| 151 |
-
print_log("TA-Lib not available. Cannot compute indicators. Falling back to 'value'.", 'ERROR')
|
| 152 |
-
return df, []
|
| 153 |
-
|
| 154 |
-
close = df['value'].values
|
| 155 |
-
high = df['High'].values
|
| 156 |
-
low = df['Low'].values
|
| 157 |
-
volume = df['Volume'].values
|
| 158 |
-
open_ = df['Open'].values
|
| 159 |
-
|
| 160 |
-
indicator_map = {
|
| 161 |
-
'rsi': {'func': ta.RSI, 'inputs': ['close'], 'params': {'timeperiod': 14}, 'output': ['rsi_14']},
|
| 162 |
-
'macd': {'func': ta.MACD, 'inputs': ['close'], 'params': {'fastperiod': 12, 'slowperiod': 26, 'signalperiod': 9}, 'output': ['macd_12_26_9', 'macds_12_26_9', 'macdh_12_26_9']},
|
| 163 |
-
'bbands': {'func': ta.BBANDS, 'inputs': ['close'], 'params': {'timeperiod': 20, 'nbdevup': 2, 'nbdevdn': 2}, 'output': ['bbu_20_2.0', 'bbm_20_2.0', 'bbl_20_2.0']},
|
| 164 |
-
'sma': {'func': ta.SMA, 'inputs': ['close'], 'params': {'timeperiod': 20}, 'output': ['sma_20']},
|
| 165 |
-
'ema': {'func': ta.EMA, 'inputs': ['close'], 'params': {'timeperiod': 20}, 'output': ['ema_20']},
|
| 166 |
-
'atr': {'func': ta.ATR, 'inputs': ['high', 'low', 'close'], 'params': {'timeperiod': 14}, 'output': ['atr_14']},
|
| 167 |
-
'stoch': {'func': ta.STOCH, 'inputs': ['high', 'low', 'close'], 'params': {'fastk_period': 14, 'slowk_period': 3, 'slowd_period': 3}, 'output': ['stochk_14_3_3', 'stochd_14_3_3']},
|
| 168 |
-
'adx': {'func': ta.ADX, 'inputs': ['high', 'low', 'close'], 'params': {'timeperiod': 14}, 'output': ['adx_14']},
|
| 169 |
-
'willr': {'func': ta.WILLR, 'inputs': ['high', 'low', 'close'], 'params': {'timeperiod': 14}, 'output': ['willr_14']},
|
| 170 |
-
'cci': {'func': ta.CCI, 'inputs': ['high', 'low', 'close'], 'params': {'timeperiod': 20}, 'output': ['cci_20']},
|
| 171 |
-
'pdi': {'func': ta.PLUS_DI, 'inputs': ['high', 'low', 'close'], 'params': {'timeperiod': 14}, 'output': ['pdi_14']},
|
| 172 |
-
'mdi': {'func': ta.MINUS_DI, 'inputs': ['high', 'low', 'close'], 'params': {'timeperiod': 14}, 'output': ['mdi_14']}
|
| 173 |
-
}
|
| 174 |
-
|
| 175 |
-
input_dict = {'close': close, 'high': high, 'low': low, 'open': open_, 'volume': volume}
|
| 176 |
-
|
| 177 |
-
valid_indicators = []
|
| 178 |
-
for ind in selected_indicators:
|
| 179 |
-
if ind in indicator_map:
|
| 180 |
-
print_log(f"Computing indicator: {ind}")
|
| 181 |
-
config = indicator_map[ind]
|
| 182 |
-
func = config['func']
|
| 183 |
-
inputs = config['inputs']
|
| 184 |
-
params = config['params']
|
| 185 |
-
try:
|
| 186 |
-
input_arrays = [input_dict[inp] for inp in inputs]
|
| 187 |
-
result = func(*input_arrays, **params)
|
| 188 |
-
if isinstance(result, tuple):
|
| 189 |
-
for j, (res, out_col) in enumerate(zip(result, config['output'])):
|
| 190 |
-
if isinstance(res, np.ndarray) and len(res) == len(df):
|
| 191 |
-
df[out_col] = res
|
| 192 |
-
nan_count = np.isnan(res).sum()
|
| 193 |
-
if nan_count < len(res) * 0.5:
|
| 194 |
-
valid_indicators.append(out_col)
|
| 195 |
-
else:
|
| 196 |
-
print_log(f"{out_col} has excessive NaNs: {nan_count}/{len(res)}. Excluding from valid indicators.", 'WARNING')
|
| 197 |
-
else:
|
| 198 |
-
print_log(f"Invalid output for {out_col}: {type(res)}, length: {len(res) if hasattr(res, '__len__') else 'N/A'}", 'WARNING')
|
| 199 |
-
else:
|
| 200 |
-
if isinstance(result, np.ndarray) and len(result) == len(df):
|
| 201 |
-
df[config['output'][0]] = result
|
| 202 |
-
nan_count = np.isnan(result).sum()
|
| 203 |
-
if nan_count < len(result) * 0.5:
|
| 204 |
-
valid_indicators.append(config['output'][0])
|
| 205 |
-
else:
|
| 206 |
-
print_log(f"{config['output'][0]} has excessive NaNs: {nan_count}/{len(result)}. Excluding from valid indicators.", 'WARNING')
|
| 207 |
-
else:
|
| 208 |
-
print_log(f"Invalid output for {ind}: {type(result)}, length: {len(result) if hasattr(result, '__len__') else 'N/A'}", 'WARNING')
|
| 209 |
-
except Exception as e:
|
| 210 |
-
print_log(f"Error computing {ind}: {str(e)}", 'ERROR')
|
| 211 |
-
else:
|
| 212 |
-
print_log(f"Indicator {ind} not supported by TA-Lib", 'WARNING')
|
| 213 |
-
|
| 214 |
-
initial_rows = len(df)
|
| 215 |
-
df = df.dropna(subset=['value']).reset_index(drop=False)
|
| 216 |
-
print_log(f"Dropped {initial_rows - len(df)} rows with NaN in 'value'")
|
| 217 |
-
|
| 218 |
-
for col in df.columns:
|
| 219 |
-
if col not in ['Date', 'Open', 'High', 'Low', 'value', 'Volume']:
|
| 220 |
-
nan_ratio = df[col].isna().mean()
|
| 221 |
-
if nan_ratio > 0.5:
|
| 222 |
-
print_log(f"Dropping {col} due to excessive NaNs: {nan_ratio:.2%}", 'WARNING')
|
| 223 |
-
df = df.drop(columns=[col])
|
| 224 |
-
if col in valid_indicators:
|
| 225 |
-
valid_indicators.remove(col)
|
| 226 |
-
|
| 227 |
-
if not valid_indicators:
|
| 228 |
-
print_log("No valid indicators computed. Falling back to 'value'.", "WARNING")
|
| 229 |
-
valid_indicators.append('value')
|
| 230 |
-
|
| 231 |
-
print_log(f"Valid indicators: {valid_indicators}")
|
| 232 |
-
print_log(f"Technical indicators added successfully, shape: {df.shape}")
|
| 233 |
-
df.set_index('Date', inplace=True)
|
| 234 |
-
return df, valid_indicators
|
| 235 |
-
except Exception as e:
|
| 236 |
-
print_log(f"Error in add_technical_indicators: {str(e)}", 'ERROR')
|
| 237 |
-
return df, []
|
| 238 |
-
|
| 239 |
-
def add_sentiment(df, ticker, news_api_key, start_date, end_date):
|
| 240 |
-
try:
|
| 241 |
-
print_log(f"Starting add_sentiment for {ticker} from {start_date} to {end_date}")
|
| 242 |
-
if not news_api_key:
|
| 243 |
-
print_log("News API key not provided. Skipping sentiment analysis.", 'WARNING')
|
| 244 |
-
df['sentiment_score'] = 0.0
|
| 245 |
-
return df
|
| 246 |
-
|
| 247 |
-
newsapi = NewsApiClient(api_key=news_api_key)
|
| 248 |
-
all_articles = []
|
| 249 |
-
current_date = pd.to_datetime(start_date)
|
| 250 |
-
end_date = pd.to_datetime(end_date)
|
| 251 |
-
|
| 252 |
-
while current_date <= end_date:
|
| 253 |
-
from_param = current_date.strftime("%Y-%m-%d")
|
| 254 |
-
to_param = (current_date + timedelta(days=1)).strftime("%Y-%m-%d")
|
| 255 |
-
print_log(f"Fetching news for {ticker} from {from_param} to {to_param}")
|
| 256 |
-
try:
|
| 257 |
-
articles = newsapi.get_everything(q=ticker, language='en', sort_by='relevancy', from_param=from_param, to=to_param)
|
| 258 |
-
all_articles.extend(articles["articles"])
|
| 259 |
-
except Exception as e:
|
| 260 |
-
print_log(f"Error fetching news for {ticker} on {from_param}: {str(e)}", 'ERROR')
|
| 261 |
-
current_date += timedelta(days=1)
|
| 262 |
-
time.sleep(0.1)
|
| 263 |
-
|
| 264 |
-
if not all_articles:
|
| 265 |
-
print_log(f"No articles found for {ticker}. Setting sentiment to 0.", 'WARNING')
|
| 266 |
-
df['sentiment_score'] = 0.0
|
| 267 |
-
return df
|
| 268 |
-
|
| 269 |
-
sentiment_data = []
|
| 270 |
-
for article in all_articles:
|
| 271 |
-
if article["publishedAt"] and article["description"]:
|
| 272 |
-
date = pd.to_datetime(article["publishedAt"]).tz_localize(None).date()
|
| 273 |
-
text = article["description"]
|
| 274 |
-
vs = analyzer.polarity_scores(text)
|
| 275 |
-
sentiment_data.append({"Date": date, "sentiment_score": vs["compound"]})
|
| 276 |
-
|
| 277 |
-
sentiment_df = pd.DataFrame(sentiment_data)
|
| 278 |
-
sentiment_df["Date"] = pd.to_datetime(sentiment_df["Date"])
|
| 279 |
-
sentiment_df = sentiment_df.groupby("Date")["sentiment_score"].mean().reset_index()
|
| 280 |
-
|
| 281 |
-
df.reset_index(inplace=True)
|
| 282 |
-
df['Date'] = pd.to_datetime(df['Date'])
|
| 283 |
-
df = pd.merge(df, sentiment_df, on="Date", how="left")
|
| 284 |
-
df['sentiment_score'] = df['sentiment_score'].fillna(0.0)
|
| 285 |
-
df.set_index('Date', inplace=True)
|
| 286 |
-
|
| 287 |
-
print_log(f"Sentiment analysis completed for {ticker}. Added sentiment_score column.")
|
| 288 |
-
return df
|
| 289 |
-
except Exception as e:
|
| 290 |
-
print_log(f"Error in add_sentiment for {ticker}: {str(e)}", 'ERROR')
|
| 291 |
-
df['sentiment_score'] = 0.0
|
| 292 |
-
return df
|
| 293 |
-
|
| 294 |
-
def preprocess_data(df, features, target, window_size, horizon):
|
| 295 |
-
try:
|
| 296 |
-
print_log(f"Starting preprocessing: features={features}, target={target}, window={window_size}, horizon={horizon}")
|
| 297 |
-
|
| 298 |
-
if not isinstance(df.index, pd.DatetimeIndex):
|
| 299 |
-
raise ValueError("DataFrame index must be a DatetimeIndex for preprocessing.")
|
| 300 |
-
|
| 301 |
-
updated_feature_cols = [f for f in features if f in df.columns]
|
| 302 |
-
if not updated_feature_cols:
|
| 303 |
-
raise ValueError("None of the selected features are available in the data.")
|
| 304 |
-
|
| 305 |
-
data = df[updated_feature_cols].values
|
| 306 |
-
|
| 307 |
-
scaler = MinMaxScaler(feature_range=(0, 1))
|
| 308 |
-
scaled_data = scaler.fit_transform(data)
|
| 309 |
-
|
| 310 |
-
X, y = [], []
|
| 311 |
-
for i in range(len(scaled_data) - window_size - horizon + 1):
|
| 312 |
-
X.append(scaled_data[i:(i + window_size), :])
|
| 313 |
-
y.append(scaled_data[i + window_size + horizon - 1, updated_feature_cols.index(target)])
|
| 314 |
-
|
| 315 |
-
X, y = np.array(X), np.array(y)
|
| 316 |
-
|
| 317 |
-
if X.shape[1] != window_size or X.shape[2] != len(updated_feature_cols):
|
| 318 |
-
raise ValueError(f"Shape mismatch in X: expected ({len(scaled_data) - window_size - horizon + 1}, {window_size}, {len(updated_feature_cols)}), got {X.shape}")
|
| 319 |
-
|
| 320 |
-
print_log(f"Preprocessing complete. X shape: {X.shape}, y shape: {y.shape}")
|
| 321 |
-
return X, y, scaler, updated_feature_cols
|
| 322 |
-
except Exception as e:
|
| 323 |
-
print_log(f"Error in preprocess_data: {str(e)}", 'ERROR')
|
| 324 |
-
raise ValueError(f"Failed to preprocess data: {str(e)}")
|
| 325 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|