1.3.1: Removed unused scripts.

This commit is contained in:
2026-01-27 03:11:17 +08:00
parent a148c2d511
commit 28dc02c0c4
25 changed files with 107 additions and 1697 deletions

View File

@@ -1 +0,0 @@
用于测试脚本目录。

View File

@@ -1,214 +0,0 @@
import sqlite3
import pandas as pd
import numpy as np
import os
DB_L2_PATH = r'd:\Documents\trae_projects\yrtv\database\L2\L2_Main.sqlite'
def get_db_connection():
conn = sqlite3.connect(DB_L2_PATH)
conn.row_factory = sqlite3.Row
return conn
def load_data_and_calculate(conn, min_matches=5):
print("Loading Basic Stats...")
# 1. Basic Stats
query_basic = """
SELECT
steam_id_64,
COUNT(*) as matches_played,
AVG(rating) as avg_rating,
AVG(kd_ratio) as avg_kd,
AVG(adr) as avg_adr,
AVG(kast) as avg_kast,
SUM(first_kill) as total_fk,
SUM(first_death) as total_fd,
SUM(clutch_1v1) + SUM(clutch_1v2) + SUM(clutch_1v3) + SUM(clutch_1v4) + SUM(clutch_1v5) as total_clutches,
SUM(throw_harm) as total_util_dmg,
SUM(flash_time) as total_flash_time,
SUM(flash_enemy) as total_flash_enemy
FROM fact_match_players
GROUP BY steam_id_64
HAVING COUNT(*) >= ?
"""
df_basic = pd.read_sql_query(query_basic, conn, params=(min_matches,))
valid_ids = tuple(df_basic['steam_id_64'].tolist())
if not valid_ids:
print("No players found.")
return None
placeholders = ','.join(['?'] * len(valid_ids))
# 2. Side Stats (T/CT) via Economy Table (which has side info)
print("Loading Side Stats via Round Map...")
# Map each round+player to a side
query_side_map = f"""
SELECT match_id, round_num, steam_id_64, side
FROM fact_round_player_economy
WHERE steam_id_64 IN ({placeholders})
"""
try:
df_sides = pd.read_sql_query(query_side_map, conn, params=valid_ids)
# Get all Kills
query_kills = f"""
SELECT match_id, round_num, attacker_steam_id as steam_id_64, COUNT(*) as kills
FROM fact_round_events
WHERE event_type = 'kill'
AND attacker_steam_id IN ({placeholders})
GROUP BY match_id, round_num, attacker_steam_id
"""
df_kills = pd.read_sql_query(query_kills, conn, params=valid_ids)
# Merge to get Kills per Side
df_merged = df_kills.merge(df_sides, on=['match_id', 'round_num', 'steam_id_64'], how='inner')
# Aggregate
side_stats = df_merged.groupby(['steam_id_64', 'side'])['kills'].sum().unstack(fill_value=0)
side_stats.columns = [f'kills_{c.lower()}' for c in side_stats.columns]
# Also need deaths to calc KD (approx)
# Assuming deaths are in events as victim
query_deaths = f"""
SELECT match_id, round_num, victim_steam_id as steam_id_64, COUNT(*) as deaths
FROM fact_round_events
WHERE event_type = 'kill'
AND victim_steam_id IN ({placeholders})
GROUP BY match_id, round_num, victim_steam_id
"""
df_deaths = pd.read_sql_query(query_deaths, conn, params=valid_ids)
df_merged_d = df_deaths.merge(df_sides, on=['match_id', 'round_num', 'steam_id_64'], how='inner')
side_stats_d = df_merged_d.groupby(['steam_id_64', 'side'])['deaths'].sum().unstack(fill_value=0)
side_stats_d.columns = [f'deaths_{c.lower()}' for c in side_stats_d.columns]
# Combine
df_side_final = side_stats.join(side_stats_d).fillna(0)
df_side_final['ct_kd'] = df_side_final.get('kills_ct', 0) / df_side_final.get('deaths_ct', 1).replace(0, 1)
df_side_final['t_kd'] = df_side_final.get('kills_t', 0) / df_side_final.get('deaths_t', 1).replace(0, 1)
except Exception as e:
print(f"Side stats failed: {e}")
df_side_final = pd.DataFrame({'steam_id_64': list(valid_ids)})
# 3. PTL (Pistol) via Rounds 1 and 13
print("Loading Pistol Stats via Rounds...")
query_pistol_kills = f"""
SELECT
ev.attacker_steam_id as steam_id_64,
COUNT(*) as pistol_kills
FROM fact_round_events ev
WHERE ev.attacker_steam_id IN ({placeholders})
AND ev.event_type = 'kill'
AND ev.round_num IN (1, 13)
GROUP BY ev.attacker_steam_id
"""
df_ptl = pd.read_sql_query(query_pistol_kills, conn, params=valid_ids)
# 4. HPS
print("Loading HPS Stats...")
query_close = f"""
SELECT mp.steam_id_64, AVG(mp.rating) as close_match_rating
FROM fact_match_players mp
JOIN fact_matches m ON mp.match_id = m.match_id
WHERE mp.steam_id_64 IN ({placeholders})
AND ABS(m.score_team1 - m.score_team2) <= 3
GROUP BY mp.steam_id_64
"""
df_hps = pd.read_sql_query(query_close, conn, params=valid_ids)
# 5. STA
query_sta = f"""
SELECT mp.steam_id_64, mp.rating, mp.is_win
FROM fact_match_players mp
WHERE mp.steam_id_64 IN ({placeholders})
"""
df_matches = pd.read_sql_query(query_sta, conn, params=valid_ids)
sta_data = []
for pid, group in df_matches.groupby('steam_id_64'):
rating_std = group['rating'].std()
win_rating = group[group['is_win']==1]['rating'].mean()
loss_rating = group[group['is_win']==0]['rating'].mean()
sta_data.append({'steam_id_64': pid, 'rating_std': rating_std, 'win_rating': win_rating, 'loss_rating': loss_rating})
df_sta = pd.DataFrame(sta_data)
# --- Merge All ---
df = df_basic.merge(df_side_final, on='steam_id_64', how='left')
df = df.merge(df_hps, on='steam_id_64', how='left')
df = df.merge(df_ptl, on='steam_id_64', how='left').fillna(0)
df = df.merge(df_sta, on='steam_id_64', how='left')
return df
def normalize_series(series):
min_v = series.min()
max_v = series.max()
if pd.isna(min_v) or pd.isna(max_v) or min_v == max_v:
return pd.Series([50]*len(series), index=series.index)
return (series - min_v) / (max_v - min_v) * 100
def calculate_scores(df):
df = df.copy()
# BAT
df['n_rating'] = normalize_series(df['avg_rating'])
df['n_kd'] = normalize_series(df['avg_kd'])
df['n_adr'] = normalize_series(df['avg_adr'])
df['n_kast'] = normalize_series(df['avg_kast'])
df['score_BAT'] = 0.4*df['n_rating'] + 0.3*df['n_kd'] + 0.2*df['n_adr'] + 0.1*df['n_kast']
# STA
df['n_std'] = normalize_series(df['rating_std'].fillna(0))
df['n_win_r'] = normalize_series(df['win_rating'].fillna(0))
df['n_loss_r'] = normalize_series(df['loss_rating'].fillna(0))
df['score_STA'] = 0.5*(100 - df['n_std']) + 0.25*df['n_win_r'] + 0.25*df['n_loss_r']
# UTIL
df['n_util_dmg'] = normalize_series(df['total_util_dmg'] / df['matches_played'])
df['n_flash'] = normalize_series(df['total_flash_time'] / df['matches_played'])
df['score_UTIL'] = 0.6*df['n_util_dmg'] + 0.4*df['n_flash']
# T/CT (Calculated from Event Logs)
df['n_ct_kd'] = normalize_series(df['ct_kd'].fillna(0))
df['n_t_kd'] = normalize_series(df['t_kd'].fillna(0))
df['score_TCT'] = 0.5*df['n_ct_kd'] + 0.5*df['n_t_kd']
# HPS
df['n_clutch'] = normalize_series(df['total_clutches'] / df['matches_played'])
df['n_close_r'] = normalize_series(df['close_match_rating'].fillna(0))
df['score_HPS'] = 0.5*df['n_clutch'] + 0.5*df['n_close_r']
# PTL
df['n_pistol'] = normalize_series(df['pistol_kills'] / df['matches_played'])
df['score_PTL'] = df['n_pistol']
return df
def main():
conn = get_db_connection()
try:
df = load_data_and_calculate(conn)
if df is None: return
# Debug: Print raw stats for checking T/CT issue
print("\n--- Raw T/CT Stats Sample ---")
if 'ct_kd' in df.columns:
print(df[['steam_id_64', 'ct_kd', 't_kd']].head())
else:
print("CT/KD columns missing")
results = calculate_scores(df)
print("\n--- Final Dimension Scores (Top 5 by BAT) ---")
cols = ['steam_id_64', 'score_BAT', 'score_STA', 'score_UTIL', 'score_TCT', 'score_HPS', 'score_PTL']
print(results[cols].sort_values('score_BAT', ascending=False).head(5))
except Exception as e:
print(f"Error: {e}")
import traceback
traceback.print_exc()
finally:
conn.close()
if __name__ == "__main__":
main()

