<p dir="auto">Training models might take considerable amounts of time and energy, but with every upgrade of sklearn one currently might lose the ability to use a model trained with an older release version.</p>
<p dir="auto">While this is mentioned in the <a href="http://scikit-learn.org/stable/modules/model_persistence.html#security-maintainability-limitations" rel="nofollow">docs</a>, i still find it upsetting, as i can either pin sklearn to some old version or re-train all models and use an up-to-date sklearn. Re-training also might make it necessary to keep large amounts of training data around and ship them to all machines, potentially with parameters found by grid-search on previous versions to at least save grid-search times.</p>
<p dir="auto">For example, i have a GradientBoostingClassifier model from 0.18.1 that now causes this userwarning:</p>
<blockquote>
<p dir="auto">Trying to unpickle estimator GradientBoostingClassifier from version 0.18.1 when using version 0.19.1. This might lead to breaking code or invalid results. Use at your own risk.</p>
</blockquote>
<p dir="auto">When trying to actually use the model the result is:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="AttributeError: 'GradientBoostingClassifier' object has no attribute 'n_features_'"><pre class="notranslate"><code class="notranslate">AttributeError: 'GradientBoostingClassifier' object has no attribute 'n_features_'
</code></pre></div>
<p dir="auto">From my guess, this is mainly an issue of using pickle on the model object (which is currently the recommended way to serialize models): every rename of model properties in the source will cause a whole lot of trouble when loading a model object pre-dating that change, as the methods won't find the properties anymore.</p>
<p dir="auto">At the same time i think that the underlying idea of an estimator changes rather rarely.</p>
<p dir="auto">Would there be any interest in providing high-level <code class="notranslate">save</code> and <code class="notranslate">load</code> functionality that decouples the run-time model mechanics a bit more from its serialization and focuses more on longevity?</p>
<p dir="auto">while running below statement i am getting exception:<br>
for i, c in enumerate(clusters):<br>
print('Cluster {} has {} members: {}...'.format(i, len(c), c[0]))</p>
<h2 dir="auto">Exception:</h2>
<p dir="auto">KeyError                                  Traceback (most recent call last)<br>
~/anaconda3/lib/python3.6/site-packages/pandas/core/indexes/base.py in get_loc(self, key, method, tolerance)<br>
3062             try:<br>
-&gt; 3063                 return self._engine.get_loc(key)<br>
3064             except KeyError:</p>
<p dir="auto">pandas/_libs/index.pyx in pandas._libs.index.IndexEngine.get_loc()</p>
<p dir="auto">pandas/_libs/index.pyx in pandas._libs.index.IndexEngine.get_loc()</p>
<p dir="auto">pandas/_libs/hashtable_class_helper.pxi in pandas._libs.hashtable.Int64HashTable.get_item()</p>
<p dir="auto">pandas/_libs/hashtable_class_helper.pxi in pandas._libs.hashtable.Int64HashTable.get_item()</p>
<p dir="auto">KeyError: 0</p>
<p dir="auto">During handling of the above exception, another exception occurred:</p>
<p dir="auto">KeyError                                  Traceback (most recent call last)<br>
 in ()<br>
22<br>
23 for i, c in enumerate(clusters): ## To get the values printed along with their index I can use Python's enumerate function<br>
---&gt; 24   print('Cluster {} has {} members: {}...'.format(i, len(c), c[0]))<br>
25<br>
26 # which prints</p>
<p dir="auto">~/anaconda3/lib/python3.6/site-packages/pandas/core/frame.py in <strong>getitem</strong>(self, key)<br>
2683             return self._getitem_multilevel(key)<br>
2684         else:<br>
-&gt; 2685             return self._getitem_column(key)<br>
2686<br>
2687     def _getitem_column(self, key):</p>
<p dir="auto">~/anaconda3/lib/python3.6/site-packages/pandas/core/frame.py in _getitem_column(self, key)<br>
2690         # get column<br>
2691         if self.columns.is_unique:<br>
-&gt; 2692             return self._get_item_cache(key)<br>
2693<br>
2694         # duplicate columns &amp; possible reduce dimensionality</p>
<p dir="auto">~/anaconda3/lib/python3.6/site-packages/pandas/core/generic.py in _get_item_cache(self, item)<br>
2484         res = cache.get(item)<br>
2485         if res is None:<br>
-&gt; 2486             values = self._data.get(item)<br>
2487             res = self._box_item_values(item, values)<br>
2488             cache[item] = res</p>
<p dir="auto">~/anaconda3/lib/python3.6/site-packages/pandas/core/internals.py in get(self, item, fastpath)<br>
4113<br>
4114             if not isna(item):<br>
-&gt; 4115                 loc = self.items.get_loc(item)<br>
4116             else:<br>
4117                 indexer = np.arange(len(self.items))[isna(self.items)]</p>
<p dir="auto">~/anaconda3/lib/python3.6/site-packages/pandas/core/indexes/base.py in get_loc(self, key, method, tolerance)<br>
3063                 return self._engine.get_loc(key)<br>
3064             except KeyError:<br>
-&gt; 3065                 return self._engine.get_loc(self._maybe_cast_indexer(key))<br>
3066<br>
3067         indexer = self.get_indexer([key], method=method, tolerance=tolerance)</p>
<p dir="auto">pandas/_libs/index.pyx in pandas._libs.index.IndexEngine.get_loc()</p>
<p dir="auto">pandas/_libs/index.pyx in pandas._libs.index.IndexEngine.get_loc()</p>
<p dir="auto">pandas/_libs/hashtable_class_helper.pxi in pandas._libs.hashtable.Int64HashTable.get_item()</p>
<p dir="auto">pandas/_libs/hashtable_class_helper.pxi in pandas._libs.hashtable.Int64HashTable.get_item()</p>
<p dir="auto">KeyError: 0</p>