
    MCj2                     j   d Z ddlZddlZddlZddlmZ ddlZddlZ	 ej                  ej                  d        ej                  e      Zddddd	dd
Zdede	j                   fdZdde	j                   dede	j                   fdZde	j                   de	j                   fdZddZedk(  r e        yy)aJ  
Crop yield data preprocessing.

Cleans raw crop production data (ICRISAT VDSA or APY government format)
into a standardized long-format table: one row per district-year-crop.

Usage:
    python -m ml_pipeline.preprocessing.clean_crop_data         --input data/raw/icrisat/yield.csv         --output data/processed/crop_clean.csv
    N)Pathz%%(asctime)s %(levelname)s %(message)s)levelformat         	   )kharifrabisummerz
whole yearautumnwinter
input_pathreturnc                 J   | j                         st        d|        t        j                  |       j                  D cg c]0  }|j                         j                         j                  dd      2 c}_        dj                  vrLdj                  vr!t        dt        j                               t        j                  d       d   d<   dj                  v r"d	j                  vrj                  dd	i
      h d}|t        j                        z
  }|r$t        d| dt        j                               g d}t        fd|D        d       }|%t        d| dt        j                         d      |dk7  r9j                  |di
      |dk(  r t        j                  d       d   dz  d<   dj                  vrFddg}t        fd|D        d       }|rj                  |di
      S t        j                  d       S c c}w )NzInput file not found:  _districtstateuW   Input has neither a 'district' nor a 'state' column — cannot proceed. Found columns: u   No district column found in input — using 'state' as a stopgap district value. Model granularity will be state-level, not district-level, until real district data is sourced.	crop_yearyearcolumns>   cropr   r   z"Input is missing required columns z	. Found: )yield_ton_hayield_kg_hayieldproductivityc              3   @   K   | ]  }|j                   v s|  y wNr   .0cdfs     VC:\Crop_Prediction\Backend\crop-ai-system\ml_pipeline\preprocessing\clean_crop_data.py	<genexpr>z$load_and_validate.<locals>.<genexpr>D   s     H!RZZAH   z/No recognizable yield column found. Looked for z, found columns: z?. Rename the source column or add the new alias to this script.r   r   z9Converting yield_kg_ha to yield_ton_ha (dividing by 1000)i  area_haareaarea_hectaresc              3   @   K   | ]  }|j                   v s|  y wr    r   r!   s     r%   r&   z$load_and_validate.<locals>.<genexpr>S   s     JQ!rzz/qJr'   u;   No area column found — area_ha will be absent from output)existsFileNotFoundErrorpdread_csvr   striplowerreplace
ValueErrorlistloggerwarningrenamesetnextinfo)	r   r#   requiredmissingyield_aliasesfound_yield_colarea_aliasesfound_area_colr$   s	           @r%   load_and_validaterA      s-   "8 EFF	Z	 B?AzzJ!!'')//#++C5JBJ #"**$++/

+;*<>  	C	

 G:bjj V2::%=YYV4Y5+HRZZ(G=gYiPTUWU_U_P`Oabcc MMH}H$OO=m_ M"2::./ 001
 	

 .(YY@YAm+KKST!#N!3d!:B~

"0J,JDQNI#>?B I NNXYIs Ks   5H r$   std_thresholdc                    | j                  d      d   j                  ddg      j                         }g d|_        | j	                  |dd      }|d   j                         |d   d	k(  z  t        j                  |d   |d
   z
        ||d   z  k  z  }t        |       }||   j                  d
dg      j                  d      }t        |      }t        j                  d||z
   d||z
  |z  dd       |S )u  
    Drops rows more than std_threshold standard deviations from their
    crop's mean yield. Implemented via boolean masking rather than
    groupby().apply() returning filtered sub-frames — recent pandas
    versions (2.2+) can silently drop the grouping column itself when
    apply() returns a row-filtered subset of the original frame, which
    would corrupt 'crop' out of the output entirely.
    r   r   meanstd)r   _group_mean
_group_stdleft)onhowrG   r   rF   r   TdropzOutlier removal: dropped z rows (z.1%))groupbyaggreset_indexr   mergeisnanpabslenrL   r5   r:   )r$   rB   group_statsmerged	keep_maskbeforeresultafters           r%   remove_outliers_per_cropr\   \   s    **V$^488&%IUUWK?KXXkf&X9F 	|!!#,1$	&66&(6-+@@AMTZ[gThDhh	j  WFI##]L,I#JVV\`VaFKE
KK+FUN+;7FUNV\C\]`BaabcdM    c                    | d   j                  t              j                  j                         j                  j                         | d<   | d   j                  t              j                  j                         j                  j                         | d<   d| j                  v r| d   j                  t              j                  j                         j                  j                         | d<   | d   j                  t              | d<   | d   j                         j                         }|dkD  rPt        j                  | dt        t        j                                       nt        j                  d       d| d<   t        j                  | d	   d
      | d	<   t        |       }| | d	   dkD     } t        |       }t        j!                  d||z
   d       t#        |       } | j%                  d	dg      j'                  d      } | S )Nr   r   seasonmonthr   zO rows have an unrecognized season value and got month=NaN. Recognized seasons: uM   No 'season' column present — month will be absent, defaulting to 6 (kharif)r   r   coerce)errorszDropped z/ rows with zero, negative, or non-numeric yield)subsetTrK   )astypestrr0   r1   r   mapSEASON_TO_MONTHisnullsumr5   r6   r4   keysr.   
to_numericrU   r:   r\   dropnarP   )r$   unmappedrY   r[   s       r%   cleanrn   x   s   
^**3/3399;??EEGBzNF""3'++11377==?BvJ2::(|**3/3399;??EEG8l&&77g;%%'++-a<NN* ''+O,@,@,B'C&DF
 	fg7r.'9(KB~WF	B~"	#BGE
KK(6E>**YZ[	!"	%B	>73	4	@	@d	@	KBIr]   c                     t        j                  d      } | j                  dd       | j                  dd       | j                         }t	        |j
                        }t	        |j                        }t        j                  d|        t        |      }t        j                  d       t        |      }t        |      d	k(  r*t        j                  d
       t        j                  d       |j                  j!                  dd       |j#                  |d       t        j                  dt        |       d|        t        j                  dt%        |d   j'                                       y )NzClean raw crop yield data)descriptionz--inputT)r;   z--outputzLoading raw crop data from z8Cleaning: type coercion, season mapping, outlier removalr   zKZero rows remain after cleaning. Check the source file and column mappings.   )parentsexist_okF)indexzSaved z cleaned rows to zCrops present: r   )argparseArgumentParseradd_argument
parse_argsr   inputoutputr5   r:   rA   rn   rU   errorsysexitparentmkdirto_csvsortedunique)parserargsr   output_pathraw_dfclean_dfs         r%   mainr      s)   $$1LMF
	D1

T2Ddjj!Jt{{#K
KK-j\:;z*F
KKJKV}H
8}bcTD9OOKuO-
KK&X'8FG
KK/&&)9)@)@)B"C!DEFr]   __main__)g      @)r   N)__doc__ru   loggingr|   pathlibr   numpyrS   pandasr.   basicConfigINFO	getLogger__name__r5   rg   	DataFramerA   floatr\   rn   r    r]   r%   <module>r      s   
   
      ',,/V W			8	$aqTUacd>$ >2<< >B e bll 8bll r|| :G2 zF r]   