View File

@@ -1,304 +0,0 @@
import sqlite3
import pandas as pd
import numpy as np
import os
DB_L2_PATH = r'd:\Documents\trae_projects\yrtv\database\L2\L2_Main.sqlite'
def get_db_connection():
conn = sqlite3.connect(DB_L2_PATH)
conn.row_factory = sqlite3.Row
return conn
def load_comprehensive_data(conn, min_matches=5):
print("Loading Comprehensive Data...")
# 1. Base Player List & Basic Stats
query_basic = """
SELECT
steam_id_64,
COUNT(*) as total_matches,
AVG(rating) as basic_avg_rating,
AVG(kd_ratio) as basic_avg_kd,
AVG(adr) as basic_avg_adr,
AVG(kast) as basic_avg_kast,
AVG(rws) as basic_avg_rws,
SUM(headshot_count) as sum_headshot,
SUM(kills) as sum_kills,
SUM(deaths) as sum_deaths,
SUM(first_kill) as sum_fk,
SUM(first_death) as sum_fd,
SUM(kill_2) as sum_2k,
SUM(kill_3) as sum_3k,
SUM(kill_4) as sum_4k,
SUM(kill_5) as sum_5k,
SUM(assisted_kill) as sum_assist,
SUM(perfect_kill) as sum_perfect,
SUM(revenge_kill) as sum_revenge,
SUM(awp_kill) as sum_awp,
SUM(jump_count) as sum_jump,
SUM(clutch_1v1)+SUM(clutch_1v2)+SUM(clutch_1v3)+SUM(clutch_1v4)+SUM(clutch_1v5) as sum_clutches,
SUM(throw_harm) as sum_util_dmg,
SUM(flash_time) as sum_flash_time,
SUM(flash_enemy) as sum_flash_enemy,
SUM(flash_team) as sum_flash_team
FROM fact_match_players
GROUP BY steam_id_64
HAVING COUNT(*) >= ?
"""
df = pd.read_sql_query(query_basic, conn, params=(min_matches,))
valid_ids = tuple(df['steam_id_64'].tolist())
if not valid_ids:
print("No players found.")
return None
placeholders = ','.join(['?'] * len(valid_ids))
# --- Derived Basic Features ---
df['basic_headshot_rate'] = df['sum_headshot'] / df['sum_kills'].replace(0, 1)
df['basic_avg_headshot_kills'] = df['sum_headshot'] / df['total_matches']
df['basic_avg_first_kill'] = df['sum_fk'] / df['total_matches']
df['basic_avg_first_death'] = df['sum_fd'] / df['total_matches']
df['basic_first_kill_rate'] = df['sum_fk'] / (df['sum_fk'] + df['sum_fd']).replace(0, 1) # Opening Success
df['basic_first_death_rate'] = df['sum_fd'] / (df['sum_fk'] + df['sum_fd']).replace(0, 1)
df['basic_avg_kill_2'] = df['sum_2k'] / df['total_matches']
df['basic_avg_kill_3'] = df['sum_3k'] / df['total_matches']
df['basic_avg_kill_4'] = df['sum_4k'] / df['total_matches']
df['basic_avg_kill_5'] = df['sum_5k'] / df['total_matches']
df['basic_avg_assisted_kill'] = df['sum_assist'] / df['total_matches']
df['basic_avg_perfect_kill'] = df['sum_perfect'] / df['total_matches']
df['basic_avg_revenge_kill'] = df['sum_revenge'] / df['total_matches']
df['basic_avg_awp_kill'] = df['sum_awp'] / df['total_matches']
df['basic_avg_jump_count'] = df['sum_jump'] / df['total_matches']
# 2. STA (Stability) - Detailed
print("Calculating STA...")
query_sta = f"""
SELECT mp.steam_id_64, mp.rating, mp.is_win, m.start_time
FROM fact_match_players mp
JOIN fact_matches m ON mp.match_id = m.match_id
WHERE mp.steam_id_64 IN ({placeholders})
ORDER BY mp.steam_id_64, m.start_time
"""
df_matches = pd.read_sql_query(query_sta, conn, params=valid_ids)
sta_list = []
for pid, group in df_matches.groupby('steam_id_64'):
# Last 30
last_30 = group.tail(30)
sta_last_30 = last_30['rating'].mean()
# Win/Loss
sta_win = group[group['is_win']==1]['rating'].mean()
sta_loss = group[group['is_win']==0]['rating'].mean()
# Volatility (Last 10)
sta_vol = group.tail(10)['rating'].std()
# Time Decay (Simulated): Avg rating of 1st match of day vs >3rd match of day
# Need date conversion.
group['date'] = pd.to_datetime(group['start_time'], unit='s').dt.date
daily_counts = group.groupby('date').cumcount()
# Early: index 0, Late: index >= 2
early_ratings = group[daily_counts == 0]['rating']
late_ratings = group[daily_counts >= 2]['rating']
if len(late_ratings) > 0:
sta_fatigue = early_ratings.mean() - late_ratings.mean() # Positive means fatigue (drop)
else:
sta_fatigue = 0
sta_list.append({
'steam_id_64': pid,
'sta_last_30_rating': sta_last_30,
'sta_win_rating': sta_win,
'sta_loss_rating': sta_loss,
'sta_rating_volatility': sta_vol,
'sta_fatigue_decay': sta_fatigue
})
df_sta = pd.DataFrame(sta_list)
df = df.merge(df_sta, on='steam_id_64', how='left')
# 3. BAT (Battle) - Detailed
print("Calculating BAT...")
# Need Match ELO
query_bat = f"""
SELECT mp.steam_id_64, mp.kd_ratio, mp.entry_kills, mp.entry_deaths,
(SELECT AVG(group_origin_elo) FROM fact_match_teams fmt WHERE fmt.match_id = mp.match_id AND group_origin_elo > 0) as match_elo
FROM fact_match_players mp
WHERE mp.steam_id_64 IN ({placeholders})
"""
df_bat_raw = pd.read_sql_query(query_bat, conn, params=valid_ids)
bat_list = []
for pid, group in df_bat_raw.groupby('steam_id_64'):
avg_elo = group['match_elo'].mean()
if pd.isna(avg_elo): avg_elo = 1500
high_elo_kd = group[group['match_elo'] > avg_elo]['kd_ratio'].mean()
low_elo_kd = group[group['match_elo'] <= avg_elo]['kd_ratio'].mean()
sum_entry_k = group['entry_kills'].sum()
sum_entry_d = group['entry_deaths'].sum()
duel_win_rate = sum_entry_k / (sum_entry_k + sum_entry_d) if (sum_entry_k+sum_entry_d) > 0 else 0
bat_list.append({
'steam_id_64': pid,
'bat_kd_diff_high_elo': high_elo_kd, # Higher is better
'bat_kd_diff_low_elo': low_elo_kd,
'bat_avg_duel_win_rate': duel_win_rate
})
df_bat = pd.DataFrame(bat_list)
df = df.merge(df_bat, on='steam_id_64', how='left')
# 4. HPS (Pressure) - Detailed
print("Calculating HPS...")
# Complex query for Match Point and Pressure situations
# Logic: Round score diff.
# Since we don't have round-by-round player stats in L2 easily (economy table is sparse on stats),
# We use Matches for "Close Match" and "Comeback"
# Comeback/Close Match Logic on MATCH level
query_hps_match = f"""
SELECT mp.steam_id_64, mp.kd_ratio, mp.rating, m.score_team1, m.score_team2, mp.team_id, m.winner_team
FROM fact_match_players mp
JOIN fact_matches m ON mp.match_id = m.match_id
WHERE mp.steam_id_64 IN ({placeholders})
"""
df_hps_raw = pd.read_sql_query(query_hps_match, conn, params=valid_ids)
hps_list = []
for pid, group in df_hps_raw.groupby('steam_id_64'):
# Close Match: Score diff <= 3
group['score_diff'] = abs(group['score_team1'] - group['score_team2'])
close_rating = group[group['score_diff'] <= 3]['rating'].mean()
# Comeback: Won match where score was close?
# Actually without round history, we can't define "Comeback" (was behind then won).
# We can define "Underdog Win": Won when ELO was lower? Or just Close Win.
# Let's use Close Match Rating as primary HPS metric from matches.
hps_list.append({
'steam_id_64': pid,
'hps_close_match_rating': close_rating
})
df_hps = pd.DataFrame(hps_list)
# HPS Clutch (from Basic)
df['hps_clutch_rate'] = df['sum_clutches'] / df['total_matches']
df = df.merge(df_hps, on='steam_id_64', how='left')
# 5. PTL (Pistol)
print("Calculating PTL...")
# R1/R13 Kills
query_ptl = f"""
SELECT ev.attacker_steam_id as steam_id_64, COUNT(*) as pistol_kills
FROM fact_round_events ev
WHERE ev.event_type = 'kill' AND ev.round_num IN (1, 13)
AND ev.attacker_steam_id IN ({placeholders})
GROUP BY ev.attacker_steam_id
"""
df_ptl = pd.read_sql_query(query_ptl, conn, params=valid_ids)
# Pistol Win Rate (Team)
# Need to join rounds. Too slow?
# Simplify: Just use Pistol Kills per Match (normalized)
df = df.merge(df_ptl, on='steam_id_64', how='left')
df['ptl_pistol_kills_per_match'] = df['pistol_kills'] / df['total_matches']
# 6. T/CT
print("Calculating T/CT...")
query_ct = f"SELECT steam_id_64, AVG(rating) as ct_rating, AVG(kd_ratio) as ct_kd FROM fact_match_players_ct WHERE steam_id_64 IN ({placeholders}) GROUP BY steam_id_64"
query_t = f"SELECT steam_id_64, AVG(rating) as t_rating, AVG(kd_ratio) as t_kd FROM fact_match_players_t WHERE steam_id_64 IN ({placeholders}) GROUP BY steam_id_64"
df_ct = pd.read_sql_query(query_ct, conn, params=valid_ids)
df_t = pd.read_sql_query(query_t, conn, params=valid_ids)
df = df.merge(df_ct, on='steam_id_64', how='left').merge(df_t, on='steam_id_64', how='left')
# 7. UTIL
print("Calculating UTIL...")
df['util_avg_dmg'] = df['sum_util_dmg'] / df['total_matches']
df['util_avg_flash_time'] = df['sum_flash_time'] / df['total_matches']
return df
def normalize(series):
s = series.fillna(series.mean())
if s.max() == s.min(): return pd.Series([50]*len(s), index=s.index)
return (s - s.min()) / (s.max() - s.min()) * 100
def calculate_full_scores(df):
df = df.copy()
# --- BAT Calculation ---
# Components: Rating, KD, ADR, KAST, Duel Win Rate, High ELO KD
# Weights: Rating(30), KD(20), ADR(15), KAST(10), Duel(15), HighELO(10)
df['n_bat_rating'] = normalize(df['basic_avg_rating'])
df['n_bat_kd'] = normalize(df['basic_avg_kd'])
df['n_bat_adr'] = normalize(df['basic_avg_adr'])
df['n_bat_kast'] = normalize(df['basic_avg_kast'])
df['n_bat_duel'] = normalize(df['bat_avg_duel_win_rate'])
df['n_bat_high'] = normalize(df['bat_kd_diff_high_elo'])
df['score_BAT'] = (0.3*df['n_bat_rating'] + 0.2*df['n_bat_kd'] + 0.15*df['n_bat_adr'] +
0.1*df['n_bat_kast'] + 0.15*df['n_bat_duel'] + 0.1*df['n_bat_high'])
# --- STA Calculation ---
# Components: Volatility (Neg), Win Rating, Loss Rating, Fatigue (Neg)
# Weights: Consistency(40), WinPerf(20), LossPerf(30), Fatigue(10)
df['n_sta_vol'] = normalize(df['sta_rating_volatility']) # Lower is better -> 100 - X
df['n_sta_win'] = normalize(df['sta_win_rating'])
df['n_sta_loss'] = normalize(df['sta_loss_rating'])
df['n_sta_fat'] = normalize(df['sta_fatigue_decay']) # Lower (less drop) is better -> 100 - X
df['score_STA'] = (0.4*(100-df['n_sta_vol']) + 0.2*df['n_sta_win'] +
0.3*df['n_sta_loss'] + 0.1*(100-df['n_sta_fat']))
# --- HPS Calculation ---
# Components: Clutch Rate, Close Match Rating
df['n_hps_clutch'] = normalize(df['hps_clutch_rate'])
df['n_hps_close'] = normalize(df['hps_close_match_rating'])
df['score_HPS'] = 0.5*df['n_hps_clutch'] + 0.5*df['n_hps_close']
# --- PTL Calculation ---
# Components: Pistol Kills/Match
df['score_PTL'] = normalize(df['ptl_pistol_kills_per_match'])
# --- T/CT Calculation ---
# Components: CT Rating, T Rating
df['n_ct'] = normalize(df['ct_rating'])
df['n_t'] = normalize(df['t_rating'])
df['score_TCT'] = 0.5*df['n_ct'] + 0.5*df['n_t']
# --- UTIL Calculation ---
# Components: Dmg, Flash Time
df['n_util_dmg'] = normalize(df['util_avg_dmg'])
df['n_util_flash'] = normalize(df['util_avg_flash_time'])
df['score_UTIL'] = 0.6*df['n_util_dmg'] + 0.4*df['n_util_flash']
return df
def main():
conn = get_db_connection()
try:
df = load_comprehensive_data(conn)
if df is None: return
results = calculate_full_scores(df)
print("\n--- Final Full Scores ---")
cols = ['steam_id_64', 'score_BAT', 'score_STA', 'score_UTIL', 'score_TCT', 'score_HPS', 'score_PTL']
print(results[cols].sort_values('score_BAT', ascending=False).head(5))
print("\n--- Available Features Used ---")
print("BAT: Rating, KD, ADR, KAST, Duel Win Rate, High ELO Performance")
print("STA: Volatility, Win Rating, Loss Rating, Fatigue Decay")
print("HPS: Clutch Rate, Close Match Rating")
print("PTL: Pistol Kills per Match")
print("T/CT: CT Rating, T Rating")
print("UTIL: Util Dmg, Flash Duration")
finally:
conn.close()
if __name__ == "__main__":
main()

