
    j3                        d Z ddlmZ ddlZddlmZ ddlZddlZ	ddl
mZ ddd	d
ddZddddddZdZdZdZdZdZdZd%dZd&d'dZd(dZdZddddddZd)dZd*d Zd+d!Zd,d-d"Zd,d.d#Zd/d$Zy)0a  Core estimation: evidence retrieval by tier, projection, factors, caps,
confidence, and empirical prediction intervals.

Evidence tiers (Crystal's hierarchy, preserved):
  1 exact        same event + country + channel, LIVE history
  2 same_teams   same normalized teams (fuzzy >= .90), same country, LIVE
  3 same_event_country   same event + country, other channel (share-adjusted)
  4 cross_market same event, other country (TVU + share projected)
  5 slot_stats   same country+channel time-slot statistics
Estimate = tier evidence de-conditioned to a LIVE/reference base, then
re-conditioned to the target row via curves/multipliers/factors (log-space).
    )annotationsN)SequenceMatcher   )ReferenceDatazSame event on this channelzSame teams in this marketzSame event in this marketzSame event in another marketz This channel's time-slot historyr               g      W@g      V@g     T@g      R@g      M@)g333333?      @)gư>g      4@)g?g      $@
ףp=
?g333333?g     @P@c                    t        t        |       j                  d      D ch c]'  }t        j                  dd|j                               ) c}dhz
        }dj                  |      S c c}w )N|z	[^a-z0-9] )sortedstrsplitresublowerjoin)sttokss      -/var/www/html/crystal/crystal2/engine/core.py
norm_teamsr   '   sT    AS@QR1266,AGGI6RVXUYYZD88D> Ss   ,A*c                L    | |k(  xs t        d | |      j                         |k\  S N)r   ratio)abthreshs      r   teams_matchr#   ,   s(    6B_T1a0668FBB    c                B   | d   j                  fd      }| d   j                  fd      }| d   j                  j                        }fd}| d   j                  |      }| j                  fdd	
      }| d   ||z  |z  |z  |z  j                  d      z  S )a2  Strip each observation to a comparable base:
       base = ama / (hour_w * weekday_w * telecast_mult * team_w * host_f).
    Evidence-side behavioural factors MUST be removed here, or re-applying them
    to the target double-counts them (the exact compounding failure documented
    in the Crystal audit).hourc                8    j                  t        |             S r   )hour_wint)hrefs    r   <lambda>z_debase.<locals>.<lambda>6   s    #**SV"4 r$   weekdayc                8    j                  t        |             S r   )	weekday_wr)   )wr+   s    r   r,   z_debase.<locals>.<lambda>7   s    S]]3q6%: r$   telecast_typec           
     "   t        |       j                  d      D cg c]#  }|j                         s|j                         % }}dd l}|r7t	        |j                  |D cg c]  }j                  |       c}            S dS c c}w c c}w )Nr   r         ?)r   r   stripnumpyfloatmeanteam_w)teamsr   ts_npr+   s       r   _twz_debase.<locals>._tw9   sm    !$U!1!1#!6DA!'')aggiDD?AuSXXb9szz!}9:;JsJ E9s   BB"Br9   c                4    j                  | d   | d         S )N
event_namecountry)host_f)rr+   s    r   r,   z_debase.<locals>.<lambda>>   s    CJJq)E r$   r   )axisama_000g&.>)r   )maptelecast_multapplyclip)evr+   hwwwtmr<   twhfs    `      r   _debaserN   0   s     
F4	5B	I		:	;B	O		 	 !2!2	3BK 
G	B	EA	NBi=BGbL2-288t8DDDr$      r	   r   r   c           	     >   |j                  ||      }|syg }| j                         D ]b  \  }\  }}|t        d   k  r|j                  ||      }	|	s+|	dkD  s1|j                  t	        t        j                  ||	z              |f       d |rt        |      d   S dS )a  Pick the in-market channel closest in day-share to the target.

    `chans` is {channel: (median_base, n)} precomputed by fastindex. Returns
    None when no channel is deep enough or no share is known, and the caller
    then falls back to the whole-market median.
    Nr	   r   r   )shareitemsMIN_TIER_ROWSappendabsnplogmin)
chansr?   channelr+   sh_tscoredch_mnr   s
             r   _nearest_channelr`   M   s     99Wg&DF{{} 7GR}QIIgr"QMM3rvvdQh/0"567 $3v;q>--r$   c           	         t        t        j                  t        t	        |      d                  }| dt        |d      z  z   dt        dd|z
        z  z
  S )a  Move confidence with the weight of evidence, not by a token amount.

    The old bonus was min(6, 1.5*log10 n): one row scored 92 and five thousand
    scored 98. Six points across a 5,000x difference in evidence is not a
    confidence score, it is decoration. This rewards depth on the same scale it
    penalises thinness -- roughly -14 at one row, neutral at ten, +6 at a
    hundred or more.
    r   r   g       @g      ,@g        r3   )r6   rV   log10maxr)   rX   )confr_   depths      r   _depth_adjustrf   a   sL     "((3s1vq>*+E#E3''$S#+1F*FFFr$   c                     j                         D cg c]  \  }\  }}|t        k\  r||k7  r| c}}}xs#  D cg c]
  }||k7  s	| c}xs t               }|D cg c]  }|j                  |||      |f }}|D 	cg c]  \  }	}|		|	|f }}	}|rt	        |      d   S t        | fd      S c c}}}w c c}w c c}w c c}}	w )a  Choose the analog market to project this event from.

    `cands` is {country: (median_base, n)}. Markets with at least
    MIN_SOURCE_ROWS observations are ranked by ReferenceData.similarity and the
    closest wins; the row floor is dropped rather than the estimate refused if
    nothing clears it. Falls back to the most-rows market only when similarity
    cannot be measured for any candidate.
    r   c                    |    d   S )Nr    )ccandss    r   r,   z#_pick_source_fast.<locals>.<lambda>~   s    uQx{ r$   )key)rR   MIN_SOURCE_ROWSlist
