Files
wjones 41942eb9c9 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.
2026-06-24 14:35:29 -04:00

947 lines
34 KiB
Python

#!/usr/bin/env python3
"""
Script to read and parse Powerball numbers from a CSV file with advanced pattern detection.
"""
import csv
from datetime import datetime, timedelta
from pathlib import Path
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]:
"""
Read a CSV file containing Powerball numbers.
Expected CSV format:
Draw Date,Winning Numbers,Multiplier
09/26/2020,11 21 27 36 62 24,3
Args:
filepath: Path to the CSV file
Returns:
List of dictionaries containing parsed powerball data
"""
powerball_data = []
try:
with open(filepath, 'r', encoding='utf-8') as csvfile:
reader = csv.DictReader(csvfile)
for row_num, row in enumerate(reader, start=2): # start=2 because row 1 is header
try:
# Skip empty rows
if not any(row.values()):
continue
# Parse the row
draw_date = datetime.strptime(row['Draw Date'].strip(), '%m/%d/%Y')
# Parse winning numbers - filter out empty strings
numbers_str = row['Winning Numbers'].strip()
winning_numbers = [int(n) for n in numbers_str.split() if n.strip()]
multiplier = int(row['Multiplier'].strip())
powerball_data.append({
'draw_date': draw_date,
'date_str': draw_date.strftime('%Y-%m-%d'),
'winning_numbers': winning_numbers,
'multiplier': multiplier
})
except ValueError as e:
print(f"Warning: Skipping row {row_num} due to error: {e}")
print(f" Row data: {row}")
continue
except FileNotFoundError:
print(f"Error: File '{filepath}' not found.")
return []
except Exception as e:
print(f"Error: Failed to read CSV file - {e}")
return []
return powerball_data
def display_powerball_data(data: List[Dict]) -> None:
"""
Display powerball data in a formatted table.
Args:
data: List of powerball data dictionaries
"""
if not data:
print("No data to display.")
return
print(f"{'Draw Date':<12} {'Winning Numbers':<30} {'Multiplier':<10}")
print("-" * 52)
for entry in data:
numbers_str = ' '.join(map(str, entry['winning_numbers']))
print(f"{entry['date_str']:<12} {numbers_str:<30} {entry['multiplier']:<10}")
def _get_unweighted_top_numbers(draws: List[Dict]) -> Tuple[List[int], Optional[int]]:
"""Return top 5 white balls and top Powerball from a draw list."""
if not draws:
return [], None
white_counter = Counter()
powerball_counter = Counter()
for entry in draws:
numbers = entry['winning_numbers']
for number in numbers[:5]:
white_counter[number] += 1
if len(numbers) >= 6:
powerball_counter[numbers[5]] += 1
top_white = [number for number, _ in white_counter.most_common(5)]
top_powerball = powerball_counter.most_common(1)[0][0] if powerball_counter else None
return top_white, top_powerball
def _get_recency_weighted_top_numbers(draws: List[Dict]) -> Tuple[List[int], Optional[int]]:
"""Return top numbers weighted so newer draws contribute more."""
if not draws:
return [], None
sorted_draws = sorted(draws, key=lambda x: x['draw_date'])
total_draws = len(sorted_draws)
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
numbers = entry['winning_numbers']
for number in numbers[:5]:
white_scores[number] += weight
if len(numbers) >= 6:
powerball_scores[numbers[5]] += weight
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
def _get_aggressive_recency_weighted_top_numbers(draws: List[Dict]) -> Tuple[List[int], Optional[int]]:
"""Return top numbers with an aggressive recency curve (cubic weighting)."""
if not draws:
return [], None
sorted_draws = sorted(draws, key=lambda x: x['draw_date'])
total_draws = len(sorted_draws)
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
weight = normalized_position ** 3
numbers = entry['winning_numbers']
for number in numbers[:5]:
white_scores[number] += weight
if len(numbers) >= 6:
powerball_scores[numbers[5]] += weight
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
def analyze_most_frequent_numbers(data: List[Dict]) -> Dict:
"""
Analyze and display the most frequent number in each slot position.
Args:
data: List of powerball data dictionaries
"""
if not data:
print("No data to analyze.")
return {}
# Initialize lists to hold numbers for each position
num_positions = len(data[0]['winning_numbers'])
position_numbers = [[] for _ in range(num_positions)]
# Collect all numbers for each position
for entry in data:
for position, number in enumerate(entry['winning_numbers']):
position_numbers[position].append(number)
# Find most common number in each position
print("\n" + "=" * 60)
print("Most Frequent Numbers by Slot Position")
print("=" * 60)
most_frequent = []
for position, numbers in enumerate(position_numbers, start=1):
counter = Counter(numbers)
most_common_num, frequency = counter.most_common(1)[0]
most_frequent.append(most_common_num)
percentage = (frequency / len(numbers)) * 100
print(f"Position {position}: {most_common_num:<3} (appears {frequency} times, {percentage:.1f}%)")
print("-" * 60)
print(f"Most frequent numbers combined: {' '.join(map(str, most_frequent))}")
# Analyze most frequent number across first 5 positions combined
print("\n" + "=" * 60)
print("Additional Analysis")
print("=" * 60)
# Combine all numbers from positions 1-5
first_five_combined = []
for i in range(min(5, num_positions)):
first_five_combined.extend(position_numbers[i])
top_five_numbers = []
top_ten_numbers = []
if first_five_combined:
counter_first_five = Counter(first_five_combined)
top_five_numbers = counter_first_five.most_common(5)
top_ten_numbers = counter_first_five.most_common(10)
print("Top 5 most drawn numbers in first 5 positions combined:")
for rank, (number, frequency) in enumerate(top_five_numbers, start=1):
percentage = (frequency / len(first_five_combined)) * 100
print(f" {rank}. {number:<3} (appears {frequency} times, {percentage:.1f}%)")
# Analyze the sixth position (Powerball)
powerball_ranked = []
most_common_sixth = None
if num_positions >= 6:
sixth_position_numbers = position_numbers[5]
counter_sixth = Counter(sixth_position_numbers)
powerball_ranked = counter_sixth.most_common(5)
most_common_sixth, freq_sixth = counter_sixth.most_common(1)[0]
percentage_sixth = (freq_sixth / len(sixth_position_numbers)) * 100
print(f"\nMost drawn number in position 6 (Powerball): {most_common_sixth} (appears {freq_sixth} times, {percentage_sixth:.1f}%)")
# Third strategy: most frequent numbers from the most recent 104 draws
sorted_by_date = sorted(data, key=lambda x: x['draw_date'])
recent_104_draws = sorted_by_date[-104:]
recent_104_top_five, recent_104_powerball = _get_unweighted_top_numbers(recent_104_draws)
# Fourth strategy: weighted-by-recency across all draws
weighted_top_five, weighted_powerball = _get_recency_weighted_top_numbers(data)
# Fifth strategy: aggressive weighted-by-recency across all draws
aggressive_weighted_top_five, aggressive_weighted_powerball = _get_aggressive_recency_weighted_top_numbers(data)
# Return statistics for prediction
return {
'top_five_combined': [num for num, freq in top_five_numbers] if first_five_combined else [],
'top_ten_combined': [num for num, freq in top_ten_numbers],
'most_common_powerball': most_common_sixth,
'powerball_ranked': [num for num, freq in powerball_ranked],
'recent_104_top_five': recent_104_top_five,
'recent_104_powerball': recent_104_powerball,
'weighted_top_five': weighted_top_five,
'weighted_powerball': weighted_powerball,
'aggressive_weighted_top_five': aggressive_weighted_top_five,
'aggressive_weighted_powerball': aggressive_weighted_powerball
}
def generate_suggested_combination(stats: dict) -> None:
"""
Generate a suggested combination based on statistical analysis.
Args:
stats: Dictionary containing statistical analysis results
"""
print("\n" + "=" * 60)
print("Suggested Combination Based on Statistical Analysis")
print("=" * 60)
print("\n*** DISCLAIMER: This is purely statistical analysis.")
print("Past results do NOT predict future outcomes.")
print("Each draw is random and independent.\n")
top_five = stats['top_five_combined']
top_ten = stats.get('top_ten_combined', [])
powerball = stats['most_common_powerball']
ranked_powerballs = stats.get('powerball_ranked', [])
recent_104_top_five = stats.get('recent_104_top_five', [])
recent_104_powerball = stats.get('recent_104_powerball')
weighted_top_five = stats.get('weighted_top_five', [])
weighted_powerball = stats.get('weighted_powerball')
aggressive_weighted_top_five = stats.get('aggressive_weighted_top_five', [])
aggressive_weighted_powerball = stats.get('aggressive_weighted_powerball')
if len(top_five) >= 5 and powerball:
# Use the top 5 most frequent numbers from positions 1-5
primary_numbers = sorted(top_five[:5])
primary_powerball = powerball
# Build a secondary set from the next-most-frequent historical numbers.
secondary_pool = top_ten[5:10]
if len(secondary_pool) < 5:
secondary_pool = top_ten[:5]
secondary_numbers = sorted(secondary_pool[:5])
secondary_powerball = ranked_powerballs[1] if len(ranked_powerballs) > 1 else primary_powerball
third_numbers = sorted(recent_104_top_five[:5]) if len(recent_104_top_five) >= 5 else []
third_powerball = recent_104_powerball
fourth_numbers = sorted(weighted_top_five[:5]) if len(weighted_top_five) >= 5 else []
fourth_powerball = weighted_powerball
fifth_numbers = sorted(aggressive_weighted_top_five[:5]) if len(aggressive_weighted_top_five) >= 5 else []
fifth_powerball = aggressive_weighted_powerball
print("Primary set (most frequent):")
print(f" White balls: {' '.join(map(str, primary_numbers))}")
print(f" Powerball: {primary_powerball}")
print("\nSecondary set (next-most frequent):")
print(f" White balls: {' '.join(map(str, secondary_numbers))}")
print(f" Powerball: {secondary_powerball}")
if third_numbers and third_powerball:
print("\nThird set (most frequent in recent 104 draws):")
print(f" White balls: {' '.join(map(str, third_numbers))}")
print(f" Powerball: {third_powerball}")
if fourth_numbers and fourth_powerball:
print("\nFourth set (weighted by recency):")
print(f" White balls: {' '.join(map(str, fourth_numbers))}")
print(f" Powerball: {fourth_powerball}")
if fifth_numbers and fifth_powerball:
print("\nFifth set (aggressive recency weighting):")
print(f" White balls: {' '.join(map(str, fifth_numbers))}")
print(f" Powerball: {fifth_powerball}")
print()
print(f"Primary combination: {' '.join(map(str, primary_numbers))} + {primary_powerball}")
print(f"Secondary combination: {' '.join(map(str, secondary_numbers))} + {secondary_powerball}")
if third_numbers and third_powerball:
print(f"Third combination: {' '.join(map(str, third_numbers))} + {third_powerball}")
if fourth_numbers and fourth_powerball:
print(f"Fourth combination: {' '.join(map(str, fourth_numbers))} + {fourth_powerball}")
if fifth_numbers and fifth_powerball:
print(f"Fifth combination: {' '.join(map(str, fifth_numbers))} + {fifth_powerball}")
print()
print("These combinations are based on:")
print(" • The 5 most frequently drawn numbers across all white ball positions")
print(f" • The most frequently drawn Powerball number ({primary_powerball})")
print(" • A secondary set from the next-most-frequent white ball and Powerball values")
print(" • Recent-window frequency (last 104 draws)")
print(" • Recency-weighted scoring where newer draws count more")
print(" • Aggressive recency weighting using a cubic curve")
else:
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
script_dir = Path(__file__).parent
csv_file = script_dir / 'powerball_numbers.csv'
# You can also specify a different file path here
# csv_file = Path('path/to/your/file.csv')
print(f"Reading Powerball numbers from: {csv_file}\n")
powerball_data = read_powerball_csv(str(csv_file))
if powerball_data:
print(f"Successfully loaded {len(powerball_data)} records.\n")
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.")
if __name__ == '__main__':
main()