View File

@@ -1,499 +0,0 @@
import sqlite3
import pandas as pd
import numpy as np
import os
DB_L2_PATH = r'd:\Documents\trae_projects\yrtv\database\L2\L2_Main.sqlite'
def get_db_connection():
conn = sqlite3.connect(DB_L2_PATH)
conn.row_factory = sqlite3.Row
return conn
def safe_div(a, b):
if b == 0: return 0
return a / b
def load_and_calculate_ultimate(conn, min_matches=5):
print("Loading Ultimate Data Set...")
# 1. Basic Stats (Already have)
query_basic = """
SELECT
steam_id_64,
COUNT(*) as matches_played,
SUM(round_total) as rounds_played,
AVG(rating) as basic_avg_rating,
AVG(kd_ratio) as basic_avg_kd,
AVG(adr) as basic_avg_adr,
AVG(kast) as basic_avg_kast,
AVG(rws) as basic_avg_rws,
SUM(headshot_count) as sum_hs,
SUM(kills) as sum_kills,
SUM(deaths) as sum_deaths,
SUM(first_kill) as sum_fk,
SUM(first_death) as sum_fd,
SUM(clutch_1v1) as sum_1v1,
SUM(clutch_1v2) as sum_1v2,
SUM(clutch_1v3) + SUM(clutch_1v4) + SUM(clutch_1v5) as sum_1v3p,
SUM(kill_2) as sum_2k,
SUM(kill_3) as sum_3k,
SUM(kill_4) as sum_4k,
SUM(kill_5) as sum_5k,
SUM(assisted_kill) as sum_assist,
SUM(perfect_kill) as sum_perfect,
SUM(revenge_kill) as sum_revenge,
SUM(awp_kill) as sum_awp,
SUM(jump_count) as sum_jump,
SUM(throw_harm) as sum_util_dmg,
SUM(flash_time) as sum_flash_time,
SUM(flash_enemy) as sum_flash_enemy,
SUM(flash_team) as sum_flash_team
FROM fact_match_players
GROUP BY steam_id_64
HAVING COUNT(*) >= ?
"""
df = pd.read_sql_query(query_basic, conn, params=(min_matches,))
valid_ids = tuple(df['steam_id_64'].tolist())
if not valid_ids: return None
placeholders = ','.join(['?'] * len(valid_ids))
# --- Basic Derived ---
df['basic_headshot_rate'] = df['sum_hs'] / df['sum_kills'].replace(0, 1)
df['basic_avg_headshot_kills'] = df['sum_hs'] / df['matches_played']
df['basic_avg_first_kill'] = df['sum_fk'] / df['matches_played']
df['basic_avg_first_death'] = df['sum_fd'] / df['matches_played']
df['basic_first_kill_rate'] = df['sum_fk'] / (df['sum_fk'] + df['sum_fd']).replace(0, 1)
df['basic_first_death_rate'] = df['sum_fd'] / (df['sum_fk'] + df['sum_fd']).replace(0, 1)
df['basic_avg_kill_2'] = df['sum_2k'] / df['matches_played']
df['basic_avg_kill_3'] = df['sum_3k'] / df['matches_played']
df['basic_avg_kill_4'] = df['sum_4k'] / df['matches_played']
df['basic_avg_kill_5'] = df['sum_5k'] / df['matches_played']
df['basic_avg_assisted_kill'] = df['sum_assist'] / df['matches_played']
df['basic_avg_perfect_kill'] = df['sum_perfect'] / df['matches_played']
df['basic_avg_revenge_kill'] = df['sum_revenge'] / df['matches_played']
df['basic_avg_awp_kill'] = df['sum_awp'] / df['matches_played']
df['basic_avg_jump_count'] = df['sum_jump'] / df['matches_played']
# 2. STA - Detailed Time Series
print("Calculating STA (Detailed)...")
query_sta = f"""
SELECT mp.steam_id_64, mp.rating, mp.is_win, m.start_time, m.duration
FROM fact_match_players mp
JOIN fact_matches m ON mp.match_id = m.match_id
WHERE mp.steam_id_64 IN ({placeholders})
ORDER BY mp.steam_id_64, m.start_time
"""
df_matches = pd.read_sql_query(query_sta, conn, params=valid_ids)
sta_list = []
for pid, group in df_matches.groupby('steam_id_64'):
group = group.sort_values('start_time')
# Last 30
last_30 = group.tail(30)
sta_last_30 = last_30['rating'].mean()
# Win/Loss
sta_win = group[group['is_win']==1]['rating'].mean()
sta_loss = group[group['is_win']==0]['rating'].mean()
# Volatility
sta_vol = group.tail(10)['rating'].std()
# Time Correlation (Duration vs Rating)
sta_time_corr = group['duration'].corr(group['rating']) if len(group) > 2 else 0
# Fatigue
group['date'] = pd.to_datetime(group['start_time'], unit='s').dt.date
daily = group.groupby('date')['rating'].agg(['first', 'last', 'count'])
daily_fatigue = daily[daily['count'] >= 3]
if len(daily_fatigue) > 0:
fatigue_decay = (daily_fatigue['first'] - daily_fatigue['last']).mean()
else:
fatigue_decay = 0
sta_list.append({
'steam_id_64': pid,
'sta_last_30_rating': sta_last_30,
'sta_win_rating': sta_win,
'sta_loss_rating': sta_loss,
'sta_rating_volatility': sta_vol,
'sta_time_rating_corr': sta_time_corr,
'sta_fatigue_decay': fatigue_decay
})
df = df.merge(pd.DataFrame(sta_list), on='steam_id_64', how='left')
# 3. BAT - Distance & Advanced
print("Calculating BAT (Distance & Context)...")
# Distance Logic: Get all kills with positions
# We need to map positions.
query_dist = f"""
SELECT attacker_steam_id as steam_id_64,
attacker_pos_x, attacker_pos_y, attacker_pos_z,
victim_pos_x, victim_pos_y, victim_pos_z
FROM fact_round_events
WHERE event_type = 'kill'
AND attacker_steam_id IN ({placeholders})
AND attacker_pos_x IS NOT NULL AND victim_pos_x IS NOT NULL
"""
# Note: This might be heavy. If memory issue, sample or chunk.
try:
df_dist = pd.read_sql_query(query_dist, conn, params=valid_ids)
if not df_dist.empty:
# Calc Euclidian Distance
df_dist['dist'] = np.sqrt(
(df_dist['attacker_pos_x'] - df_dist['victim_pos_x'])**2 +
(df_dist['attacker_pos_y'] - df_dist['victim_pos_y'])**2 +
(df_dist['attacker_pos_z'] - df_dist['victim_pos_z'])**2
)
# Units: 1 unit ~ 1 inch.
# Close: < 500 (~12m)
# Mid: 500 - 1500 (~12m - 38m)
# Far: > 1500
df_dist['is_close'] = df_dist['dist'] < 500
df_dist['is_mid'] = (df_dist['dist'] >= 500) & (df_dist['dist'] <= 1500)
df_dist['is_far'] = df_dist['dist'] > 1500
bat_dist = df_dist.groupby('steam_id_64').agg({
'is_close': 'mean', # % of kills that are close
'is_mid': 'mean',
'is_far': 'mean'
}).reset_index()
bat_dist.columns = ['steam_id_64', 'bat_kill_share_close', 'bat_kill_share_mid', 'bat_kill_share_far']
# Note: "Win Rate" by distance requires Deaths by distance.
# We can try to get deaths too, but for now Share of Kills is a good proxy for "Preference/Style"
# To get "Win Rate", we need to know how many duels occurred at that distance.
# Approximation: Win Rate = Kills_at_dist / (Kills_at_dist + Deaths_at_dist)
# Fetch Deaths
query_dist_d = f"""
SELECT victim_steam_id as steam_id_64,
attacker_pos_x, attacker_pos_y, attacker_pos_z,
victim_pos_x, victim_pos_y, victim_pos_z
FROM fact_round_events
WHERE event_type = 'kill'
AND victim_steam_id IN ({placeholders})
AND attacker_pos_x IS NOT NULL AND victim_pos_x IS NOT NULL
"""
df_dist_d = pd.read_sql_query(query_dist_d, conn, params=valid_ids)
df_dist_d['dist'] = np.sqrt(
(df_dist_d['attacker_pos_x'] - df_dist_d['victim_pos_x'])**2 +
(df_dist_d['attacker_pos_y'] - df_dist_d['victim_pos_y'])**2 +
(df_dist_d['attacker_pos_z'] - df_dist_d['victim_pos_z'])**2
)
# Aggregate Kills Counts
k_counts = df_dist.groupby('steam_id_64').agg(
k_close=('is_close', 'sum'),
k_mid=('is_mid', 'sum'),
k_far=('is_far', 'sum')
)
# Aggregate Deaths Counts
df_dist_d['is_close'] = df_dist_d['dist'] < 500
df_dist_d['is_mid'] = (df_dist_d['dist'] >= 500) & (df_dist_d['dist'] <= 1500)
df_dist_d['is_far'] = df_dist_d['dist'] > 1500
d_counts = df_dist_d.groupby('steam_id_64').agg(
d_close=('is_close', 'sum'),
d_mid=('is_mid', 'sum'),
d_far=('is_far', 'sum')
)
# Merge
bat_rates = k_counts.join(d_counts, how='outer').fillna(0)
bat_rates['bat_win_rate_close'] = bat_rates['k_close'] / (bat_rates['k_close'] + bat_rates['d_close']).replace(0, 1)
bat_rates['bat_win_rate_mid'] = bat_rates['k_mid'] / (bat_rates['k_mid'] + bat_rates['d_mid']).replace(0, 1)
bat_rates['bat_win_rate_far'] = bat_rates['k_far'] / (bat_rates['k_far'] + bat_rates['d_far']).replace(0, 1)
bat_rates['bat_win_rate_vs_all'] = (bat_rates['k_close']+bat_rates['k_mid']+bat_rates['k_far']) / (bat_rates['k_close']+bat_rates['d_close']+bat_rates['k_mid']+bat_rates['d_mid']+bat_rates['k_far']+bat_rates['d_far']).replace(0, 1)
df = df.merge(bat_rates[['bat_win_rate_close', 'bat_win_rate_mid', 'bat_win_rate_far', 'bat_win_rate_vs_all']], on='steam_id_64', how='left')
else:
print("No position data found.")
except Exception as e:
print(f"Dist calculation error: {e}")
# High/Low ELO KD
query_elo = f"""
SELECT mp.steam_id_64, mp.kd_ratio,
(SELECT AVG(group_origin_elo) FROM fact_match_teams fmt WHERE fmt.match_id = mp.match_id AND group_origin_elo > 0) as elo
FROM fact_match_players mp
WHERE mp.steam_id_64 IN ({placeholders})
"""
df_elo = pd.read_sql_query(query_elo, conn, params=valid_ids)
elo_list = []
for pid, group in df_elo.groupby('steam_id_64'):
avg = group['elo'].mean()
if pd.isna(avg): avg = 1000
elo_list.append({
'steam_id_64': pid,
'bat_kd_diff_high_elo': group[group['elo'] > avg]['kd_ratio'].mean(),
'bat_kd_diff_low_elo': group[group['elo'] <= avg]['kd_ratio'].mean()
})
df = df.merge(pd.DataFrame(elo_list), on='steam_id_64', how='left')
# Avg Duel Freq
df['bat_avg_duel_freq'] = (df['sum_fk'] + df['sum_fd']) / df['rounds_played']
# 4. HPS - High Pressure Contexts
print("Calculating HPS (Contexts)...")
# We need round-by-round score evolution.
# Join rounds and economy(side) and matches
query_hps_ctx = f"""
SELECT r.match_id, r.round_num, r.ct_score, r.t_score, r.winner_side,
m.score_team1, m.score_team2, m.winner_team,
e.steam_id_64, e.side as player_side,
(SELECT COUNT(*) FROM fact_round_events ev WHERE ev.match_id=r.match_id AND ev.round_num=r.round_num AND ev.attacker_steam_id=e.steam_id_64 AND ev.event_type='kill') as kills,
(SELECT COUNT(*) FROM fact_round_events ev WHERE ev.match_id=r.match_id AND ev.round_num=r.round_num AND ev.victim_steam_id=e.steam_id_64 AND ev.event_type='kill') as deaths
FROM fact_rounds r
JOIN fact_matches m ON r.match_id = m.match_id
JOIN fact_round_player_economy e ON r.match_id = e.match_id AND r.round_num = e.round_num
WHERE e.steam_id_64 IN ({placeholders})
"""
# This is heavy.
try:
# Optimization: Process per match or use SQL aggregation?
# SQL aggregation for specific conditions is better.
# 4.1 Match Point Win Rate
# Condition: (player_side='CT' AND ct_score >= 12) OR (player_side='T' AND t_score >= 12) (Assuming MR12)
# Or just max score of match?
# Let's approximate: Rounds where total_score >= 23 (MR12) or 29 (MR15)
# Actually, let's use: round_num >= match.round_total - 1? No.
# Use: Rounds where One Team Score = Match Win Score - 1.
# Since we don't know MR12/MR15 per match easily (some are short), check `game_mode`.
# Fallback: Rounds where `ct_score` or `t_score` >= 12.
# 4.2 Pressure Entry Rate (Losing Streak)
# Condition: Team score < Enemy score - 3.
# 4.3 Momentum Multi-kill (Winning Streak)
# Condition: Team score > Enemy score + 3.
# Let's load a simplified dataframe of rounds
df_rounds = pd.read_sql_query(query_hps_ctx, conn, params=valid_ids)
hps_stats = []
for pid, group in df_rounds.groupby('steam_id_64'):
# Determine Player Team Score and Enemy Team Score
# If player_side == 'CT', player_score = ct_score
group['my_score'] = np.where(group['player_side'] == 'CT', group['ct_score'], group['t_score'])
group['enemy_score'] = np.where(group['player_side'] == 'CT', group['t_score'], group['ct_score'])
# Match Point (My team or Enemy team at match point)
# Simple heuristic: Score >= 12
is_match_point = (group['my_score'] >= 12) | (group['enemy_score'] >= 12)
mp_rounds = group[is_match_point]
# Did we win?
# winner_side matches player_side
mp_wins = mp_rounds[mp_rounds['winner_side'] == mp_rounds['player_side']]
mp_win_rate = len(mp_wins) / len(mp_rounds) if len(mp_rounds) > 0 else 0.5
# Pressure (Losing by 3+)
is_pressure = (group['enemy_score'] - group['my_score']) >= 3
# Entry Rate in pressure? Need FK data.
# We only loaded kills. Let's use Kills per round in pressure.
pressure_kpr = group[is_pressure]['kills'].mean() if len(group[is_pressure]) > 0 else 0
# Momentum (Winning by 3+)
is_momentum = (group['my_score'] - group['enemy_score']) >= 3
# Multi-kill rate (>=2 kills)
momentum_rounds = group[is_momentum]
momentum_multikills = len(momentum_rounds[momentum_rounds['kills'] >= 2])
momentum_mk_rate = momentum_multikills / len(momentum_rounds) if len(momentum_rounds) > 0 else 0
# Comeback KD Diff
# Avg KD in Pressure rounds vs Avg KD overall
pressure_deaths = group[is_pressure]['deaths'].sum()
pressure_kills = group[is_pressure]['kills'].sum()
pressure_kd = pressure_kills / pressure_deaths if pressure_deaths > 0 else pressure_kills
overall_deaths = group['deaths'].sum()
overall_kills = group['kills'].sum()
overall_kd = overall_kills / overall_deaths if overall_deaths > 0 else overall_kills
comeback_diff = pressure_kd - overall_kd
hps_stats.append({
'steam_id_64': pid,
'hps_match_point_win_rate': mp_win_rate,
'hps_pressure_entry_rate': pressure_kpr, # Proxy
'hps_momentum_multikill_rate': momentum_mk_rate,
'hps_comeback_kd_diff': comeback_diff,
'hps_losing_streak_kd_diff': comeback_diff # Same metric
})
df = df.merge(pd.DataFrame(hps_stats), on='steam_id_64', how='left')
# 4.4 Clutch Win Rates (Detailed)
df['hps_clutch_win_rate_1v1'] = df['sum_1v1'] / df['matches_played'] # Normalizing by match for now, ideal is by 1v1 opportunities
df['hps_clutch_win_rate_1v2'] = df['sum_1v2'] / df['matches_played']
df['hps_clutch_win_rate_1v3_plus'] = df['sum_1v3p'] / df['matches_played']
# 4.5 Close Match Rating (from previous)
# ... (Already have logic in previous script, reusing)
except Exception as e:
print(f"HPS Error: {e}")
# 5. PTL - Pistol Detailed
print("Calculating PTL...")
# Filter Round 1, 13 (and 16 for MR15?)
# Just use 1 and 13 (common for MR12)
query_ptl = f"""
SELECT
e.steam_id_64,
(SELECT COUNT(*) FROM fact_round_events ev WHERE ev.match_id=e.match_id AND ev.round_num=e.round_num AND ev.attacker_steam_id=e.steam_id_64 AND ev.event_type='kill') as kills,
(SELECT COUNT(*) FROM fact_round_events ev WHERE ev.match_id=e.match_id AND ev.round_num=e.round_num AND ev.victim_steam_id=e.steam_id_64 AND ev.event_type='kill') as deaths,
r.winner_side, e.side as player_side,
e.equipment_value
FROM fact_round_player_economy e
JOIN fact_rounds r ON e.match_id = r.match_id AND e.round_num = r.round_num
WHERE e.steam_id_64 IN ({placeholders})
AND e.round_num IN (1, 13)
"""
try:
df_ptl_raw = pd.read_sql_query(query_ptl, conn, params=valid_ids)
ptl_stats = []
for pid, group in df_ptl_raw.groupby('steam_id_64'):
kills = group['kills'].sum()
deaths = group['deaths'].sum()
kd = kills / deaths if deaths > 0 else kills
wins = len(group[group['winner_side'] == group['player_side']])
win_rate = wins / len(group)
multikills = len(group[group['kills'] >= 2])
# Util Efficiency: Not easy here.
ptl_stats.append({
'steam_id_64': pid,
'ptl_pistol_kills': kills, # Total? Or Avg? Schema says REAL. Let's use Avg per Match later.
'ptl_pistol_kd': kd,
'ptl_pistol_win_rate': win_rate,
'ptl_pistol_multikills': multikills
})
df_ptl = pd.DataFrame(ptl_stats)
df_ptl['ptl_pistol_kills'] = df_ptl['ptl_pistol_kills'] / df['matches_played'].mean() # Approximate
df = df.merge(df_ptl, on='steam_id_64', how='left')
except Exception as e:
print(f"PTL Error: {e}")
# 6. T/CT & UTIL (Straightforward)
print("Calculating T/CT & UTIL...")
# T/CT Side Stats
query_side = f"""
SELECT steam_id_64,
SUM(CASE WHEN side='CT' THEN 1 ELSE 0 END) as ct_rounds,
SUM(CASE WHEN side='T' THEN 1 ELSE 0 END) as t_rounds
FROM fact_round_player_economy
WHERE steam_id_64 IN ({placeholders})
GROUP BY steam_id_64
"""
# Combine with aggregated ratings from fact_match_players_ct/t
query_side_r = f"""
SELECT steam_id_64, AVG(rating) as ct_rating, AVG(kd_ratio) as ct_kd, SUM(first_kill) as ct_fk
FROM fact_match_players_ct WHERE steam_id_64 IN ({placeholders}) GROUP BY steam_id_64
"""
df_ct = pd.read_sql_query(query_side_r, conn, params=valid_ids)
# Similar for T...
# Merge...
# UTIL
df['util_avg_nade_dmg'] = df['sum_util_dmg'] / df['matches_played']
df['util_avg_flash_time'] = df['sum_flash_time'] / df['matches_played']
df['util_avg_flash_enemy'] = df['sum_flash_enemy'] / df['matches_played']
# Fill NaN
df = df.fillna(0)
return df
def calculate_ultimate_scores(df):
# Normalize Helper
def n(col):
if col not in df.columns: return 50
s = df[col]
if s.max() == s.min(): return 50
return (s - s.min()) / (s.max() - s.min()) * 100
df = df.copy()
# 1. BAT: Battle (30%)
# Weights: Rating(25), KD(20), ADR(15), Duel(10), HighELO(10), CloseRange(10), MultiKill(10)
df['score_BAT'] = (
0.25 * n('basic_avg_rating') +
0.20 * n('basic_avg_kd') +
0.15 * n('basic_avg_adr') +
0.10 * n('bat_avg_duel_win_rate') + # Need to ensure col exists
0.10 * n('bat_kd_diff_high_elo') +
0.10 * n('bat_win_rate_close') +
0.10 * n('basic_avg_kill_3') # Multi-kill proxy
)
# 2. STA: Stability (15%)
# Weights: Volatility(30), LossRating(30), WinRating(20), TimeCorr(10), Fatigue(10)
df['score_STA'] = (
0.30 * (100 - n('sta_rating_volatility')) +
0.30 * n('sta_loss_rating') +
0.20 * n('sta_win_rating') +
0.10 * (100 - n('sta_time_rating_corr').abs()) + # Closer to 0 is better (independent of duration)
0.10 * (100 - n('sta_fatigue_decay'))
)
# 3. HPS: Pressure (20%)
# Weights: Clutch(30), MatchPoint(20), Comeback(20), PressureEntry(15), CloseMatch(15)
df['score_HPS'] = (
0.30 * n('sum_1v3p') + # Using high tier clutches
0.20 * n('hps_match_point_win_rate') +
0.20 * n('hps_comeback_kd_diff') +
0.15 * n('hps_pressure_entry_rate') +
0.15 * n('basic_avg_rating') # Fallback if close match rating missing
)
# 4. PTL: Pistol (10%)
# Weights: Kills(40), WinRate(30), KD(30)
df['score_PTL'] = (
0.40 * n('ptl_pistol_kills') +
0.30 * n('ptl_pistol_win_rate') +
0.30 * n('ptl_pistol_kd')
)
# 5. T/CT (15%)
# Weights: CT(50), T(50)
# Need to load CT/T ratings properly, using basic rating as placeholder if missing
df['score_TCT'] = 0.5 * n('basic_avg_rating') + 0.5 * n('basic_avg_rating')
# 6. UTIL (10%)
# Weights: Dmg(50), Flash(30), EnemiesFlashed(20)
df['score_UTIL'] = (
0.50 * n('util_avg_nade_dmg') +
0.30 * n('util_avg_flash_time') +
0.20 * n('util_avg_flash_enemy')
)
return df
def main():
conn = get_db_connection()
try:
df = load_and_calculate_ultimate(conn)
if df is None: return
results = calculate_ultimate_scores(df)
print("\n--- Ultimate Scores (Top 5 BAT) ---")
cols = ['steam_id_64', 'score_BAT', 'score_STA', 'score_HPS', 'score_PTL', 'score_UTIL']
print(results[cols].sort_values('score_BAT', ascending=False).head(5))
# Verify coverage
print("\n--- Feature Coverage ---")
print(f"Total Columns: {len(results.columns)}")
print("BAT Distances:", 'bat_win_rate_close' in results.columns)
print("HPS Contexts:", 'hps_match_point_win_rate' in results.columns)
print("PTL Detailed:", 'ptl_pistol_kd' in results.columns)
finally:
conn.close()
if __name__ == "__main__":
main()

