-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdata_handler.py
More file actions
225 lines (182 loc) · 9.13 KB
/
Copy pathdata_handler.py
File metadata and controls
225 lines (182 loc) · 9.13 KB
1
2
3
4
5
6
7
8
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
import pandas as pd
import numpy as np
import hashlib
from datetime import datetime
from collections import defaultdict
from pathlib import Path
class PowerballDataHandler:
"""Handles data loading, preparation, and feature engineering for Powerball predictions"""
def __init__(self, csv_path):
self.csv_path = csv_path
self.data = pd.read_csv(csv_path)
self.prepare_data()
def prepare_data(self):
"""Prepare and engineer features from raw data"""
# Now that CSV headers are corrected, we can use the proper column mapping
corrected_data = self.data.copy()
# Create proper date from the actual Month, Day, Year columns
corrected_data['Date'] = pd.to_datetime(
corrected_data[['Year', 'Month', 'Day']],
errors='coerce'
)
# Map the lottery numbers correctly with the fixed headers:
# Num 1-5 are the white balls (1-69 range)
# Powerball is the red powerball (1-26 range)
# PowerPlay is the multiplier
corrected_data['White_1'] = corrected_data['Num 1'] # 1st white ball
corrected_data['White_2'] = corrected_data['Num 2'] # 2nd white ball
corrected_data['White_3'] = corrected_data['Num 3'] # 3rd white ball
corrected_data['White_4'] = corrected_data['Num 4'] # 4th white ball
corrected_data['White_5'] = corrected_data['Num 5'] # 5th white ball
corrected_data['Powerball'] = corrected_data['Powerball'] # Powerball (1-26 range)
# Set up for the algorithm
self.white_cols = ['White_1', 'White_2', 'White_3', 'White_4', 'White_5']
self.whites = corrected_data[self.white_cols].values
self.powerballs = corrected_data['Powerball'].values
# Sort by date (most recent first) for time series analysis
corrected_data = corrected_data.sort_values('Date', ascending=False).reset_index(drop=True)
self.data = corrected_data
def calculate_data_hash(self):
"""Calculate hash of data for cache validation"""
try:
sorted_data = self.data.sort_values(['Year', 'Month', 'Day']).reset_index(drop=True)
data_string = ''.join(str(row.values) for _, row in sorted_data.iterrows())
return hashlib.md5(data_string.encode()).hexdigest()
except Exception:
return hashlib.md5(str(datetime.now().timestamp()).encode()).hexdigest()
def engineer_features(self, lookback_draws=200, adaptive_window=True):
"""Engineer comprehensive features from historical data"""
if len(self.data) < lookback_draws:
lookback_draws = len(self.data)
recent_data = self.data.head(lookback_draws).copy()
features = {}
# 1. Basic frequency analysis for each position
for i, col in enumerate(self.white_cols):
freq = recent_data[col].value_counts().to_dict()
features[f'pos_{i+1}_frequencies'] = freq
# Powerball frequencies
pb_freq = recent_data['Powerball'].value_counts().to_dict()
features['powerball_frequencies'] = pb_freq
# 2. Hot/Cold analysis (recent vs historical performance)
hot_window = min(30, len(recent_data) // 4)
cold_window = min(100, len(recent_data))
features['hot_numbers'] = {}
features['cold_numbers'] = {}
for i, col in enumerate(self.white_cols):
hot_freq = recent_data.head(hot_window)[col].value_counts().to_dict()
cold_freq = recent_data.tail(cold_window)[col].value_counts().to_dict()
features['hot_numbers'][f'pos_{i+1}'] = hot_freq
features['cold_numbers'][f'pos_{i+1}'] = cold_freq
# Hot/Cold powerball
hot_pb_freq = recent_data.head(hot_window)['Powerball'].value_counts().to_dict()
cold_pb_freq = recent_data.tail(cold_window)['Powerball'].value_counts().to_dict()
features['hot_numbers']['powerball'] = hot_pb_freq
features['cold_numbers']['powerball'] = cold_pb_freq
# 3. Gap analysis (draws since last appearance)
features['gaps'] = {}
for i, col in enumerate(self.white_cols):
gaps = {}
for num in range(1, 70): # White balls 1-69
last_seen = None
for idx, row in recent_data.iterrows():
if row[col] == num:
last_seen = idx
break
gaps[num] = last_seen if last_seen is not None else len(recent_data)
features['gaps'][f'pos_{i+1}'] = gaps
# Powerball gaps
pb_gaps = {}
for num in range(1, 27): # Powerball 1-26
last_seen = None
for idx, row in recent_data.iterrows():
if row['Powerball'] == num:
last_seen = idx
break
pb_gaps[num] = last_seen if last_seen is not None else len(recent_data)
features['gaps']['powerball'] = pb_gaps
# 4. Pattern analysis
features['patterns'] = self._analyze_patterns(recent_data)
# 5. Temporal features
features['temporal'] = self._analyze_temporal_patterns(recent_data)
# 6. Statistical features
features['stats'] = self._calculate_statistical_features(recent_data)
return features
def _analyze_patterns(self, data):
"""Analyze number patterns and relationships"""
patterns = {
'consecutive_pairs': defaultdict(int),
'sum_ranges': defaultdict(int),
'odd_even_patterns': defaultdict(int),
'high_low_patterns': defaultdict(int)
}
for _, row in data.iterrows():
whites = sorted([row[col] for col in self.white_cols])
# Consecutive pairs
for i in range(len(whites) - 1):
if whites[i+1] - whites[i] == 1:
patterns['consecutive_pairs'][f"{whites[i]}-{whites[i+1]}"] += 1
# Sum ranges
total_sum = sum(whites)
if total_sum <= 150:
patterns['sum_ranges']['low'] += 1
elif total_sum <= 210:
patterns['sum_ranges']['medium'] += 1
else:
patterns['sum_ranges']['high'] += 1
# Odd/Even patterns
odd_count = sum(1 for w in whites if w % 2 == 1)
patterns['odd_even_patterns'][f"{odd_count}_odd"] += 1
# High/Low patterns (>34 is high)
high_count = sum(1 for w in whites if w > 34)
patterns['high_low_patterns'][f"{high_count}_high"] += 1
return patterns
def _analyze_temporal_patterns(self, data):
"""Analyze temporal patterns in the data"""
temporal = {
'weekday_patterns': defaultdict(lambda: defaultdict(int)),
'month_patterns': defaultdict(lambda: defaultdict(int)),
'seasonal_trends': defaultdict(list)
}
for _, row in data.iterrows():
date = row['Date']
if pd.isna(date):
continue
weekday = date.weekday()
month = date.month
# Analyze patterns by weekday and month
for i, col in enumerate(self.white_cols):
temporal['weekday_patterns'][f'pos_{i+1}'][weekday] += 1
temporal['month_patterns'][f'pos_{i+1}'][month] += 1
temporal['seasonal_trends'][f'pos_{i+1}'].append(row[col])
temporal['weekday_patterns']['powerball'][weekday] += 1
temporal['month_patterns']['powerball'][month] += 1
temporal['seasonal_trends']['powerball'].append(row['Powerball'])
return temporal
def _calculate_statistical_features(self, data):
"""Calculate various statistical features"""
stats = {}
# Basic statistics for each position
for i, col in enumerate(self.white_cols):
values = data[col].values
stats[f'pos_{i+1}'] = {
'mean': np.mean(values),
'std': np.std(values),
'median': np.median(values),
'mode': data[col].mode().iloc[0] if not data[col].mode().empty else 0,
'skewness': data[col].skew(),
'kurtosis': data[col].kurtosis()
}
# Powerball statistics
pb_values = data['Powerball'].values
stats['powerball'] = {
'mean': np.mean(pb_values),
'std': np.std(pb_values),
'median': np.median(pb_values),
'mode': data['Powerball'].mode().iloc[0] if not data['Powerball'].mode().empty else 0,
'skewness': data['Powerball'].skew(),
'kurtosis': data['Powerball'].kurtosis()
}
# Cross-position correlations
white_data = data[self.white_cols]
stats['correlations'] = white_data.corr().to_dict()
return stats