<p dir="auto">Hello,</p>
<p dir="auto">the object <code class="notranslate">sklear.model_selection.GridSearchCV</code> is not picklable:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="from sklearn.model_selection import GridSearchCV
from sklearn.linear_model import Ridge
import pickle

np.random.seed(1)
X = np.random.rand(10, 2)
y = np.random.rand(10)
reg = GridSearchCV(Ridge(), param_grid={&quot;alpha&quot;: [1.0, 2.0]}).fit(X, y)

pickle.loads(pickle.dumps(reg))"><pre class="notranslate"><span class="pl-k">from</span> <span class="pl-s1">sklearn</span>.<span class="pl-s1">model_selection</span> <span class="pl-k">import</span> <span class="pl-v">GridSearchCV</span>
<span class="pl-k">from</span> <span class="pl-s1">sklearn</span>.<span class="pl-s1">linear_model</span> <span class="pl-k">import</span> <span class="pl-v">Ridge</span>
<span class="pl-k">import</span> <span class="pl-s1">pickle</span>

<span class="pl-s1">np</span>.<span class="pl-s1">random</span>.<span class="pl-en">seed</span>(<span class="pl-c1">1</span>)
<span class="pl-v">X</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-s1">random</span>.<span class="pl-en">rand</span>(<span class="pl-c1">10</span>, <span class="pl-c1">2</span>)
<span class="pl-s1">y</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-s1">random</span>.<span class="pl-en">rand</span>(<span class="pl-c1">10</span>)
<span class="pl-s1">reg</span> <span class="pl-c1">=</span> <span class="pl-v">GridSearchCV</span>(<span class="pl-v">Ridge</span>(), <span class="pl-s1">param_grid</span><span class="pl-c1">=</span>{<span class="pl-s">"alpha"</span>: [<span class="pl-c1">1.0</span>, <span class="pl-c1">2.0</span>]}).<span class="pl-en">fit</span>(<span class="pl-v">X</span>, <span class="pl-s1">y</span>)

<span class="pl-s1">pickle</span>.<span class="pl-en">loads</span>(<span class="pl-s1">pickle</span>.<span class="pl-en">dumps</span>(<span class="pl-s1">reg</span>))</pre></div>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
&lt;ipython-input-40-8bf454eb8188&gt; in &lt;module&gt;()
      8 reg = GridSearchCV(Ridge(), param_grid={&quot;alpha&quot;: [1.0, 2.0]}).fit(X, y)
      9 
---&gt; 10 pickle.loads(pickle.dumps(reg))

/opt/rh/python27/root/usr/lib64/python2.7/pickle.pyc in loads(str)
   1380 def loads(str):
   1381     file = StringIO(str)
-&gt; 1382     return Unpickler(file).load()
   1383 
   1384 # Doctest

/opt/rh/python27/root/usr/lib64/python2.7/pickle.pyc in load(self)
    856             while 1:
    857                 key = read(1)
--&gt; 858                 dispatch[key](self)
    859         except _Stop, stopinst:
    860             return stopinst.value

/opt/rh/python27/root/usr/lib64/python2.7/pickle.pyc in load_build(self)
   1215         setstate = getattr(inst, &quot;__setstate__&quot;, None)
   1216         if setstate:
-&gt; 1217             setstate(state)
   1218             return
   1219         slotstate = None

/home/amignon/mypython27/lib/python2.7/site-packages/numpy/ma/core.pyc in __setstate__(self, state)
   5867         &quot;&quot;&quot;
   5868         (_, shp, typ, isf, raw, msk, flv) = state
-&gt; 5869         super(MaskedArray, self).__setstate__((shp, typ, isf, raw))
   5870         self._mask.__setstate__((shp, make_mask_descr(typ), isf, msk))
   5871         self.fill_value = flv

TypeError: object pickle not returning list"><pre class="notranslate"><code class="notranslate">---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
&lt;ipython-input-40-8bf454eb8188&gt; in &lt;module&gt;()
      8 reg = GridSearchCV(Ridge(), param_grid={"alpha": [1.0, 2.0]}).fit(X, y)
      9 
---&gt; 10 pickle.loads(pickle.dumps(reg))

/opt/rh/python27/root/usr/lib64/python2.7/pickle.pyc in loads(str)
   1380 def loads(str):
   1381     file = StringIO(str)
-&gt; 1382     return Unpickler(file).load()
   1383 
   1384 # Doctest

/opt/rh/python27/root/usr/lib64/python2.7/pickle.pyc in load(self)
    856             while 1:
    857                 key = read(1)
--&gt; 858                 dispatch[key](self)
    859         except _Stop, stopinst:
    860             return stopinst.value

/opt/rh/python27/root/usr/lib64/python2.7/pickle.pyc in load_build(self)
   1215         setstate = getattr(inst, "__setstate__", None)
   1216         if setstate:
-&gt; 1217             setstate(state)
   1218             return
   1219         slotstate = None