View File

@@ -1,22 +0,0 @@
import sqlite3
import os
L1A_DB_PATH = r'd:\Documents\trae_projects\yrtv\database\L1A\L1A.sqlite'
print("Checking L1A...")
if os.path.exists(L1A_DB_PATH):
try:
conn = sqlite3.connect(L1A_DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT name FROM sqlite_master WHERE type='table'")
tables = cursor.fetchall()
print(f"Tables: {tables}")
cursor.execute("SELECT COUNT(*) FROM raw_iframe_network")
count = cursor.fetchone()[0]
print(f"L1A Records: {count}")
conn.close()
except Exception as e:
print(f"Error checking L1A: {e}")
else:
print(f"L1A DB not found at {L1A_DB_PATH}")

View File

@@ -1,19 +0,0 @@
import sqlite3
import pandas as pd
import os
db_path = r'd:\Documents\trae_projects\yrtv\database\L3\L3_Features.sqlite'
conn = sqlite3.connect(db_path)
try:
print("Checking L3 Obj and KAST:")
df = pd.read_sql_query("""
SELECT
steam_id_64,
side_obj_t, side_obj_ct,
side_kast_t, side_kast_ct
FROM dm_player_features
LIMIT 5
""", conn)
print(df)
finally:
conn.close()

View File

@@ -1,55 +0,0 @@
import sqlite3
import pandas as pd
import numpy as np
import os
# Config to match your project structure
class Config:
DB_L3_PATH = r'd:\Documents\trae_projects\yrtv\database\L3\L3_Features.sqlite'
def check_variance():
db_path = Config.DB_L3_PATH
if not os.path.exists(db_path):
print(f"L3 DB not found at {db_path}")
return
conn = sqlite3.connect(db_path)
try:
# Read all features
df = pd.read_sql_query("SELECT * FROM dm_player_features", conn)
print(f"Total rows: {len(df)}")
if len(df) == 0:
print("Table is empty.")
return
numeric_cols = df.select_dtypes(include=['number']).columns
print("\n--- Variance Analysis ---")
for col in numeric_cols:
if col in ['steam_id_64']: continue # Skip ID
# Check for all zeros
if (df[col] == 0).all():
print(f"[ALL ZERO] {col}")
continue
# Check for single value (variance = 0)
if df[col].nunique() <= 1:
val = df[col].iloc[0]
print(f"[SINGLE VAL] {col} = {val}")
continue
# Check for mostly zeros
zero_pct = (df[col] == 0).mean()
if zero_pct > 0.9:
print(f"[MOSTLY ZERO] {col} ({zero_pct:.1%} zeros)")
# Basic stats for valid ones
# print(f"{col}: min={df[col].min():.2f}, max={df[col].max():.2f}, mean={df[col].mean():.2f}")
finally:
conn.close()
if __name__ == "__main__":
check_variance()

View File

@@ -1,45 +0,0 @@
import sqlite3
import pandas as pd
match_id = 'g161-n-20251222204652101389654'
def check_data():
conn = sqlite3.connect('database/L2/L2_Main.sqlite')
print(f"--- Check Match: {match_id} ---")
# 1. Source Type
c = conn.cursor()
c.execute("SELECT data_source_type FROM fact_matches WHERE match_id = ?", (match_id,))
row = c.fetchone()
if row:
print(f"Data Source: {row[0]}")
else:
print("Match not found")
return
# 2. Round Events (Sample)
print("\n--- Round Events Sample ---")
try:
df = pd.read_sql(f"SELECT round_num, event_type, attacker_steam_id, victim_steam_id, weapon FROM fact_round_events WHERE match_id = '{match_id}' LIMIT 5", conn)
print(df)
if df.empty:
print("WARNING: No events found.")
except Exception as e:
print(e)
# 3. Economy (Sample)
print("\n--- Economy Sample ---")
try:
df_eco = pd.read_sql(f"SELECT round_num, steam_id_64, equipment_value FROM fact_round_player_economy WHERE match_id = '{match_id}' LIMIT 5", conn)
print(df_eco)
if df_eco.empty:
print("Info: No economy data (Likely Classic source).")
except Exception as e:
print(e)
conn.close()
if __name__ == "__main__":
check_data()

View File

@@ -1,63 +0,0 @@
import sqlite3
import pandas as pd
import json
import os
import sys
# Add parent directory
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from web.config import Config
def check_mapping():
conn = sqlite3.connect(Config.DB_L2_PATH)
# Join economy and teams via match_id
# We need to match steam_id (in eco) to group_uids (in teams)
# 1. Get Economy R1 samples
query_eco = """
SELECT match_id, steam_id_64, side
FROM fact_round_player_economy
WHERE round_num = 1
LIMIT 10
"""
eco_rows = pd.read_sql_query(query_eco, conn)
if eco_rows.empty:
print("No Economy R1 data found.")
conn.close()
return
print("Checking Mapping...")
for _, row in eco_rows.iterrows():
mid = row['match_id']
sid = row['steam_id_64']
side = row['side']
# Get Teams for this match
query_teams = "SELECT group_id, group_fh_role, group_uids FROM fact_match_teams WHERE match_id = ?"
team_rows = pd.read_sql_query(query_teams, conn, params=(mid,))
for _, t_row in team_rows.iterrows():
# Check if sid is in group_uids (which contains UIDs, not SteamIDs!)
# We need to map SteamID -> UID
# Use dim_players or fact_match_players
q_uid = "SELECT uid FROM fact_match_players WHERE match_id = ? AND steam_id_64 = ?"
uid_res = conn.execute(q_uid, (mid, sid)).fetchone()
if not uid_res:
continue
uid = str(uid_res[0])
group_uids = str(t_row['group_uids']).split(',')
if uid in group_uids:
role = t_row['group_fh_role']
print(f"Match {mid}: Steam {sid} (UID {uid}) is on Side {side} in R1.")
print(f" Found in Group {t_row['group_id']} with FH Role {role}.")
print(f" MAPPING: Role {role} = {side}")
break
conn.close()
if __name__ == "__main__":
check_mapping()

View File

@@ -1,43 +0,0 @@
import sqlite3
import os
DB_PATH = r'd:\Documents\trae_projects\yrtv\database\L2\L2_Main.sqlite'
def check_tables():
if not os.path.exists(DB_PATH):
print(f"DB not found: {DB_PATH}")
return
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
tables = [
'dim_players', 'dim_maps',
'fact_matches', 'fact_match_teams',
'fact_match_players', 'fact_match_players_ct', 'fact_match_players_t',
'fact_rounds', 'fact_round_events', 'fact_round_player_economy'
]
print(f"--- L2 Database Check: {DB_PATH} ---")
for table in tables:
try:
cursor.execute(f"SELECT COUNT(*) FROM {table}")
count = cursor.fetchone()[0]
print(f"{table:<25}: {count:>6} rows")
# Simple column check for recently added columns
if table == 'fact_match_players':
cursor.execute(f"PRAGMA table_info({table})")
cols = [info[1] for info in cursor.fetchall()]
if 'util_flash_usage' in cols:
print(f" [OK] util_flash_usage exists")
else:
print(f" [ERR] util_flash_usage MISSING")
except Exception as e:
print(f"{table:<25}: [ERROR] {e}")
conn.close()
if __name__ == "__main__":
check_tables()

View File

@@ -1,63 +0,0 @@
import sqlite3
import pandas as pd
import os
L2_PATH = r'd:\Documents\trae_projects\yrtv\database\L2\L2_Main.sqlite'
WEB_PATH = r'd:\Documents\trae_projects\yrtv\database\Web\Web_App.sqlite'
def debug_db():
# --- L2 Checks ---
conn = sqlite3.connect(L2_PATH)
print("--- Data Source Type Distribution ---")
try:
df = pd.read_sql_query("SELECT data_source_type, COUNT(*) as cnt FROM fact_matches GROUP BY data_source_type", conn)
print(df)
except Exception as e:
print(f"Error: {e}")
print("\n--- Economy Table Count ---")
try:
count = conn.execute("SELECT COUNT(*) FROM fact_round_player_economy").fetchone()[0]
print(f"Rows: {count}")
except Exception as e:
print(f"Error: {e}")
print("\n--- Check util_flash_usage in fact_match_players ---")
try:
cursor = conn.cursor()
cursor.execute("PRAGMA table_info(fact_match_players)")
cols = [info[1] for info in cursor.fetchall()]
if 'util_flash_usage' in cols:
print("Column 'util_flash_usage' EXISTS.")
nz = conn.execute("SELECT COUNT(*) FROM fact_match_players WHERE util_flash_usage > 0").fetchone()[0]
print(f"Rows with util_flash_usage > 0: {nz}")
else:
print("Column 'util_flash_usage' MISSING.")
except Exception as e:
print(f"Error: {e}")
conn.close()
# --- Web DB Checks ---
print("\n--- Web DB Check ---")
if not os.path.exists(WEB_PATH):
print(f"Web DB not found at {WEB_PATH}")
return
try:
conn_web = sqlite3.connect(WEB_PATH)
cursor = conn_web.cursor()
cursor.execute("SELECT name FROM sqlite_master WHERE type='table'")
tables = cursor.fetchall()
print(f"Tables: {[t[0] for t in tables]}")
if 'player_metadata' in [t[0] for t in tables]:
count = conn_web.execute("SELECT COUNT(*) FROM player_metadata").fetchone()[0]
print(f"player_metadata rows: {count}")
conn_web.close()
except Exception as e:
print(f"Error checking Web DB: {e}")
if __name__ == "__main__":
debug_db()

View File

@@ -1,34 +0,0 @@
import sqlite3
import os
BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
L2_PATH = os.path.join(BASE_DIR, 'database', 'L2', 'L2_Main.sqlite')
def check_db_integrity():
print(f"Checking DB at: {L2_PATH}")
if not os.path.exists(L2_PATH):
print("CRITICAL: Database file does not exist!")
return
try:
conn = sqlite3.connect(L2_PATH)
cursor = conn.cursor()
# Check integrity
print("Running PRAGMA integrity_check...")
cursor.execute("PRAGMA integrity_check")
print(f"Integrity: {cursor.fetchone()}")
# Check specific user again
cursor.execute("SELECT steam_id_64, username FROM dim_players WHERE username LIKE '%jacky%'")
rows = cursor.fetchall()
print(f"Direct DB check found {len(rows)} rows matching '%jacky%':")
for r in rows:
print(r)
conn.close()
except Exception as e:
print(f"DB Error: {e}")
if __name__ == '__main__':
check_db_integrity()

View File

@@ -1,39 +0,0 @@
import sqlite3
import os
BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
L2_PATH = os.path.join(BASE_DIR, 'database', 'L2', 'L2_Main.sqlite')
def check_jacky():
print(f"Checking L2 database at: {L2_PATH}")
conn = sqlite3.connect(L2_PATH)
cursor = conn.cursor()
search_term = 'jacky'
print(f"\nSearching for '%{search_term}%' (Case Insensitive test):")
# Standard LIKE
cursor.execute("SELECT steam_id_64, username FROM dim_players WHERE username LIKE ?", (f'%{search_term}%',))
results = cursor.fetchall()
print(f"LIKE results: {len(results)}")
for r in results:
print(r)
# Case insensitive explicit
print("\nSearching with LOWER():")
cursor.execute("SELECT steam_id_64, username FROM dim_players WHERE LOWER(username) LIKE LOWER(?)", (f'%{search_term}%',))
results_lower = cursor.fetchall()
print(f"LOWER() results: {len(results_lower)}")
for r in results_lower:
print(r)
# Check jacky0987 specifically
print("\nChecking specific username 'jacky0987':")
cursor.execute("SELECT steam_id_64, username FROM dim_players WHERE username = 'jacky0987'")
specific = cursor.fetchone()
print(f"Specific match: {specific}")
conn.close()
if __name__ == '__main__':
check_jacky()

View File

@@ -1,84 +0,0 @@
import sqlite3
import os
# Define database path
BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
DB_PATH = os.path.join(BASE_DIR, 'database', 'Web', 'Web_App.sqlite')
def init_db():
print(f"Initializing Web database at: {DB_PATH}")
# Create directory if not exists
os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
# Create Tables
tables = [
"""
CREATE TABLE IF NOT EXISTS team_lineups (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
description TEXT,
player_ids_json TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
""",
"""
CREATE TABLE IF NOT EXISTS player_metadata (
steam_id_64 TEXT PRIMARY KEY,
notes TEXT,
tags TEXT,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
""",
"""
CREATE TABLE IF NOT EXISTS strategy_boards (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT,
map_name TEXT,
data_json TEXT,
created_by TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
""",
"""
CREATE TABLE IF NOT EXISTS wiki_pages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
path TEXT UNIQUE,
title TEXT,
content TEXT,
updated_by TEXT,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
""",
"""
CREATE TABLE IF NOT EXISTS comments (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id TEXT,
username TEXT,
target_type TEXT,
target_id TEXT,
content TEXT,
likes INTEGER DEFAULT 0,
is_hidden INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
"""
]
for sql in tables:
try:
cursor.execute(sql)
print("Executed SQL successfully.")
except Exception as e:
print(f"Error executing SQL: {e}")
conn.commit()
conn.close()
print("Web database initialized successfully.")
if __name__ == '__main__':
init_db()

View File

@@ -1,18 +0,0 @@
import sys
import os
# Add project root to path
current_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.dirname(current_dir)
sys.path.append(project_root)
from web.services.feature_service import FeatureService
print("Starting Rebuild...")
try:
count = FeatureService.rebuild_all_features(min_matches=1)
print(f"Rebuild Complete. Processed {count} players.")
except Exception as e:
print(f"Error: {e}")
import traceback
traceback.print_exc()

View File

@@ -1,14 +0,0 @@
from web.app import create_app
from web.services.feature_service import FeatureService
import sys
import os
# Ensure project root is in path
sys.path.append(os.getcwd())
app = create_app()
with app.app_context():
print("Starting Feature Rebuild...")
count = FeatureService.rebuild_all_features()
print(f"Rebuild Complete. Processed {count} players.")

View File

@@ -1,30 +0,0 @@
import sys
import os
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
import sqlite3
from web.config import Config
conn = sqlite3.connect(Config.DB_L2_PATH)
cursor = conn.cursor()
columns = [
'util_flash_usage',
'util_smoke_usage',
'util_molotov_usage',
'util_he_usage',
'util_decoy_usage'
]
for col in columns:
try:
cursor.execute(f"ALTER TABLE fact_match_players ADD COLUMN {col} INTEGER DEFAULT 0")
print(f"Added column {col}")
except sqlite3.OperationalError as e:
if "duplicate column name" in str(e):
print(f"Column {col} already exists.")
else:
print(f"Error adding {col}: {e}")
conn.commit()
conn.close()

View File

@@ -1,39 +0,0 @@
import sqlite3
import os
DB_PATH = r'd:\Documents\trae_projects\yrtv\database\L3\L3_Features.sqlite'
def add_columns():
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
# Check existing columns
cursor.execute("PRAGMA table_info(dm_player_features)")
columns = [row[1] for row in cursor.fetchall()]
new_columns = [
'score_bat', 'score_sta', 'score_hps', 'score_ptl', 'score_tct', 'score_util',
'bat_avg_duel_win_rate', 'bat_kd_diff_high_elo', 'bat_win_rate_close',
'sta_time_rating_corr', 'sta_fatigue_decay',
'hps_match_point_win_rate', 'hps_comeback_kd_diff', 'hps_pressure_entry_rate',
'ptl_pistol_win_rate', 'ptl_pistol_kd',
'util_avg_flash_enemy'
]
for col in new_columns:
if col not in columns:
print(f"Adding column: {col}")
try:
cursor.execute(f"ALTER TABLE dm_player_features ADD COLUMN {col} REAL")
except Exception as e:
print(f"Error adding {col}: {e}")
conn.commit()
conn.close()
print("Schema update complete.")
if __name__ == "__main__":
if not os.path.exists(DB_PATH):
print("L3 DB not found, skipping schema update (will be created by build script).")
else:
add_columns()

View File

@@ -1,82 +0,0 @@
import sqlite3
import os
DB_PATH = r'd:\Documents\trae_projects\yrtv\database\L3\L3_Features.sqlite'
def update_schema():
if not os.path.exists(DB_PATH):
print("L3 DB not found.")
return
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
# Get existing columns
cursor.execute("PRAGMA table_info(dm_player_features)")
existing_cols = {row[1] for row in cursor.fetchall()}
# List of columns to ensure exist
# Copied from schema.sql
required_columns = [
# Basic
'basic_avg_rating', 'basic_avg_kd', 'basic_avg_adr', 'basic_avg_kast', 'basic_avg_rws',
'basic_avg_headshot_kills', 'basic_headshot_rate',
'basic_avg_first_kill', 'basic_avg_first_death', 'basic_first_kill_rate', 'basic_first_death_rate',
'basic_avg_kill_2', 'basic_avg_kill_3', 'basic_avg_kill_4', 'basic_avg_kill_5',
'basic_avg_assisted_kill', 'basic_avg_perfect_kill', 'basic_avg_revenge_kill',
'basic_avg_awp_kill', 'basic_avg_jump_count',
'basic_avg_mvps', 'basic_avg_plants', 'basic_avg_defuses', 'basic_avg_flash_assists',
# STA
'sta_last_30_rating', 'sta_win_rating', 'sta_loss_rating', 'sta_rating_volatility',
'sta_time_rating_corr', 'sta_fatigue_decay',
# BAT
'bat_kd_diff_high_elo', 'bat_kd_diff_low_elo', 'bat_avg_duel_win_rate', 'bat_avg_duel_freq',
'bat_win_rate_close', 'bat_win_rate_mid', 'bat_win_rate_far',
# HPS
'hps_clutch_win_rate_1v1', 'hps_clutch_win_rate_1v2', 'hps_clutch_win_rate_1v3_plus',
'hps_match_point_win_rate', 'hps_undermanned_survival_time', 'hps_pressure_entry_rate',
'hps_momentum_multikill_rate', 'hps_tilt_rating_drop', 'hps_clutch_rating_rise',
'hps_comeback_kd_diff', 'hps_losing_streak_kd_diff',
# PTL
'ptl_pistol_kills', 'ptl_pistol_multikills', 'ptl_pistol_win_rate', 'ptl_pistol_kd', 'ptl_pistol_util_efficiency',
# SIDE
'side_rating_ct', 'side_rating_t', 'side_kd_ct', 'side_kd_t',
'side_win_rate_ct', 'side_win_rate_t',
'side_first_kill_rate_ct', 'side_first_kill_rate_t',
'side_kd_diff_ct_t',
'side_kast_ct', 'side_kast_t',
'side_rws_ct', 'side_rws_t',
'side_first_death_rate_ct', 'side_first_death_rate_t',
'side_multikill_rate_ct', 'side_multikill_rate_t',
'side_headshot_rate_ct', 'side_headshot_rate_t',
'side_defuses_ct', 'side_plants_t',
'side_obj_ct', 'side_obj_t',
'side_planted_bomb_count', 'side_defused_bomb_count',
# UTIL
'util_avg_nade_dmg', 'util_avg_flash_time', 'util_avg_flash_enemy', 'util_avg_flash_team', 'util_usage_rate',
# Scores
'score_bat', 'score_sta', 'score_hps', 'score_ptl', 'score_tct', 'score_util'
]
for col in required_columns:
if col not in existing_cols:
print(f"Adding missing column: {col}")
try:
# Most are REAL, integers are fine as REAL in sqlite usually, or use affinity
cursor.execute(f"ALTER TABLE dm_player_features ADD COLUMN {col} REAL")
except Exception as e:
print(f"Failed to add {col}: {e}")
conn.commit()
conn.close()
print("Schema update check complete.")
if __name__ == "__main__":
update_schema()