| # Custom metric |
|
|
| In case you don't settle for the default scikit-learn metrics, you can define your own metric. |
| |
| Here, we expect the organizer to know python. |
|
|
| ### How to define a custom metric |
|
|
| To define a custom metric, change `EVAL_METRIC` in `conf.json` to `custom`. You must also make sure that `EVAL_HIGHER_IS_BETTER` is set to `1` or `0` depending on whether a higher value of the metric is better or not. |
|
|
| The second step is to create a file `metric.py` in the private competition repo. |
| The file should contain a `compute` function that takes competition params as input. |
|
|
| Here is the part where we check if metric is custom and calculate the metric value: |
|
|
| ```python |
| def compute_metrics(params): |
| if params.metric == "custom": |
| metric_file = hf_hub_download( |
| repo_id=params.competition_id, |
| filename="metric.py", |
| token=params.token, |
| repo_type="dataset", |
| ) |
| sys.path.append(os.path.dirname(metric_file)) |
| metric = importlib.import_module("metric") |
| evaluation = metric.compute(params) |
| . |
| . |
| . |
| ```` |
|
|
| You can find the above part in competitions github repo `compute_metrics.py` |
|
|
| `params` is defined as: |
|
|
| ```python |
| class EvalParams(BaseModel): |
| competition_id: str |
| competition_type: str |
| metric: str |
| token: str |
| team_id: str |
| submission_id: str |
| submission_id_col: str |
| submission_cols: List[str] |
| submission_rows: int |
| output_path: str |
| submission_repo: str |
| time_limit: int |
| dataset: str # private test dataset, used only for script competitions |
| ``` |
|
|
| You are free to do whatever you want to in the `compute` function. |
| In the end it must return a dictionary with the following keys: |
|
|
| ```python |
| { |
| "public_score": { |
| "metric1": metric_value, |
| },, |
| "private_score": { |
| "metric1": metric_value, |
| },, |
| } |
| ``` |
|
|
| public and private scores must be dictionaries! You can also use multiple metrics. |
| Example for multiple metrics: |
|
|
| ```python |
| { |
| "public_score": { |
| "metric1": metric_value, |
| "metric2": metric_value, |
| }, |
| "private_score": { |
| "metric1": metric_value, |
| "metric2": metric_value, |
| }, |
| } |
| ``` |
|
|
| Note: When using multiple metrics, conf.json must have `SCORING_METRIC` specified to rank the participants in the competition. |
|
|
| For example, if I want to use metric2 to rank the participants, I will set `SCORING_METRIC` to `metric2` in `conf.json`. |
|
|
| ### Example of a custom metric |
|
|
| ```python |
| import pandas as pd |
| from huggingface_hub import hf_hub_download |
|
|
|
|
| def compute(params): |
| solution_file = hf_hub_download( |
| repo_id=params.competition_id, |
| filename="solution.csv", |
| token=params.token, |
| repo_type="dataset", |
| ) |
|
|
| solution_df = pd.read_csv(solution_file) |
|
|
| submission_filename = f"submissions/{params.team_id}-{params.submission_id}.csv" |
| submission_file = hf_hub_download( |
| repo_id=params.competition_id, |
| filename=submission_filename, |
| token=params.token, |
| repo_type="dataset", |
| ) |
| submission_df = pd.read_csv(submission_file) |
|
|
| public_ids = solution_df[solution_df.split == "public"][params.submission_id_col].values |
| private_ids = solution_df[solution_df.split == "private"][params.submission_id_col].values |
|
|
| public_solution_df = solution_df[solution_df[params.submission_id_col].isin(public_ids)] |
| public_submission_df = submission_df[submission_df[params.submission_id_col].isin(public_ids)] |
|
|
| private_solution_df = solution_df[solution_df[params.submission_id_col].isin(private_ids)] |
| private_submission_df = submission_df[submission_df[params.submission_id_col].isin(private_ids)] |
|
|
| public_solution_df = public_solution_df.sort_values(params.submission_id_col).reset_index(drop=True) |
| public_submission_df = public_submission_df.sort_values(params.submission_id_col).reset_index(drop=True) |
|
|
| private_solution_df = private_solution_df.sort_values(params.submission_id_col).reset_index(drop=True) |
| private_submission_df = private_submission_df.sort_values(params.submission_id_col).reset_index(drop=True) |
|
|
| # CALCULATE METRICS HERE....... |
| # _metric = SOME METRIC FUNCTION |
| target_cols = [col for col in solution_df.columns if col not in [params.submission_id_col, "split"]] |
| public_score = _metric(public_solution_df[target_cols], public_submission_df[target_cols]) |
| private_score = _metric(private_solution_df[target_cols], private_submission_df[target_cols]) |
|
|
| evaluation = { |
| "public_score": { |
| "metric1": public_score, |
| }, |
| "private_score": { |
| "metric1": public_score, |
| } |
| } |
| return evaluation |
| ``` |
|
|
| Take a careful look at the above code. |
| You can see that we are downloading the solution file and the submission file from the dataset repo. |
| We are then calculating the metric on the public and private splits of the solution and submission files. |
| Finally, we are returning the metric values in a dictionary. |
|
|