/home/amignon/mypython27/lib/python2.7/site-packages/numpy/ma/core.pyc in __setstate__(self, state)
   5867         """
   5868         (_, shp, typ, isf, raw, msk, flv) = state
-&gt; 5869         super(MaskedArray, self).__setstate__((shp, typ, isf, raw))
   5870         self._mask.__setstate__((shp, make_mask_descr(typ), isf, msk))
   5871         self.fill_value = flv

TypeError: object pickle not returning list
</code></pre></div>
<p dir="auto">From what I understand, it is caused to a bug in <code class="notranslate">numpy.ma.MaskedArray</code> that I have just reported in <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="184469836" data-permission-text="Title is private" data-url="https://github.com/numpy/numpy/issues/8191" data-hovercard-type="issue" data-hovercard-url="/numpy/numpy/issues/8191/hovercard" href="https://github.com/numpy/numpy/issues/8191">numpy/numpy#8191</a>. It is due to the use of masked arrays in the <code class="notranslate">cv_results_</code> member to store grid parameters:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="p = reg.cv_results_[&quot;param_alpha&quot;]
print repr(p)
pickle.loads(pickle.dumps(reg))"><pre class="notranslate"><span class="pl-s1">p</span> <span class="pl-c1">=</span> <span class="pl-s1">reg</span>.<span class="pl-s1">cv_results_</span>[<span class="pl-s">"param_alpha"</span>]
<span class="pl-k">print</span> <span class="pl-en">repr</span>(<span class="pl-s1">p</span>)
<span class="pl-s1">pickle</span>.<span class="pl-en">loads</span>(<span class="pl-s1">pickle</span>.<span class="pl-en">dumps</span>(<span class="pl-s1">reg</span>))</pre></div>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="masked_array(data = [1.0 2.0],
             mask = [False False],
       fill_value = ?)

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
&lt;ipython-input-45-a128a9cc4ff0&gt; in &lt;module&gt;()
      1 p = reg.cv_results_[&quot;param_alpha&quot;]
      2 print repr(p)
----&gt; 3 pickle.loads(pickle.dumps(reg))

/opt/rh/python27/root/usr/lib64/python2.7/pickle.pyc in loads(str)
   1380 def loads(str):
   1381     file = StringIO(str)
-&gt; 1382     return Unpickler(file).load()
   1383 
   1384 # Doctest

/opt/rh/python27/root/usr/lib64/python2.7/pickle.pyc in load(self)
    856             while 1:
    857                 key = read(1)
--&gt; 858                 dispatch[key](self)
    859         except _Stop, stopinst:
    860             return stopinst.value

/opt/rh/python27/root/usr/lib64/python2.7/pickle.pyc in load_build(self)
   1215         setstate = getattr(inst, &quot;__setstate__&quot;, None)
   1216         if setstate:
-&gt; 1217             setstate(state)
   1218             return
   1219         slotstate = None

/home/amignon/mypython27/lib/python2.7/site-packages/numpy/ma/core.pyc in __setstate__(self, state)
   5867         &quot;&quot;&quot;
   5868         (_, shp, typ, isf, raw, msk, flv) = state
-&gt; 5869         super(MaskedArray, self).__setstate__((shp, typ, isf, raw))
   5870         self._mask.__setstate__((shp, make_mask_descr(typ), isf, msk))
   5871         self.fill_value = flv

TypeError: object pickle not returning list"><pre class="notranslate"><code class="notranslate">masked_array(data = [1.0 2.0],
             mask = [False False],
       fill_value = ?)

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
&lt;ipython-input-45-a128a9cc4ff0&gt; in &lt;module&gt;()
      1 p = reg.cv_results_["param_alpha"]
      2 print repr(p)
----&gt; 3 pickle.loads(pickle.dumps(reg))

/opt/rh/python27/root/usr/lib64/python2.7/pickle.pyc in loads(str)
   1380 def loads(str):
   1381     file = StringIO(str)
-&gt; 1382     return Unpickler(file).load()
   1383 
   1384 # Doctest

/opt/rh/python27/root/usr/lib64/python2.7/pickle.pyc in load(self)
    856             while 1:
    857                 key = read(1)
--&gt; 858                 dispatch[key](self)
    859         except _Stop, stopinst:
    860             return stopinst.value

/opt/rh/python27/root/usr/lib64/python2.7/pickle.pyc in load_build(self)
   1215         setstate = getattr(inst, "__setstate__", None)
   1216         if setstate:
-&gt; 1217             setstate(state)
   1218             return
   1219         slotstate = None

/home/amignon/mypython27/lib/python2.7/site-packages/numpy/ma/core.pyc in __setstate__(self, state)
   5867         """
   5868         (_, shp, typ, isf, raw, msk, flv) = state
-&gt; 5869         super(MaskedArray, self).__setstate__((shp, typ, isf, raw))
   5870         self._mask.__setstate__((shp, make_mask_descr(typ), isf, msk))
   5871         self.fill_value = flv

TypeError: object pickle not returning list
</code></pre></div>
<p dir="auto">So basically it is a cross project bug.</p>
<p dir="auto">Currently, ColumnTransformer will return AttributeError if one of the transformers is a Pipeline object because it only checks if the transformer has get_feature_names attribute.</p>
<h4 dir="auto">Describe the workflow you want to enable</h4>
<p dir="auto">It should be able to pass the initialized column for the Pipeline transformer inside ColumnTransformer.</p>
<h4 dir="auto">Describe your proposed solution</h4>
<p dir="auto">It should check if the transformer is a Pipeline object before checking the attribute, and simply pass the initialized column for the Pipeline transformer.</p>
<h4 dir="auto">Describe alternatives you've considered, if relevant</h4>
<p dir="auto">Alternatively, it can be done by adding get_feature_names attribute to Pipeline object, which will check if the first step has get_feature_names attribute.</p>