similarityrX   rc   )
rk   targeteventr+   rj   r^   r_   eligibler\   ds
   `         r   _pick_source_fastrt   n   s     %*KKM 9 9ja"a'AK  9 @ 0aAK0@48K  >FFs~~fa/3FFF!'9A1=q!f9F96{1~x23390F9s"   B8
B?	B?!C
C	C	c                   | d   | d   | d   }}}t        | d         j                         j                         j                  dd      }t	        | j                  dd            }t	        | j                  d	d
            }	t        | j                  dd            }
|}ddlm} d\  }}}}|d   j                  |||f      }|r|d   t        d   k\  rd|d   |d   }}}|)|
r' ||||
      }|r|d   t        d   k\  rd|d   |d   }}}|z|d   j                  ||f      }|rbt        d |j                         D              }|t        d   k\  r6t        ||||      }|r	||   \  }}n|d   j                  ||f      }|\  }}d}|&|d   j                  |      }|rt        |      dk\  rd}|3|d   j                  ||f      }|r|d   t        d
   k\  rd
|d   |d   }}}|t        j                  |d      t	        |      t        j                   t        j                   dddddd
}|d|d<   |S d}|dk(  r|d   |   }t#        ||||      }||   \  }}t	        |      |d<   ||d<   |j%                  |      |j%                  |      }}||d |d<   |S |j'                         }t)        t        j*                  ||z  |d!   z  gt,               }|j/                  |      |j/                  |      }}|j1                  ||      xs |}|xs d"|xs d"z  } |d#   j                  ||f      xs d"}!t)        t        j*                  | |!z  |d$   z  gt2               }"|||"z  z  }d%|d&d'|"d&d(}|j5                  |||      }#|#9t)        t        j*                  |#|d)   z  gt6               }#||#z  }|d*|#d&d(z  }nhd+|d<   nb|d,v r^|j1                  ||      }|r|j1                  ||      nd }$|r4|$r2t)        t        j*                  ||$z  gt2               }%||%z  }d-|%d&d(}|j9                  |      }&|j;                  |      |j=                  |	      }(}'t        | j                  dd            j?                  d.      D )cg c]#  })|)j                         s|)j                         % }*})|*r;t)        t        j@                  |*D )cg c]  })|jC                  |)       c})            nd"}+|jE                  ||      },||'z  |(z  |&z  |+z  |,z  }-t)        |xs i j                  |d"            }.t)        t        j*                  |.d/d0            }.|-|.z  }-|j%                  |      }|r0|-|z  }/|/tF        kD  rd1|-d2d(|d3<   tF        |z  }-n|/tH        kD  rd4|d<   tK        tL        |   |      }0|0|d5vr|dk\  rd6ndz  }0t)        t        j*                  |0d
d7            }0|d8k  r
|d   sd9|d<   |0tN        k  r
|d   sd:|d<   |r||d;<   t	        |      |d<   |jQ                  tS        t)        |-      d      tS        |0d      d<|d2d(| d=|'d>d?|(d>d@|&d>dA|+d>dB|,d>d(|.d"k7  rdC|.d&d(ndz   dD       |S c c})w c c})w )ENr>   country_namechannel_namer1    _r&      r-   r   sports_teamsr   r   )
match_tkey)NNr   Neccr   r   ec_channelsc              3  &   K   | ]	  }|d      yw)r   Nri   ).0vs     r   	<genexpr>zestimate_row.<locals>.<genexpr>   s     5!5s   r	   ece_countriesr
   cczNo evidence)
strategy_tierstrategyevidence_rowsestimated_ama_000
confidenceflagcap_appliedformulasource_channelsource_countryNO_EVIDENCEr   r   r   MISSING_TVU_REFUSEDtvur3   ec_rel_sharerQ   z * tvu_ratio(z.3fz) * share_ratio()affinityz * affinity_ratio(NO_AFFINITY_DATA)r   r	   r   z * share_ratio(r         ?g?zHARD_MAX_18PCT (was z.1fr   REVIEW_ABOVE_15PCT_TVU)LIVEg      @c   
   THIN_EVIDENCEREVIEW_LOW_CONFIDENCEr   zmedian_debased_evidence(z
 * hour_w(z.2fz) * weekday_w(z) * telecast(z) * team_w(z	) * host(z	 * calib()r   r   r   )*r   r4   upperreplacer)   getr   	fastindexr|   rS   sumvaluesr`   len
