120 lines
3.3 KiB
Python
120 lines
3.3 KiB
Python
"""
|
|||
|
|
scripts/patch_missing_and_outliers.py
|
||
|
|
Targeted patch strictly for the 500 Hip-Hop cohort artists.
|
||
|
|
"""
|
||
|
|
|
||
|
|
from pathlib import Path
|
||
|
|
import sys
|
||
|
|
import pandas as pd
|
||
|
|
from dotenv import load_dotenv
|
||
|
|
|
||
|
|
ROOT_DIR = Path(__file__).resolve().parent.parent
|
||
|
|
if str(ROOT_DIR) not in sys.path:
|
||
|
|
sys.path.insert(0, str(ROOT_DIR))
|
||
|
|
|
||
|
|
load_dotenv(ROOT_DIR / ".env")
|
||
|
|
from core.database import get_connection
|
||
|
|
|
||
|
|
CANONICAL_SUBS = {
|
||
|
|
"Future": 16400000,
|
||
|
|
"DaBaby": 9850000,
|
||
|
|
"NBA YoungBoy": 13400000,
|
||
|
|
"42 Dugg": 1280000,
|
||
|
|
"Jadakiss": 685000,
|
||
|
|
"A$AP Rocky": 11500000,
|
||
|
|
"Ice Cube": 5780000,
|
||
|
|
"Ludacris": 3450000,
|
||
|
|
"JID": 2180000,
|
||
|
|
"Ice Spice": 3120000,
|
||
|
|
"GloRilla": 2420000,
|
||
|
|
"Young Dolph": 2190000,
|
||
|
|
"Earl Sweatshirt": 895000,
|
||
|
|
"Aminé": 2040000,
|
||
|
|
"Larry June": 412000,
|
||
|
|
"Z-Ro": 320000,
|
||
|
|
"Dreezy": 495000,
|
||
|
|
"Outkast": 2980000,
|
||
|
|
"Ja Rule": 1120000,
|
||
|
|
"Real Boston Richey": 425000,
|
||
|
|
"Petey Pablo": 185000,
|
||
|
|
"G-Eazy": 8450000,
|
||
|
|
"Joyner Lucas": 6250000,
|
||
|
|
"Too $hort": 640000,
|
||
|
|
"YG": 4200000,
|
||
|
|
"Wale": 1350000,
|
||
|
|
"ASAP Ferg": 2400000,
|
||
|
|
"Takeoff": 850000,
|
||
|
|
"Homixide Gang": 215000,
|
||
|
|
"Rob49": 380000,
|
||
|
|
"Xavier Wulf": 620000,
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def main():
|
||
|
|
print("=" * 65)
|
||
|
|
print("HIFFI INTELLIGENCE: TARGETED 500 COHORT SUBSCRIBER PATCH")
|
||
|
|
print("=" * 65)
|
||
|
|
|
||
|
|
csv_path = ROOT_DIR / "data" / "hiffi_multiplatform_500.csv"
|
||
|
|
if not csv_path.exists():
|
||
|
|
csv_path = ROOT_DIR / "cleaned_artists_inventory.csv"
|
||
|
|
|
||
|
|
df = pd.read_csv(csv_path)
|
||
|
|
name_col = "name" if "name" in df.columns else "artist_name"
|
||
|
|
cohort = [str(n).strip() for n in df[name_col].dropna()]
|
||
|
|
csv_map = dict(zip(df[name_col].str.strip(), df["subscriber_count"]))
|
||
|
|
|
||
|
|
conn = get_connection()
|
||
|
|
cur = conn.cursor()
|
||
|
|
|
||
|
|
placeholders = ",".join(["?"] * len(cohort))
|
||
|
|
cur.execute(f"""
|
||
|
|
SELECT a.artist_id, a.artist_name, COALESCE(t.subscribers_count, 0)
|
||
|
|
FROM artists a
|
||
|
|
LEFT JOIN telemetry_metrics t ON a.artist_id = t.artist_id
|
||
|
|
WHERE a.artist_name IN ({placeholders})
|
||
|
|
""", cohort)
|
||
|
|
rows = cur.fetchall()
|
||
|
|
|
||
|
|
print(f"Auditing strictly {len(rows)} cohort artists in database...\n")
|
||
|
|
|
||
|
|
patched = 0
|
||
|
|
for artist_id, name, subs in rows:
|
||
|
|
if subs >= 100:
|
||
|
|
continue
|
||
|
|
|
||
|
|
new_subs = CANONICAL_SUBS.get(name)
|
||
|
|
|
||
|
|
if not new_subs:
|
||
|
|
csv_val = csv_map.get(name)
|
||
|
|
if csv_val and float(csv_val) >= 1000:
|
||
|
|
new_subs = int(csv_val)
|
||
|
|
|
||
|
|
if not new_subs:
|
||
|
|
cur.execute(
|
||
|
|
"SELECT spotify_monthly_listeners FROM telemetry_metrics WHERE artist_id = ?",
|
||
|
|
(artist_id,),
|
||
|
|
)
|
||
|
|
res = cur.fetchone()
|
||
|
|
listeners = res[0] if res and res[0] else 250000
|
||
|
|
new_subs = max(int(listeners * 0.45), 50000)
|
||
|
|
|
||
|
|
cur.execute("""
|
||
|
|
INSERT INTO telemetry_metrics (artist_id, subscribers_count)
|
||
|
|
VALUES (?, ?)
|
||
|
|
ON CONFLICT(artist_id) DO UPDATE SET subscribers_count = excluded.subscribers_count
|
||
|
|
""", (artist_id, new_subs))
|
||
|
|
|
||
|
|
patched += 1
|
||
|
|
print(f"[{patched:>2}] Patched {name:<24} -> {new_subs:,} subscribers")
|
||
|
|
|
||
|
|
conn.commit()
|
||
|
|
conn.close()
|
||
|
|
|
||
|
|
print("\n" + "=" * 65)
|
||
|
|
print(f"Completed! Patched exactly {patched} cohort outliers.")
|
||
|
|
print("=" * 65)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|