Add advanced pattern detection features to Powerball reader
- Enhanced CSV parsing script to include advanced statistical analyses. - Implemented functions to detect consecutive numbers, odd/even distributions, high/low distributions, sum patterns, gap patterns, hot/cold numbers, overdue numbers, number pairs, and decade distributions. - Integrated pattern analysis results into combination generation for more strategic number selection. - Updated main function to run advanced analyses and generate pattern-based combinations.
This commit is contained in:
@@ -22,7 +22,7 @@ IPMIPW = None
|
||||
IPMIEK = DEFAULT_EK
|
||||
|
||||
# Fan / temperature settings
|
||||
FANSPEED = 20 # percent
|
||||
FANSPEED = 15 # percent
|
||||
MAXTEMP = 37 # Celsius
|
||||
|
||||
def build_ipmi_base():
|
||||
|
||||
@@ -77,6 +77,16 @@ clean_walfiles() {
|
||||
fi
|
||||
done < <(find "$WAL_ARCHIVE_DIR" -maxdepth 1 -type f ! -name '*.backup' -print0)
|
||||
|
||||
# Also delete old .backup files (except the newest one) that exceed retention period
|
||||
for backup_file in "${backup_files[@]}"; do
|
||||
if [[ "$backup_file" != "$newest_backup" ]]; then
|
||||
backup_ts=$(stat -c %Y "$backup_file")
|
||||
if [[ "$backup_ts" -lt "$age_cutoff_ts" ]]; then
|
||||
files_to_delete+=("$backup_file")
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ${#files_to_delete[@]} -eq 0 ]]; then
|
||||
log "No WAL files matched cleanup criteria."
|
||||
return 0
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Fix the powerball CSV file format."""
|
||||
|
||||
import shutil
|
||||
|
||||
# Read the original file
|
||||
with open('powerball_numbers.csv', 'r') as f:
|
||||
lines = f.readlines()
|
||||
|
||||
# Create backup
|
||||
shutil.copy('powerball_numbers.csv', 'powerball_numbers.csv.backup')
|
||||
|
||||
# Open output file
|
||||
with open('powerball_numbers.csv', 'w') as f:
|
||||
# Write header
|
||||
f.write('Draw Date,Winning Numbers,Multiplier\n')
|
||||
|
||||
# Process each line
|
||||
for line in lines:
|
||||
parts = line.strip().split(',')
|
||||
|
||||
# Extract components
|
||||
month = parts[0]
|
||||
day_year = parts[1].split('/')
|
||||
day = day_year[0]
|
||||
year = day_year[1]
|
||||
|
||||
# Format date as MM/DD/YYYY
|
||||
date = f"{int(month):02d}/{int(day):02d}/{year}"
|
||||
|
||||
# Get the 6 winning numbers (5 white balls + 1 powerball)
|
||||
numbers = ' '.join(parts[2:8])
|
||||
|
||||
# Get the multiplier
|
||||
multiplier = parts[8]
|
||||
|
||||
# Write the formatted line
|
||||
f.write(f'{date},{numbers},{multiplier}\n')
|
||||
|
||||
print("✓ File fixed! Created backup at powerball_numbers.csv.backup")
|
||||
print("\nFirst few lines of fixed file:")
|
||||
with open('powerball_numbers.csv', 'r') as f:
|
||||
for i, line in enumerate(f):
|
||||
if i < 5:
|
||||
print(line.strip())
|
||||
else:
|
||||
break
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Script to read and parse Powerball numbers from a CSV file.
|
||||
Script to read and parse Powerball numbers from a CSV file with advanced pattern detection.
|
||||
"""
|
||||
|
||||
import csv
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Tuple, Optional
|
||||
from collections import Counter
|
||||
from typing import List, Dict, Tuple, Optional, Set
|
||||
from collections import Counter, defaultdict
|
||||
from itertools import combinations
|
||||
|
||||
|
||||
def read_powerball_csv(filepath: str) -> List[Dict]:
|
||||
@@ -115,8 +116,8 @@ def _get_recency_weighted_top_numbers(draws: List[Dict]) -> Tuple[List[int], Opt
|
||||
sorted_draws = sorted(draws, key=lambda x: x['draw_date'])
|
||||
total_draws = len(sorted_draws)
|
||||
|
||||
white_scores = Counter()
|
||||
powerball_scores = Counter()
|
||||
white_scores: Dict[int, float] = defaultdict(float)
|
||||
powerball_scores: Dict[int, float] = defaultdict(float)
|
||||
|
||||
for index, entry in enumerate(sorted_draws, start=1):
|
||||
weight = index / total_draws
|
||||
@@ -128,8 +129,8 @@ def _get_recency_weighted_top_numbers(draws: List[Dict]) -> Tuple[List[int], Opt
|
||||
if len(numbers) >= 6:
|
||||
powerball_scores[numbers[5]] += weight
|
||||
|
||||
top_white = [number for number, _ in white_scores.most_common(5)]
|
||||
top_powerball = powerball_scores.most_common(1)[0][0] if powerball_scores else None
|
||||
top_white = [number for number, _ in sorted(white_scores.items(), key=lambda x: x[1], reverse=True)[:5]]
|
||||
top_powerball = max(powerball_scores.items(), key=lambda x: x[1])[0] if powerball_scores else None
|
||||
|
||||
return top_white, top_powerball
|
||||
|
||||
@@ -142,8 +143,8 @@ def _get_aggressive_recency_weighted_top_numbers(draws: List[Dict]) -> Tuple[Lis
|
||||
sorted_draws = sorted(draws, key=lambda x: x['draw_date'])
|
||||
total_draws = len(sorted_draws)
|
||||
|
||||
white_scores = Counter()
|
||||
powerball_scores = Counter()
|
||||
white_scores: Dict[int, float] = defaultdict(float)
|
||||
powerball_scores: Dict[int, float] = defaultdict(float)
|
||||
|
||||
for index, entry in enumerate(sorted_draws, start=1):
|
||||
normalized_position = index / total_draws
|
||||
@@ -156,8 +157,8 @@ def _get_aggressive_recency_weighted_top_numbers(draws: List[Dict]) -> Tuple[Lis
|
||||
if len(numbers) >= 6:
|
||||
powerball_scores[numbers[5]] += weight
|
||||
|
||||
top_white = [number for number, _ in white_scores.most_common(5)]
|
||||
top_powerball = powerball_scores.most_common(1)[0][0] if powerball_scores else None
|
||||
top_white = [number for number, _ in sorted(white_scores.items(), key=lambda x: x[1], reverse=True)[:5]]
|
||||
top_powerball = max(powerball_scores.items(), key=lambda x: x[1])[0] if powerball_scores else None
|
||||
|
||||
return top_white, top_powerball
|
||||
|
||||
@@ -171,7 +172,7 @@ def analyze_most_frequent_numbers(data: List[Dict]) -> Dict:
|
||||
"""
|
||||
if not data:
|
||||
print("No data to analyze.")
|
||||
return
|
||||
return {}
|
||||
|
||||
# Initialize lists to hold numbers for each position
|
||||
num_positions = len(data[0]['winning_numbers'])
|
||||
@@ -267,7 +268,7 @@ def generate_suggested_combination(stats: dict) -> None:
|
||||
print("Suggested Combination Based on Statistical Analysis")
|
||||
print("=" * 60)
|
||||
|
||||
print("\n⚠️ DISCLAIMER: This is purely statistical analysis.")
|
||||
print("\n*** DISCLAIMER: This is purely statistical analysis.")
|
||||
print("Past results do NOT predict future outcomes.")
|
||||
print("Each draw is random and independent.\n")
|
||||
|
||||
@@ -350,6 +351,569 @@ def generate_suggested_combination(stats: dict) -> None:
|
||||
print("Insufficient data to generate a suggestion.")
|
||||
|
||||
|
||||
def detect_consecutive_patterns(data: List[Dict]) -> Dict:
|
||||
"""
|
||||
Analyze frequency of consecutive numbers in draws.
|
||||
|
||||
Args:
|
||||
data: List of powerball data dictionaries
|
||||
|
||||
Returns:
|
||||
Dictionary with consecutive number statistics
|
||||
"""
|
||||
consecutive_counts = Counter()
|
||||
total_draws = len(data)
|
||||
draws_with_consecutives = 0
|
||||
consecutive_pairs = []
|
||||
|
||||
for entry in data:
|
||||
white_balls = sorted(entry['winning_numbers'][:5])
|
||||
has_consecutive = False
|
||||
|
||||
for i in range(len(white_balls) - 1):
|
||||
if white_balls[i+1] - white_balls[i] == 1:
|
||||
consecutive_counts[f"{white_balls[i]}-{white_balls[i+1]}"] += 1
|
||||
consecutive_pairs.append((white_balls[i], white_balls[i+1]))
|
||||
has_consecutive = True
|
||||
|
||||
if has_consecutive:
|
||||
draws_with_consecutives += 1
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("PATTERN: Consecutive Numbers Analysis")
|
||||
print("=" * 60)
|
||||
percentage = (draws_with_consecutives / total_draws) * 100 if total_draws > 0 else 0
|
||||
print(f"Draws with consecutive numbers: {draws_with_consecutives}/{total_draws} ({percentage:.1f}%)")
|
||||
|
||||
if consecutive_counts:
|
||||
print("\nMost common consecutive pairs:")
|
||||
for pair, count in consecutive_counts.most_common(10):
|
||||
pair_pct = (count / total_draws) * 100
|
||||
print(f" {pair}: {count} times ({pair_pct:.1f}%)")
|
||||
|
||||
return {
|
||||
'draws_with_consecutives': draws_with_consecutives,
|
||||
'percentage': percentage,
|
||||
'common_pairs': dict(consecutive_counts.most_common(10))
|
||||
}
|
||||
|
||||
|
||||
def detect_odd_even_patterns(data: List[Dict]) -> Dict:
|
||||
"""
|
||||
Analyze odd/even distribution patterns.
|
||||
|
||||
Args:
|
||||
data: List of powerball data dictionaries
|
||||
|
||||
Returns:
|
||||
Dictionary with odd/even distribution statistics
|
||||
"""
|
||||
distribution = Counter()
|
||||
|
||||
for entry in data:
|
||||
white_balls = entry['winning_numbers'][:5]
|
||||
odd_count = sum(1 for num in white_balls if num % 2 == 1)
|
||||
even_count = 5 - odd_count
|
||||
distribution[f"{odd_count}odd-{even_count}even"] += 1
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("PATTERN: Odd/Even Distribution")
|
||||
print("=" * 60)
|
||||
print("Distribution of odd vs even numbers:")
|
||||
|
||||
total = sum(distribution.values())
|
||||
for pattern, count in sorted(distribution.items(), key=lambda x: x[1], reverse=True):
|
||||
percentage = (count / total) * 100
|
||||
print(f" {pattern}: {count} times ({percentage:.1f}%)")
|
||||
|
||||
return {'distribution': dict(distribution)}
|
||||
|
||||
|
||||
def detect_high_low_patterns(data: List[Dict]) -> Dict:
|
||||
"""
|
||||
Analyze high/low number distribution (1-35 = low, 36-69 = high).
|
||||
|
||||
Args:
|
||||
data: List of powerball data dictionaries
|
||||
|
||||
Returns:
|
||||
Dictionary with high/low distribution statistics
|
||||
"""
|
||||
distribution = Counter()
|
||||
SPLIT_POINT = 35
|
||||
|
||||
for entry in data:
|
||||
white_balls = entry['winning_numbers'][:5]
|
||||
low_count = sum(1 for num in white_balls if num <= SPLIT_POINT)
|
||||
high_count = 5 - low_count
|
||||
distribution[f"{low_count}low-{high_count}high"] += 1
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print(f"PATTERN: High/Low Distribution (Low: 1-{SPLIT_POINT}, High: {SPLIT_POINT+1}-69)")
|
||||
print("=" * 60)
|
||||
print("Distribution of low vs high numbers:")
|
||||
|
||||
total = sum(distribution.values())
|
||||
for pattern, count in sorted(distribution.items(), key=lambda x: x[1], reverse=True):
|
||||
percentage = (count / total) * 100
|
||||
print(f" {pattern}: {count} times ({percentage:.1f}%)")
|
||||
|
||||
return {'distribution': dict(distribution)}
|
||||
|
||||
|
||||
def detect_sum_patterns(data: List[Dict]) -> Dict:
|
||||
"""
|
||||
Analyze the sum of winning numbers.
|
||||
|
||||
Args:
|
||||
data: List of powerball data dictionaries
|
||||
|
||||
Returns:
|
||||
Dictionary with sum statistics
|
||||
"""
|
||||
sums = []
|
||||
|
||||
for entry in data:
|
||||
white_balls = entry['winning_numbers'][:5]
|
||||
total = sum(white_balls)
|
||||
sums.append(total)
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("PATTERN: Sum of Winning Numbers")
|
||||
print("=" * 60)
|
||||
|
||||
avg_sum = sum(sums) / len(sums) if sums else 0
|
||||
min_sum = min(sums) if sums else 0
|
||||
max_sum = max(sums) if sums else 0
|
||||
|
||||
print(f"Average sum: {avg_sum:.1f}")
|
||||
print(f"Range: {min_sum} - {max_sum}")
|
||||
|
||||
# Create buckets for sum ranges
|
||||
buckets = Counter()
|
||||
for s in sums:
|
||||
bucket = (s // 25) * 25 # Group into 25-number ranges
|
||||
buckets[f"{bucket}-{bucket+24}"] += 1
|
||||
|
||||
print("\nSum distribution by range:")
|
||||
for range_str, count in sorted(buckets.items(), key=lambda x: int(x[0].split('-')[0])):
|
||||
percentage = (count / len(sums)) * 100
|
||||
print(f" {range_str}: {count} times ({percentage:.1f}%)")
|
||||
|
||||
return {
|
||||
'average': avg_sum,
|
||||
'min': min_sum,
|
||||
'max': max_sum,
|
||||
'buckets': dict(buckets)
|
||||
}
|
||||
|
||||
|
||||
def detect_gap_patterns(data: List[Dict]) -> Dict:
|
||||
"""
|
||||
Analyze gaps (spacing) between consecutive numbers when sorted.
|
||||
|
||||
Args:
|
||||
data: List of powerball data dictionaries
|
||||
|
||||
Returns:
|
||||
Dictionary with gap statistics
|
||||
"""
|
||||
all_gaps = []
|
||||
|
||||
for entry in data:
|
||||
white_balls = sorted(entry['winning_numbers'][:5])
|
||||
gaps = [white_balls[i+1] - white_balls[i] for i in range(len(white_balls) - 1)]
|
||||
all_gaps.extend(gaps)
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("PATTERN: Gap Analysis (spacing between sorted numbers)")
|
||||
print("=" * 60)
|
||||
|
||||
avg_gap = sum(all_gaps) / len(all_gaps) if all_gaps else 0
|
||||
gap_counter = Counter(all_gaps)
|
||||
|
||||
print(f"Average gap: {avg_gap:.1f}")
|
||||
print("\nMost common gap sizes:")
|
||||
for gap, count in gap_counter.most_common(10):
|
||||
percentage = (count / len(all_gaps)) * 100
|
||||
print(f" Gap of {gap}: {count} times ({percentage:.1f}%)")
|
||||
|
||||
return {
|
||||
'average_gap': avg_gap,
|
||||
'gap_distribution': dict(gap_counter.most_common(15))
|
||||
}
|
||||
|
||||
|
||||
def detect_hot_cold_numbers(data: List[Dict], recent_draws: int = 20) -> Dict:
|
||||
"""
|
||||
Identify hot (frequently appearing) and cold (rarely appearing) numbers in recent draws.
|
||||
|
||||
Args:
|
||||
data: List of powerball data dictionaries
|
||||
recent_draws: Number of recent draws to analyze
|
||||
|
||||
Returns:
|
||||
Dictionary with hot/cold number analysis
|
||||
"""
|
||||
sorted_data = sorted(data, key=lambda x: x['draw_date'])
|
||||
recent = sorted_data[-recent_draws:] if len(sorted_data) >= recent_draws else sorted_data
|
||||
|
||||
white_counter = Counter()
|
||||
powerball_counter = Counter()
|
||||
|
||||
for entry in recent:
|
||||
for num in entry['winning_numbers'][:5]:
|
||||
white_counter[num] += 1
|
||||
if len(entry['winning_numbers']) >= 6:
|
||||
powerball_counter[entry['winning_numbers'][5]] += 1
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print(f"PATTERN: Hot & Cold Numbers (Last {len(recent)} draws)")
|
||||
print("=" * 60)
|
||||
|
||||
print(f"\nHottest white balls (appeared most in last {len(recent)} draws):")
|
||||
for num, count in white_counter.most_common(10):
|
||||
print(f" {num}: {count} times")
|
||||
|
||||
print(f"\nHottest Powerballs:")
|
||||
for num, count in powerball_counter.most_common(5):
|
||||
print(f" {num}: {count} times")
|
||||
|
||||
# Cold numbers - all possible white ball numbers (1-69) that appeared least
|
||||
all_white_numbers = set(range(1, 70))
|
||||
appeared = set(white_counter.keys())
|
||||
not_appeared = all_white_numbers - appeared
|
||||
|
||||
print(f"\nColdest white balls (appeared least or not at all):")
|
||||
cold_numbers = sorted(
|
||||
[(num, white_counter.get(num, 0)) for num in all_white_numbers],
|
||||
key=lambda x: (x[1], x[0])
|
||||
)[:10]
|
||||
|
||||
for num, count in cold_numbers:
|
||||
if count == 0:
|
||||
print(f" {num}: 0 times (not appeared)")
|
||||
else:
|
||||
print(f" {num}: {count} times")
|
||||
|
||||
return {
|
||||
'hot_white': dict(white_counter.most_common(10)),
|
||||
'hot_powerball': dict(powerball_counter.most_common(5)),
|
||||
'cold_white': dict(cold_numbers[:10])
|
||||
}
|
||||
|
||||
|
||||
def detect_overdue_numbers(data: List[Dict]) -> Dict:
|
||||
"""
|
||||
Identify numbers that haven't appeared in the longest time.
|
||||
|
||||
Args:
|
||||
data: List of powerball data dictionaries
|
||||
|
||||
Returns:
|
||||
Dictionary with overdue number analysis
|
||||
"""
|
||||
sorted_data = sorted(data, key=lambda x: x['draw_date'])
|
||||
|
||||
# Track last appearance of each number
|
||||
last_seen_white = {}
|
||||
last_seen_powerball = {}
|
||||
|
||||
for entry in sorted_data:
|
||||
draw_date = entry['draw_date']
|
||||
for num in entry['winning_numbers'][:5]:
|
||||
last_seen_white[num] = draw_date
|
||||
if len(entry['winning_numbers']) >= 6:
|
||||
last_seen_powerball[entry['winning_numbers'][5]] = draw_date
|
||||
|
||||
most_recent_draw = sorted_data[-1]['draw_date']
|
||||
|
||||
# Calculate days since last appearance
|
||||
overdue_white = {}
|
||||
for num in range(1, 70): # White balls are 1-69
|
||||
if num in last_seen_white:
|
||||
days_overdue = (most_recent_draw - last_seen_white[num]).days
|
||||
overdue_white[num] = days_overdue
|
||||
else:
|
||||
overdue_white[num] = float('inf') # Never appeared
|
||||
|
||||
overdue_powerball = {}
|
||||
for num in range(1, 27): # Powerballs are 1-26
|
||||
if num in last_seen_powerball:
|
||||
days_overdue = (most_recent_draw - last_seen_powerball[num]).days
|
||||
overdue_powerball[num] = days_overdue
|
||||
else:
|
||||
overdue_powerball[num] = float('inf')
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("PATTERN: Overdue Numbers (longest time since last appearance)")
|
||||
print("=" * 60)
|
||||
|
||||
print("\nMost overdue white balls:")
|
||||
sorted_overdue_white = sorted(overdue_white.items(), key=lambda x: x[1], reverse=True)[:10]
|
||||
for num, days in sorted_overdue_white:
|
||||
if days == float('inf'):
|
||||
print(f" {num}: Never appeared")
|
||||
else:
|
||||
print(f" {num}: {days} days ago")
|
||||
|
||||
print("\nMost overdue Powerballs:")
|
||||
sorted_overdue_powerball = sorted(overdue_powerball.items(), key=lambda x: x[1], reverse=True)[:5]
|
||||
for num, days in sorted_overdue_powerball:
|
||||
if days == float('inf'):
|
||||
print(f" {num}: Never appeared")
|
||||
else:
|
||||
print(f" {num}: {days} days ago")
|
||||
|
||||
return {
|
||||
'overdue_white': dict(sorted_overdue_white),
|
||||
'overdue_powerball': dict(sorted_overdue_powerball)
|
||||
}
|
||||
|
||||
|
||||
def detect_number_pairs(data: List[Dict], top_n: int = 10) -> Dict:
|
||||
"""
|
||||
Identify which number pairs appear together most frequently.
|
||||
|
||||
Args:
|
||||
data: List of powerball data dictionaries
|
||||
top_n: Number of top pairs to display
|
||||
|
||||
Returns:
|
||||
Dictionary with pair frequency analysis
|
||||
"""
|
||||
pair_counter = Counter()
|
||||
|
||||
for entry in data:
|
||||
white_balls = entry['winning_numbers'][:5]
|
||||
# Get all pairs from this draw
|
||||
for pair in combinations(sorted(white_balls), 2):
|
||||
pair_counter[pair] += 1
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("PATTERN: Number Pair Analysis")
|
||||
print("=" * 60)
|
||||
print(f"\nTop {top_n} most common number pairs:")
|
||||
|
||||
for (num1, num2), count in pair_counter.most_common(top_n):
|
||||
percentage = (count / len(data)) * 100
|
||||
print(f" ({num1}, {num2}): appeared together {count} times ({percentage:.1f}%)")
|
||||
|
||||
return {
|
||||
'top_pairs': dict(pair_counter.most_common(top_n))
|
||||
}
|
||||
|
||||
|
||||
def detect_decade_distribution(data: List[Dict]) -> Dict:
|
||||
"""
|
||||
Analyze how numbers are distributed across decades (1-9, 10-19, 20-29, etc.).
|
||||
|
||||
Args:
|
||||
data: List of powerball data dictionaries
|
||||
|
||||
Returns:
|
||||
Dictionary with decade distribution statistics
|
||||
"""
|
||||
decade_counts = Counter()
|
||||
|
||||
for entry in data:
|
||||
white_balls = entry['winning_numbers'][:5]
|
||||
for num in white_balls:
|
||||
decade = (num // 10) * 10
|
||||
decade_label = f"{decade:02d}-{decade+9:02d}" if decade < 60 else "60-69"
|
||||
decade_counts[decade_label] += 1
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("PATTERN: Decade Distribution")
|
||||
print("=" * 60)
|
||||
print("How often numbers from each range appear:")
|
||||
|
||||
total = sum(decade_counts.values())
|
||||
for decade in ["00-09", "10-19", "20-29", "30-39", "40-49", "50-59", "60-69"]:
|
||||
count = decade_counts.get(decade, 0)
|
||||
percentage = (count / total) * 100 if total > 0 else 0
|
||||
print(f" {decade}: {count} times ({percentage:.1f}%)")
|
||||
|
||||
return {'decade_distribution': dict(decade_counts)}
|
||||
|
||||
|
||||
def run_all_pattern_analyses(data: List[Dict]) -> Dict:
|
||||
"""
|
||||
Run all pattern detection analyses.
|
||||
|
||||
Args:
|
||||
data: List of powerball data dictionaries
|
||||
|
||||
Returns:
|
||||
Dictionary containing all pattern analysis results
|
||||
"""
|
||||
print("\n" + "#" * 60)
|
||||
print("# ADVANCED PATTERN DETECTION ANALYSIS")
|
||||
print("#" * 60)
|
||||
|
||||
results = {}
|
||||
|
||||
results['consecutive'] = detect_consecutive_patterns(data)
|
||||
results['odd_even'] = detect_odd_even_patterns(data)
|
||||
results['high_low'] = detect_high_low_patterns(data)
|
||||
results['sum'] = detect_sum_patterns(data)
|
||||
results['gaps'] = detect_gap_patterns(data)
|
||||
results['hot_cold'] = detect_hot_cold_numbers(data, recent_draws=20)
|
||||
results['overdue'] = detect_overdue_numbers(data)
|
||||
results['pairs'] = detect_number_pairs(data, top_n=15)
|
||||
results['decades'] = detect_decade_distribution(data)
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def generate_pattern_based_combinations(data: List[Dict], pattern_results: Dict, num_combinations: int = 5) -> List[Dict]:
|
||||
"""
|
||||
Generate number combinations based on pattern analysis.
|
||||
|
||||
Args:
|
||||
data: List of powerball data dictionaries
|
||||
pattern_results: Results from run_all_pattern_analyses
|
||||
num_combinations: Number of combinations to generate
|
||||
|
||||
Returns:
|
||||
List of dictionaries containing combination details
|
||||
"""
|
||||
import random
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("PATTERN-BASED NUMBER COMBINATIONS")
|
||||
print("=" * 60)
|
||||
print("\n*** DISCLAIMER: These combinations are based on pattern analysis.")
|
||||
print("Lottery draws are random. Past patterns do NOT predict future results.")
|
||||
print("Play responsibly.\n")
|
||||
|
||||
combinations = []
|
||||
|
||||
# Get pattern insights
|
||||
hot_white = list(pattern_results['hot_cold']['hot_white'].keys())[:15]
|
||||
cold_white = [num for num, _ in pattern_results['hot_cold']['cold_white'].items() if _ < 3][:10]
|
||||
overdue_white = [num for num, days in pattern_results['overdue']['overdue_white'].items() if days != float('inf')][:15]
|
||||
hot_powerball = list(pattern_results['hot_cold']['hot_powerball'].keys())[:3]
|
||||
overdue_powerball = [num for num, days in pattern_results['overdue']['overdue_powerball'].items() if days != float('inf')][:5]
|
||||
|
||||
# Get most common distributions
|
||||
odd_even_dist = pattern_results['odd_even']['distribution']
|
||||
most_common_oe = max(odd_even_dist.items(), key=lambda x: x[1])[0]
|
||||
target_odds = int(most_common_oe.split('odd')[0])
|
||||
|
||||
high_low_dist = pattern_results['high_low']['distribution']
|
||||
most_common_hl = max(high_low_dist.items(), key=lambda x: x[1])[0]
|
||||
target_lows = int(most_common_hl.split('low')[0])
|
||||
|
||||
# Get average sum
|
||||
avg_sum = pattern_results['sum']['average']
|
||||
sum_tolerance = 30
|
||||
|
||||
# Get top pairs
|
||||
top_pairs = list(pattern_results['pairs']['top_pairs'].keys())[:20]
|
||||
|
||||
# Strategy descriptions
|
||||
strategies = [
|
||||
("Hot Numbers Focus", hot_white, "Uses frequently drawn recent numbers"),
|
||||
("Balanced Hot + Overdue", hot_white[:8] + overdue_white[:12], "Mixes hot numbers with overdue picks"),
|
||||
("Overdue Numbers Focus", overdue_white, "Focuses on numbers that haven't appeared recently"),
|
||||
("Cold Numbers Gamble", cold_white + hot_white[:10], "Includes rarely drawn numbers"),
|
||||
("Pair-Based Selection", [n for pair in top_pairs for n in pair], "Uses numbers from common pairs")
|
||||
]
|
||||
|
||||
for strategy_idx in range(min(num_combinations, len(strategies))):
|
||||
strategy_name, number_pool, strategy_desc = strategies[strategy_idx]
|
||||
|
||||
# Ensure we have enough numbers in pool
|
||||
if len(number_pool) < 20:
|
||||
number_pool = list(set(number_pool + hot_white + list(range(1, 70))))
|
||||
|
||||
# Try to generate a combination that fits the patterns
|
||||
attempts = 0
|
||||
max_attempts = 1000
|
||||
selected = [] # Initialize to avoid unbound variable
|
||||
|
||||
while attempts < max_attempts:
|
||||
# Select 5 random numbers from pool
|
||||
selected = random.sample(number_pool[:30], min(5, len(number_pool[:30])))
|
||||
selected = sorted(selected)
|
||||
|
||||
# Check odd/even distribution
|
||||
odds_count = sum(1 for n in selected if n % 2 == 1)
|
||||
if abs(odds_count - target_odds) > 1:
|
||||
attempts += 1
|
||||
continue
|
||||
|
||||
# Check high/low distribution
|
||||
lows_count = sum(1 for n in selected if n <= 35)
|
||||
if abs(lows_count - target_lows) > 1:
|
||||
attempts += 1
|
||||
continue
|
||||
|
||||
# Check sum is reasonable
|
||||
total = sum(selected)
|
||||
if abs(total - avg_sum) > sum_tolerance:
|
||||
attempts += 1
|
||||
continue
|
||||
|
||||
# Check gaps are reasonable (not too clustered or too spread)
|
||||
gaps = [selected[i+1] - selected[i] for i in range(4)]
|
||||
if min(gaps) < 2 or max(gaps) > 25:
|
||||
attempts += 1
|
||||
continue
|
||||
|
||||
# Good combination found
|
||||
break
|
||||
|
||||
# If we didn't find a perfect match, selected still has the last attempt
|
||||
if not selected:
|
||||
selected = sorted(random.sample(range(1, 70), 5))
|
||||
|
||||
# Select powerball
|
||||
if strategy_idx % 2 == 0 and hot_powerball:
|
||||
powerball = random.choice(hot_powerball)
|
||||
elif overdue_powerball:
|
||||
powerball = random.choice(overdue_powerball[:5])
|
||||
else:
|
||||
powerball = random.randint(1, 26)
|
||||
|
||||
# Calculate combination stats
|
||||
odds = sum(1 for n in selected if n % 2 == 1)
|
||||
evens = 5 - odds
|
||||
lows = sum(1 for n in selected if n <= 35)
|
||||
highs = 5 - lows
|
||||
total = sum(selected)
|
||||
|
||||
combinations.append({
|
||||
'strategy': strategy_name,
|
||||
'description': strategy_desc,
|
||||
'numbers': selected,
|
||||
'powerball': powerball,
|
||||
'odds': odds,
|
||||
'evens': evens,
|
||||
'lows': lows,
|
||||
'highs': highs,
|
||||
'sum': total,
|
||||
'attempts': attempts
|
||||
})
|
||||
|
||||
# Display combinations
|
||||
for i, combo in enumerate(combinations, 1):
|
||||
print(f"\nCombination #{i}: {combo['strategy']}")
|
||||
print(f" Strategy: {combo['description']}")
|
||||
print(f" Numbers: {' '.join(map(str, combo['numbers']))} + Powerball: {combo['powerball']}")
|
||||
print(f" Stats: {combo['odds']}odd-{combo['evens']}even, {combo['lows']}low-{combo['highs']}high, Sum: {combo['sum']}")
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("Quick Pick Lines:")
|
||||
print("=" * 60)
|
||||
for i, combo in enumerate(combinations, 1):
|
||||
numbers_str = ' - '.join(f"{n:2d}" for n in combo['numbers'])
|
||||
print(f" Line {i}: {numbers_str} | PB: {combo['powerball']:2d}")
|
||||
|
||||
return combinations
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function."""
|
||||
# Default to 'powerball_numbers.csv' in the same directory as the script
|
||||
@@ -368,6 +932,12 @@ def main():
|
||||
display_powerball_data(powerball_data)
|
||||
stats = analyze_most_frequent_numbers(powerball_data)
|
||||
generate_suggested_combination(stats)
|
||||
|
||||
# Run advanced pattern detection
|
||||
pattern_results = run_all_pattern_analyses(powerball_data)
|
||||
|
||||
# Generate pattern-based combinations
|
||||
pattern_combos = generate_pattern_based_combinations(powerball_data, pattern_results, num_combinations=5)
|
||||
else:
|
||||
print("Failed to load powerball data.")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user