prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Unnecessary string formatting when saving the model
  https://github.com/mozilla/bugbug/blob/ab007344c5c799c08739b2d56f334afcaf242919/bugbug/model.py#L111 is not needed, we can use the variable directly.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `bugbug/model.py`
  Content:
  ```
  1 # -*- coding: utf-8 -*-
  2 # This Source Code Form is subject to the terms of the Mozilla Public
  3 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
  4 # You can obtain one at http://mozilla.org/MPL/2.0/.
  5 
  6 import numpy as np
  7 import shap
  8 from imblearn.metrics import classification_report_imbalanced
  9 from imblearn.under_sampling import RandomUnderSampler
  10 from sklearn import metrics
  11 from sklearn.externals import joblib
  12 from sklearn.feature_extraction.text import TfidfVectorizer
  13 from sklearn.model_selection import cross_val_score
  14 from sklearn.model_selection import train_test_split
  15 
  16 from bugbug import bugzilla
  17 from bugbug.nlp import SpacyVectorizer
  18 
  19 
  20 class Model():
  21     def __init__(self, lemmatization=False):
  22         if lemmatization:
  23             self.text_vectorizer = SpacyVectorizer
  24         else:
  25             self.text_vectorizer = TfidfVectorizer
  26 
  27         self.undersampling_enabled = True
  28         self.cross_validation_enabled = True
  29 
  30     def get_feature_names(self):
  31         return []
  32 
  33     def train(self):
  34         classes = self.get_labels()
  35         class_names = sorted(list(set(classes.values())), reverse=True)
  36 
  37         # Get bugs, filtering out those for which we have no labels.
  38         def bugs():
  39             return (bug for bug in bugzilla.get_bugs() if bug['id'] in classes)
  40 
  41         # Calculate labels.
  42         y = np.array([classes[bug['id']] for bug in bugs()])
  43 
  44         # Extract features from the bugs.
  45         X = self.extraction_pipeline.fit_transform(bugs())
  46 
  47         print(f'X: {X.shape}, y: {y.shape}')
  48 
  49         # Split dataset in training and test.
  50         X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=0)
  51 
  52         if self.undersampling_enabled:
  53             # Under-sample the majority classes, as the datasets are imbalanced.
  54             X_train, y_train = RandomUnderSampler(random_state=0).fit_sample(X_train, y_train)
  55 
  56         print(f'X_train: {X_train.shape}, y_train: {y_train.shape}')
  57         print(f'X_test: {X_test.shape}, y_test: {y_test.shape}')
  58 
  59         # Use k-fold cross validation to evaluate results.
  60         if self.cross_validation_enabled:
  61             scores = cross_val_score(self.clf, X_train, y_train, cv=5)
  62             print(f'CV Accuracy: f{scores.mean()} (+/- {scores.std() * 2})')
  63 
  64         # Evaluate results on the test set.
  65         self.clf.fit(X_train, y_train)
  66 
  67         feature_names = self.get_feature_names()
  68         if len(feature_names):
  69             explainer = shap.TreeExplainer(self.clf)
  70             shap_values = explainer.shap_values(X_train)
  71 
  72             print('Feature ranking (top 20 features):')
  73             # Calculate the values that represent the fraction of the model output variability attributable
  74             # to each feature across the whole dataset.
  75             shap_sums = np.abs(shap_values).sum(0)
  76             rel_shap_sums = shap_sums / shap_sums.sum()
  77             indices = np.argsort(rel_shap_sums)[::-1][:20]
  78             for i, index in enumerate(indices):
  79                 print(f'{i + 1}. \'{feature_names[index]}\' ({rel_shap_sums[index]})')
  80 
  81         y_pred = self.clf.predict(X_test)
  82 
  83         print(f'No confidence threshold - {len(y_test)} classified')
  84         print(metrics.confusion_matrix(y_test, y_pred, labels=class_names))
  85         print(classification_report_imbalanced(y_test, y_pred, labels=class_names))
  86 
  87         # Evaluate results on the test set for some confidence thresholds.
  88         for confidence_threshold in [0.6, 0.7, 0.8, 0.9]:
  89             y_pred_probas = self.clf.predict_proba(X_test)
  90 
  91             y_test_filter = []
  92             y_pred_filter = []
  93             for i in range(0, len(y_test)):
  94                 argmax = np.argmax(y_pred_probas[i])
  95                 if y_pred_probas[i][argmax] < confidence_threshold:
  96                     continue
  97 
  98                 y_test_filter.append(y_test[i])
  99                 y_pred_filter.append(argmax)
  100 
  101             y_pred_filter = self.clf._le.inverse_transform(y_pred_filter)
  102 
  103             print(f'\nConfidence threshold > {confidence_threshold} - {len(y_test_filter)} classified')
  104             print(metrics.confusion_matrix(y_test_filter, y_pred_filter, labels=class_names))
  105             print(classification_report_imbalanced(y_test_filter, y_pred_filter, labels=class_names))
  106 
  107         joblib.dump(self, f'{self.__class__.__name__.lower()}')
  108 
  109     @staticmethod
  110     def load(model_file_name):
  111         return joblib.load(model_file_name)
  112 
  113     def overwrite_classes(self, bugs, classes, probabilities):
  114         return classes
  115 
  116     def classify(self, bugs, probabilities=False, importances=False):
  117         assert bugs is not None
  118         assert self.extraction_pipeline is not None and self.clf is not None, 'The module needs to be initialized first'
  119 
  120         if not isinstance(bugs, list):
  121             bugs = [bugs]
  122 
  123         assert isinstance(bugs[0], dict)
  124 
  125         X = self.extraction_pipeline.transform(bugs)
  126         if probabilities:
  127             classes = self.clf.predict_proba(X)
  128         else:
  129             classes = self.clf.predict(X)
  130 
  131         classes = self.overwrite_classes(bugs, classes, probabilities)
  132 
  133         if importances:
  134             explainer = shap.TreeExplainer(self.clf)
  135             shap_values = explainer.shap_values(X)
  136 
  137             shap_sums = shap_values.sum(0)
  138             abs_shap_sums = np.abs(shap_sums)
  139             rel_shap_sums = abs_shap_sums / abs_shap_sums.sum()
  140             indices = np.argsort(abs_shap_sums)[::-1]
  141             importances = [(index, shap_sums[index] > 0, rel_shap_sums[index]) for index in indices]
  142 
  143             return classes, importances
  144 
  145         return classes
  146
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/bugbug/model.py b/bugbug/model.py
  --- a/bugbug/model.py
  +++ b/bugbug/model.py
  @@ -104,7 +104,7 @@
               print(metrics.confusion_matrix(y_test_filter, y_pred_filter, labels=class_names))
               print(classification_report_imbalanced(y_test_filter, y_pred_filter, labels=class_names))
   
  -        joblib.dump(self, f'{self.__class__.__name__.lower()}')
  +        joblib.dump(self, self.__class__.__name__.lower())
   
       @staticmethod
       def load(model_file_name):
  
verification_info: {"golden_diff": "diff --git a/bugbug/model.py b/bugbug/model.py\n--- a/bugbug/model.py\n+++ b/bugbug/model.py\n@@ -104,7 +104,7 @@\n             print(metrics.confusion_matrix(y_test_filter, y_pred_filter, labels=class_names))\n             print(classification_report_imbalanced(y_test_filter, y_pred_filter, labels=class_names))\n \n-        joblib.dump(self, f'{self.__class__.__name__.lower()}')\n+        joblib.dump(self, self.__class__.__name__.lower())\n \n     @staticmethod\n     def load(model_file_name):\n", "issue": "Unnecessary string formatting when saving the model\nhttps://github.com/mozilla/bugbug/blob/ab007344c5c799c08739b2d56f334afcaf242919/bugbug/model.py#L111 is not needed, we can use the variable directly.\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n# This Source Code Form is subject to the terms of the Mozilla Public\n# License, v. 2.0. If a copy of the MPL was not distributed with this file,\n# You can obtain one at http://mozilla.org/MPL/2.0/.\n\nimport numpy as np\nimport shap\nfrom imblearn.metrics import classification_report_imbalanced\nfrom imblearn.under_sampling import RandomUnderSampler\nfrom sklearn import metrics\nfrom sklearn.externals import joblib\nfrom sklearn.feature_extraction.text import TfidfVectorizer\nfrom sklearn.model_selection import cross_val_score\nfrom sklearn.model_selection import train_test_split\n\nfrom bugbug import bugzilla\nfrom bugbug.nlp import SpacyVectorizer\n\n\nclass Model():\n    def __init__(self, lemmatization=False):\n        if lemmatization:\n            self.text_vectorizer = SpacyVectorizer\n        else:\n            self.text_vectorizer = TfidfVectorizer\n\n        self.undersampling_enabled = True\n        self.cross_validation_enabled = True\n\n    def get_feature_names(self):\n        return []\n\n    def train(self):\n        classes = self.get_labels()\n        class_names = sorted(list(set(classes.values())), reverse=True)\n\n        # Get bugs, filtering out those for which we have no labels.\n        def bugs():\n            return (bug for bug in bugzilla.get_bugs() if bug['id'] in classes)\n\n        # Calculate labels.\n        y = np.array([classes[bug['id']] for bug in bugs()])\n\n        # Extract features from the bugs.\n        X = self.extraction_pipeline.fit_transform(bugs())\n\n        print(f'X: {X.shape}, y: {y.shape}')\n\n        # Split dataset in training and test.\n        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=0)\n\n        if self.undersampling_enabled:\n            # Under-sample the majority classes, as the datasets are imbalanced.\n            X_train, y_train = RandomUnderSampler(random_state=0).fit_sample(X_train, y_train)\n\n        print(f'X_train: {X_train.shape}, y_train: {y_train.shape}')\n        print(f'X_test: {X_test.shape}, y_test: {y_test.shape}')\n\n        # Use k-fold cross validation to evaluate results.\n        if self.cross_validation_enabled:\n            scores = cross_val_score(self.clf, X_train, y_train, cv=5)\n            print(f'CV Accuracy: f{scores.mean()} (+/- {scores.std() * 2})')\n\n        # Evaluate results on the test set.\n        self.clf.fit(X_train, y_train)\n\n        feature_names = self.get_feature_names()\n        if len(feature_names):\n            explainer = shap.TreeExplainer(self.clf)\n            shap_values = explainer.shap_values(X_train)\n\n            print('Feature ranking (top 20 features):')\n            # Calculate the values that represent the fraction of the model output variability attributable\n            # to each feature across the whole dataset.\n            shap_sums = np.abs(shap_values).sum(0)\n            rel_shap_sums = shap_sums / shap_sums.sum()\n            indices = np.argsort(rel_shap_sums)[::-1][:20]\n            for i, index in enumerate(indices):\n                print(f'{i + 1}. \\'{feature_names[index]}\\' ({rel_shap_sums[index]})')\n\n        y_pred = self.clf.predict(X_test)\n\n        print(f'No confidence threshold - {len(y_test)} classified')\n        print(metrics.confusion_matrix(y_test, y_pred, labels=class_names))\n        print(classification_report_imbalanced(y_test, y_pred, labels=class_names))\n\n        # Evaluate results on the test set for some confidence thresholds.\n        for confidence_threshold in [0.6, 0.7, 0.8, 0.9]:\n            y_pred_probas = self.clf.predict_proba(X_test)\n\n            y_test_filter = []\n            y_pred_filter = []\n            for i in range(0, len(y_test)):\n                argmax = np.argmax(y_pred_probas[i])\n                if y_pred_probas[i][argmax] < confidence_threshold:\n                    continue\n\n                y_test_filter.append(y_test[i])\n                y_pred_filter.append(argmax)\n\n            y_pred_filter = self.clf._le.inverse_transform(y_pred_filter)\n\n            print(f'\\nConfidence threshold > {confidence_threshold} - {len(y_test_filter)} classified')\n            print(metrics.confusion_matrix(y_test_filter, y_pred_filter, labels=class_names))\n            print(classification_report_imbalanced(y_test_filter, y_pred_filter, labels=class_names))\n\n        joblib.dump(self, f'{self.__class__.__name__.lower()}')\n\n    @staticmethod\n    def load(model_file_name):\n        return joblib.load(model_file_name)\n\n    def overwrite_classes(self, bugs, classes, probabilities):\n        return classes\n\n    def classify(self, bugs, probabilities=False, importances=False):\n        assert bugs is not None\n        assert self.extraction_pipeline is not None and self.clf is not None, 'The module needs to be initialized first'\n\n        if not isinstance(bugs, list):\n            bugs = [bugs]\n\n        assert isinstance(bugs[0], dict)\n\n        X = self.extraction_pipeline.transform(bugs)\n        if probabilities:\n            classes = self.clf.predict_proba(X)\n        else:\n            classes = self.clf.predict(X)\n\n        classes = self.overwrite_classes(bugs, classes, probabilities)\n\n        if importances:\n            explainer = shap.TreeExplainer(self.clf)\n            shap_values = explainer.shap_values(X)\n\n            shap_sums = shap_values.sum(0)\n            abs_shap_sums = np.abs(shap_sums)\n            rel_shap_sums = abs_shap_sums / abs_shap_sums.sum()\n            indices = np.argsort(abs_shap_sums)[::-1]\n            importances = [(index, shap_sums[index] > 0, rel_shap_sums[index]) for index in indices]\n\n            return classes, importances\n\n        return classes\n", "path": "bugbug/model.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n# This Source Code Form is subject to the terms of the Mozilla Public\n# License, v. 2.0. If a copy of the MPL was not distributed with this file,\n# You can obtain one at http://mozilla.org/MPL/2.0/.\n\nimport numpy as np\nimport shap\nfrom imblearn.metrics import classification_report_imbalanced\nfrom imblearn.under_sampling import RandomUnderSampler\nfrom sklearn import metrics\nfrom sklearn.externals import joblib\nfrom sklearn.feature_extraction.text import TfidfVectorizer\nfrom sklearn.model_selection import cross_val_score\nfrom sklearn.model_selection import train_test_split\n\nfrom bugbug import bugzilla\nfrom bugbug.nlp import SpacyVectorizer\n\n\nclass Model():\n    def __init__(self, lemmatization=False):\n        if lemmatization:\n            self.text_vectorizer = SpacyVectorizer\n        else:\n            self.text_vectorizer = TfidfVectorizer\n\n        self.undersampling_enabled = True\n        self.cross_validation_enabled = True\n\n    def get_feature_names(self):\n        return []\n\n    def train(self):\n        classes = self.get_labels()\n        class_names = sorted(list(set(classes.values())), reverse=True)\n\n        # Get bugs, filtering out those for which we have no labels.\n        def bugs():\n            return (bug for bug in bugzilla.get_bugs() if bug['id'] in classes)\n\n        # Calculate labels.\n        y = np.array([classes[bug['id']] for bug in bugs()])\n\n        # Extract features from the bugs.\n        X = self.extraction_pipeline.fit_transform(bugs())\n\n        print(f'X: {X.shape}, y: {y.shape}')\n\n        # Split dataset in training and test.\n        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=0)\n\n        if self.undersampling_enabled:\n            # Under-sample the majority classes, as the datasets are imbalanced.\n            X_train, y_train = RandomUnderSampler(random_state=0).fit_sample(X_train, y_train)\n\n        print(f'X_train: {X_train.shape}, y_train: {y_train.shape}')\n        print(f'X_test: {X_test.shape}, y_test: {y_test.shape}')\n\n        # Use k-fold cross validation to evaluate results.\n        if self.cross_validation_enabled:\n            scores = cross_val_score(self.clf, X_train, y_train, cv=5)\n            print(f'CV Accuracy: f{scores.mean()} (+/- {scores.std() * 2})')\n\n        # Evaluate results on the test set.\n        self.clf.fit(X_train, y_train)\n\n        feature_names = self.get_feature_names()\n        if len(feature_names):\n            explainer = shap.TreeExplainer(self.clf)\n            shap_values = explainer.shap_values(X_train)\n\n            print('Feature ranking (top 20 features):')\n            # Calculate the values that represent the fraction of the model output variability attributable\n            # to each feature across the whole dataset.\n            shap_sums = np.abs(shap_values).sum(0)\n            rel_shap_sums = shap_sums / shap_sums.sum()\n            indices = np.argsort(rel_shap_sums)[::-1][:20]\n            for i, index in enumerate(indices):\n                print(f'{i + 1}. \\'{feature_names[index]}\\' ({rel_shap_sums[index]})')\n\n        y_pred = self.clf.predict(X_test)\n\n        print(f'No confidence threshold - {len(y_test)} classified')\n        print(metrics.confusion_matrix(y_test, y_pred, labels=class_names))\n        print(classification_report_imbalanced(y_test, y_pred, labels=class_names))\n\n        # Evaluate results on the test set for some confidence thresholds.\n        for confidence_threshold in [0.6, 0.7, 0.8, 0.9]:\n            y_pred_probas = self.clf.predict_proba(X_test)\n\n            y_test_filter = []\n            y_pred_filter = []\n            for i in range(0, len(y_test)):\n                argmax = np.argmax(y_pred_probas[i])\n                if y_pred_probas[i][argmax] < confidence_threshold:\n                    continue\n\n                y_test_filter.append(y_test[i])\n                y_pred_filter.append(argmax)\n\n            y_pred_filter = self.clf._le.inverse_transform(y_pred_filter)\n\n            print(f'\\nConfidence threshold > {confidence_threshold} - {len(y_test_filter)} classified')\n            print(metrics.confusion_matrix(y_test_filter, y_pred_filter, labels=class_names))\n            print(classification_report_imbalanced(y_test_filter, y_pred_filter, labels=class_names))\n\n        joblib.dump(self, self.__class__.__name__.lower())\n\n    @staticmethod\n    def load(model_file_name):\n        return joblib.load(model_file_name)\n\n    def overwrite_classes(self, bugs, classes, probabilities):\n        return classes\n\n    def classify(self, bugs, probabilities=False, importances=False):\n        assert bugs is not None\n        assert self.extraction_pipeline is not None and self.clf is not None, 'The module needs to be initialized first'\n\n        if not isinstance(bugs, list):\n            bugs = [bugs]\n\n        assert isinstance(bugs[0], dict)\n\n        X = self.extraction_pipeline.transform(bugs)\n        if probabilities:\n            classes = self.clf.predict_proba(X)\n        else:\n            classes = self.clf.predict(X)\n\n        classes = self.overwrite_classes(bugs, classes, probabilities)\n\n        if importances:\n            explainer = shap.TreeExplainer(self.clf)\n            shap_values = explainer.shap_values(X)\n\n            shap_sums = shap_values.sum(0)\n            abs_shap_sums = np.abs(shap_sums)\n            rel_shap_sums = abs_shap_sums / abs_shap_sums.sum()\n            indices = np.argsort(abs_shap_sums)[::-1]\n            importances = [(index, shap_sums[index] > 0, rel_shap_sums[index]) for index in indices]\n\n            return classes, importances\n\n        return classes\n", "path": "bugbug/model.py"}]}