TIER_NAMESrV   nanrt   r   	exponentsr6   rG   CLIP_TVUflagship_sharerQ   
CLIP_SHAREaffinity_ratioCLIP_AFFINITYrE   r(   r/   r   r7   r8   r@   HARD_MAX_TVU_SHAREFLAG_TVU_SHARErf   	TIER_CONFREVIEW_MIN_CONFupdateround)1rowr+   
ev_indexedcorrection_by_tierrq   r?   rZ   telecastr&   wdtkeyrH   r|   tierbasen_evsrc_channelhitrY   totalwholerk   out	proj_notesrc_countrytvu_ttvu_sbetar_tvufl_tfl_sr[   rel_trel_sr_shr_affsh_poolrA   rK   rI   rJ   r   r9   rL   rM   estcorrshare_of_tvurd   s1                                                    r   estimate_rowr      s   !,/^1Dc.FYG7E3'(..0668@@cJHswwvr"#D#cggi.C*DRcggnb12D	B%$7!D$k
U)--1
2C
s1vq))c!fc!fDd|Wd+3q6]1-- #a&#a&$D|=!%%ug&675elln55Ea((.ugwL!&{!3JD$tHLL%)9:E!&JD$|=!%%e,SZ1_D|hllGW-.3q6]1-- #a&#a&$D jnnT=.QI "bffbR2	!C
 |#F
 Iqy=!%('wsC;'
d"4yO !,www')=u=EM/CKJ}} bgguu}e<HxHI ''0#2D2D[2Qdyy'*2d->"&&{';<CRWWeemW=K
KL#E#;.>tCjJ	 ""5';?"''%4
+;";LmLMEEMD-eC[::I,CK		
 yy'*5@#))G[1dGbggdWn:z:;AAID)!C2I 
		8	$BZZs}}R0B #CGGNB$? @ F Fs KY1qwwyQWWYYEY;@rwwu5!

156	7cB	E7	#B
)b.2

"R
'C$*//c:;DsC()D4KC GGGEU{,,#7Cy!BC$u,CN*2CK4$/D89,CADq"%&DbyV%Foc&k-F +t9CJJ"5:q1D!n.tCj) Cr#h ?##%c(+bXYr#haQ 37#+4*A.2G  JK Z5s   Y2Y2
Y7c                >    ddl m}  || |xs t        | dd            S )z9Precompute every group median once. See engine/fastindex.r   )build_cached
source_dirN)r   r   getattr)r+   	cache_dirr   s      r   index_evidencer     s     'YJ'#|T*JKKr$   c                N   dddddd}i ||xs i }d}g g }}| j                         D ]  \  }}|j                  |d   d      |d	   }
}	t        j                  |
      r?|j	                  t
        j                         |j	                  t
        j                         t|j	                  t        |
t        t        j                  | |	z              z  d
             |j	                  t        |
t        t        j                  ||	z              z  d
              ||c| d<   | d<   | S )z~80% interval from per-tier log-residual sigma (empirical when supplied,
    conservative defaults otherwise). z(80%) = 1.2816.r   g)\(?gQ?g?r   r   gh o?r   r   r   interval80_lowinterval80_high)
iterrowsr   pdisnarT   rV   r   r   r6   exp)dfresidual_sigma_by_tierdefaultsigzlohiry   rA   r   es              r   attach_intervalsr     s    4DTd;G
7W
7/52
7CAB :1wwq)3/3F1G1771:IIbffryy0IIeAbffaR!Vn 55q9:IIeAbffQUm 44a89: 35b/B"./Ir$   )r   r   returnr   )g?)r    r   r!   r   r"   r6   r   bool)rH   pd.DataFramer+   r   r   z	pd.Series)rY   dictr?   r   rZ   r   r   z
str | None)rd   r6   r_   r)   r   r6   )rk   r   rp   r   rq   r   r   r   r   )
r   r   r+   r   r   r   r   dict | Noner   r   )r+   r   r   r   )r   r   r   r   r   r   )__doc__
__future__r   r   difflibr   r5   rV   pandasr   	referencer   r   r   r   r   r   r   r   r   r   r#   rN   rm   rS   r`   rf   rt   r   r   r   ri   r$   r   <module>r      s    # 	 #   $-2M,1O35
 $4D9	

  
CE$  !aA..(
G4&QhLr$   