prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Make `column_importances` optional
  If the column importance module gets automatically disabled (see #681) an issue may arise where the information required for a `ModelAnalysis` object is not available. Example stacktrace:
  
  ```python
  ---------------------------------------------------------------------------
  KeyError                                  Traceback (most recent call last)
  <ipython-input-10-b3f165881113> in <module>
       16 
       17 # Analyze the ensembles
  ---> 18 predictor.analyze_ensemble(enc_data)
  
  /tmp/b380bd15a0ec89f57a82f719f514e67f0cae00fe7d0085d816353697296992059.py in analyze_ensemble(self, enc_data)
     1439         # --------------- #
     1440         log.info("Analyzing the ensemble of mixers")
  -> 1441         self.model_analysis, self.runtime_analyzer = model_analyzer(
     1442             data=encoded_test_data,
     1443             train_data=encoded_train_data,
  
  ~/Documents/lightwood/lightwood/analysis/analyze.py in model_analyzer(predictor, data, train_data, stats_info, target, ts_cfg, dtype_dict, accuracy_functions, analysis_blocks)
       91         test_sample_size=len(encoded_val_data),
       92         confusion_matrix=runtime_analyzer['cm'],
  ---> 93         column_importances=runtime_analyzer['column_importances'],
       94         histograms=stats_info.histograms,
       95         dtypes=dtype_dict
  
  KeyError: 'column_importances'
  ```
  
  
  </issue>
  <code>
  [start of lightwood/analysis/analyze.py]
  1 from typing import Dict, List, Tuple, Optional
  2 
  3 from lightwood.helpers.log import log
  4 from lightwood.api import dtype
  5 from lightwood.ensemble import BaseEnsemble
  6 from lightwood.analysis.base import BaseAnalysisBlock
  7 from lightwood.data.encoded_ds import EncodedDs
  8 from lightwood.encoder.text.pretrained import PretrainedLangEncoder
  9 from lightwood.api.types import ModelAnalysis, StatisticalAnalysis, TimeseriesSettings, PredictionArguments
  10 
  11 
  12 def model_analyzer(
  13     predictor: BaseEnsemble,
  14     data: EncodedDs,
  15     train_data: EncodedDs,
  16     stats_info: StatisticalAnalysis,
  17     target: str,
  18     ts_cfg: TimeseriesSettings,
  19     dtype_dict: Dict[str, str],
  20     accuracy_functions,
  21     analysis_blocks: Optional[List[BaseAnalysisBlock]] = []
  22 ) -> Tuple[ModelAnalysis, Dict[str, object]]:
  23     """
  24     Analyses model on a validation subset to evaluate accuracy, estimate feature importance and generate a
  25     calibration model to estimating confidence in future predictions.
  26 
  27     Additionally, any user-specified analysis blocks (see class `BaseAnalysisBlock`) are also called here.
  28 
  29     :return:
  30     runtime_analyzer: This dictionary object gets populated in a sequential fashion with data generated from
  31     any `.analyze()` block call. This dictionary object is stored in the predictor itself, and used when
  32     calling the `.explain()` method of all analysis blocks when generating predictions.
  33 
  34     model_analysis: `ModelAnalysis` object that contains core analysis metrics, not necessarily needed when predicting.
  35     """
  36 
  37     runtime_analyzer = {}
  38     data_type = dtype_dict[target]
  39 
  40     # retrieve encoded data representations
  41     encoded_train_data = train_data
  42     encoded_val_data = data
  43     data = encoded_val_data.data_frame
  44     input_cols = list([col for col in data.columns if col != target])
  45 
  46     # predictive task
  47     is_numerical = data_type in (dtype.integer, dtype.float, dtype.array, dtype.tsarray, dtype.quantity)
  48     is_classification = data_type in (dtype.categorical, dtype.binary)
  49     is_multi_ts = ts_cfg.is_timeseries and ts_cfg.nr_predictions > 1
  50     has_pretrained_text_enc = any([isinstance(enc, PretrainedLangEncoder)
  51                                    for enc in encoded_train_data.encoders.values()])
  52 
  53     # raw predictions for validation dataset
  54     args = {} if not is_classification else {"predict_proba": True}
  55     normal_predictions = predictor(encoded_val_data, args=PredictionArguments.from_dict(args))
  56     normal_predictions = normal_predictions.set_index(data.index)
  57 
  58     # ------------------------- #
  59     # Run analysis blocks, both core and user-defined
  60     # ------------------------- #
  61     kwargs = {
  62         'predictor': predictor,
  63         'target': target,
  64         'input_cols': input_cols,
  65         'dtype_dict': dtype_dict,
  66         'normal_predictions': normal_predictions,
  67         'data': data,
  68         'train_data': train_data,
  69         'encoded_val_data': encoded_val_data,
  70         'is_classification': is_classification,
  71         'is_numerical': is_numerical,
  72         'is_multi_ts': is_multi_ts,
  73         'stats_info': stats_info,
  74         'ts_cfg': ts_cfg,
  75         'accuracy_functions': accuracy_functions,
  76         'has_pretrained_text_enc': has_pretrained_text_enc
  77     }
  78 
  79     for block in analysis_blocks:
  80         log.info("The block %s is now running its analyze() method", block.__class__.__name__)
  81         runtime_analyzer = block.analyze(runtime_analyzer, **kwargs)
  82 
  83     # ------------------------- #
  84     # Populate ModelAnalysis object
  85     # ------------------------- #
  86     model_analysis = ModelAnalysis(
  87         accuracies=runtime_analyzer['score_dict'],
  88         accuracy_histogram=runtime_analyzer['acc_histogram'],
  89         accuracy_samples=runtime_analyzer['acc_samples'],
  90         train_sample_size=len(encoded_train_data),
  91         test_sample_size=len(encoded_val_data),
  92         confusion_matrix=runtime_analyzer['cm'],
  93         column_importances=runtime_analyzer['column_importances'],
  94         histograms=stats_info.histograms,
  95         dtypes=dtype_dict
  96     )
  97 
  98     return model_analysis, runtime_analyzer
  99
  [end of lightwood/analysis/analyze.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/lightwood/analysis/analyze.py b/lightwood/analysis/analyze.py
  --- a/lightwood/analysis/analyze.py
  +++ b/lightwood/analysis/analyze.py
  @@ -84,13 +84,13 @@
       # Populate ModelAnalysis object
       # ------------------------- #
       model_analysis = ModelAnalysis(
  -        accuracies=runtime_analyzer['score_dict'],
  -        accuracy_histogram=runtime_analyzer['acc_histogram'],
  -        accuracy_samples=runtime_analyzer['acc_samples'],
  +        accuracies=runtime_analyzer.get('score_dict', {}),
  +        accuracy_histogram=runtime_analyzer.get('acc_histogram', {}),
  +        accuracy_samples=runtime_analyzer.get('acc_samples', {}),
           train_sample_size=len(encoded_train_data),
           test_sample_size=len(encoded_val_data),
           confusion_matrix=runtime_analyzer['cm'],
  -        column_importances=runtime_analyzer['column_importances'],
  +        column_importances=runtime_analyzer.get('column_importances', {}),
           histograms=stats_info.histograms,
           dtypes=dtype_dict
       )
  
verification_info: {"golden_diff": "diff --git a/lightwood/analysis/analyze.py b/lightwood/analysis/analyze.py\n--- a/lightwood/analysis/analyze.py\n+++ b/lightwood/analysis/analyze.py\n@@ -84,13 +84,13 @@\n     # Populate ModelAnalysis object\n     # ------------------------- #\n     model_analysis = ModelAnalysis(\n-        accuracies=runtime_analyzer['score_dict'],\n-        accuracy_histogram=runtime_analyzer['acc_histogram'],\n-        accuracy_samples=runtime_analyzer['acc_samples'],\n+        accuracies=runtime_analyzer.get('score_dict', {}),\n+        accuracy_histogram=runtime_analyzer.get('acc_histogram', {}),\n+        accuracy_samples=runtime_analyzer.get('acc_samples', {}),\n         train_sample_size=len(encoded_train_data),\n         test_sample_size=len(encoded_val_data),\n         confusion_matrix=runtime_analyzer['cm'],\n-        column_importances=runtime_analyzer['column_importances'],\n+        column_importances=runtime_analyzer.get('column_importances', {}),\n         histograms=stats_info.histograms,\n         dtypes=dtype_dict\n     )\n", "issue": "Make `column_importances` optional\nIf the column importance module gets automatically disabled (see #681) an issue may arise where the information required for a `ModelAnalysis` object is not available. Example stacktrace:\r\n\r\n```python\r\n---------------------------------------------------------------------------\r\nKeyError                                  Traceback (most recent call last)\r\n<ipython-input-10-b3f165881113> in <module>\r\n     16 \r\n     17 # Analyze the ensembles\r\n---> 18 predictor.analyze_ensemble(enc_data)\r\n\r\n/tmp/b380bd15a0ec89f57a82f719f514e67f0cae00fe7d0085d816353697296992059.py in analyze_ensemble(self, enc_data)\r\n   1439         # --------------- #\r\n   1440         log.info(\"Analyzing the ensemble of mixers\")\r\n-> 1441         self.model_analysis, self.runtime_analyzer = model_analyzer(\r\n   1442             data=encoded_test_data,\r\n   1443             train_data=encoded_train_data,\r\n\r\n~/Documents/lightwood/lightwood/analysis/analyze.py in model_analyzer(predictor, data, train_data, stats_info, target, ts_cfg, dtype_dict, accuracy_functions, analysis_blocks)\r\n     91         test_sample_size=len(encoded_val_data),\r\n     92         confusion_matrix=runtime_analyzer['cm'],\r\n---> 93         column_importances=runtime_analyzer['column_importances'],\r\n     94         histograms=stats_info.histograms,\r\n     95         dtypes=dtype_dict\r\n\r\nKeyError: 'column_importances'\r\n```\r\n\n", "before_files": [{"content": "from typing import Dict, List, Tuple, Optional\n\nfrom lightwood.helpers.log import log\nfrom lightwood.api import dtype\nfrom lightwood.ensemble import BaseEnsemble\nfrom lightwood.analysis.base import BaseAnalysisBlock\nfrom lightwood.data.encoded_ds import EncodedDs\nfrom lightwood.encoder.text.pretrained import PretrainedLangEncoder\nfrom lightwood.api.types import ModelAnalysis, StatisticalAnalysis, TimeseriesSettings, PredictionArguments\n\n\ndef model_analyzer(\n    predictor: BaseEnsemble,\n    data: EncodedDs,\n    train_data: EncodedDs,\n    stats_info: StatisticalAnalysis,\n    target: str,\n    ts_cfg: TimeseriesSettings,\n    dtype_dict: Dict[str, str],\n    accuracy_functions,\n    analysis_blocks: Optional[List[BaseAnalysisBlock]] = []\n) -> Tuple[ModelAnalysis, Dict[str, object]]:\n    \"\"\"\n    Analyses model on a validation subset to evaluate accuracy, estimate feature importance and generate a\n    calibration model to estimating confidence in future predictions.\n\n    Additionally, any user-specified analysis blocks (see class `BaseAnalysisBlock`) are also called here.\n\n    :return:\n    runtime_analyzer: This dictionary object gets populated in a sequential fashion with data generated from\n    any `.analyze()` block call. This dictionary object is stored in the predictor itself, and used when\n    calling the `.explain()` method of all analysis blocks when generating predictions.\n\n    model_analysis: `ModelAnalysis` object that contains core analysis metrics, not necessarily needed when predicting.\n    \"\"\"\n\n    runtime_analyzer = {}\n    data_type = dtype_dict[target]\n\n    # retrieve encoded data representations\n    encoded_train_data = train_data\n    encoded_val_data = data\n    data = encoded_val_data.data_frame\n    input_cols = list([col for col in data.columns if col != target])\n\n    # predictive task\n    is_numerical = data_type in (dtype.integer, dtype.float, dtype.array, dtype.tsarray, dtype.quantity)\n    is_classification = data_type in (dtype.categorical, dtype.binary)\n    is_multi_ts = ts_cfg.is_timeseries and ts_cfg.nr_predictions > 1\n    has_pretrained_text_enc = any([isinstance(enc, PretrainedLangEncoder)\n                                   for enc in encoded_train_data.encoders.values()])\n\n    # raw predictions for validation dataset\n    args = {} if not is_classification else {\"predict_proba\": True}\n    normal_predictions = predictor(encoded_val_data, args=PredictionArguments.from_dict(args))\n    normal_predictions = normal_predictions.set_index(data.index)\n\n    # ------------------------- #\n    # Run analysis blocks, both core and user-defined\n    # ------------------------- #\n    kwargs = {\n        'predictor': predictor,\n        'target': target,\n        'input_cols': input_cols,\n        'dtype_dict': dtype_dict,\n        'normal_predictions': normal_predictions,\n        'data': data,\n        'train_data': train_data,\n        'encoded_val_data': encoded_val_data,\n        'is_classification': is_classification,\n        'is_numerical': is_numerical,\n        'is_multi_ts': is_multi_ts,\n        'stats_info': stats_info,\n        'ts_cfg': ts_cfg,\n        'accuracy_functions': accuracy_functions,\n        'has_pretrained_text_enc': has_pretrained_text_enc\n    }\n\n    for block in analysis_blocks:\n        log.info(\"The block %s is now running its analyze() method\", block.__class__.__name__)\n        runtime_analyzer = block.analyze(runtime_analyzer, **kwargs)\n\n    # ------------------------- #\n    # Populate ModelAnalysis object\n    # ------------------------- #\n    model_analysis = ModelAnalysis(\n        accuracies=runtime_analyzer['score_dict'],\n        accuracy_histogram=runtime_analyzer['acc_histogram'],\n        accuracy_samples=runtime_analyzer['acc_samples'],\n        train_sample_size=len(encoded_train_data),\n        test_sample_size=len(encoded_val_data),\n        confusion_matrix=runtime_analyzer['cm'],\n        column_importances=runtime_analyzer['column_importances'],\n        histograms=stats_info.histograms,\n        dtypes=dtype_dict\n    )\n\n    return model_analysis, runtime_analyzer\n", "path": "lightwood/analysis/analyze.py"}]}