How to change multiple Pandas DF columns to categorical without a loop
<p>I have a DataFrame where I want to change several columns from type 'object' to 'category'.</p>

<p>I can change several columns at the same time for float, </p>

<pre><code>dftest[['col3', 'col4', 'col5', 'col6']] = \
    dftest[['col3', 'col4', 'col5', 'col6']].astype(float)
</code></pre>

<p>For 'category' I can not do it the same, I need to do one by one (or in a loop like <a href="http://stackoverflow.com/a/28910914/427129">here</a>).</p>

<pre><code>for col in ['col1', 'col2']:
    dftest[col] = dftest[col].astype('category')
</code></pre>

<p>Question: Is there any way of doing the change for all wanted columns at once like in the 'float' example?</p>

<p>If I try to do several columns at the same time I have:</p>

<pre><code>dftest[['col1','col2']] = dftest[['col1','col2']].astype('category')
## NotImplementedError: &gt; 1 ndim Categorical are not supported at this time
</code></pre>

<p>My current working test code: </p>

<pre><code>import numpy as np
import pandas as pd 

factors= np.array([
        ['a', 'xx'],
        ['a', 'xx'],
        ['ab', 'xx'],
        ['ab', 'xx'],
        ['ab', 'yy'],
        ['cc', 'yy'],
        ['cc', 'zz'],
        ['d', 'zz'],
        ['d', 'zz'],
        ['g', 'zz'] 
        ])

values = np.random.randn(10,4).round(2)

dftest = pd.DataFrame(np.hstack([factors,values]), 
                  columns = ['col1', 'col2', 'col3', 'col4', 'col5', 'col6'])

#dftest[['col1','col2']] = dftest[['col1','col2']].astype('category')
## NotImplementedError: &gt; 1 ndim Categorical are not supported at this time

## it works with individual astype
#dftest['col2'] = dftest['col2'].astype('category')
#dftest['col1'] = dftest['col1'].astype('category')

print(dftest)

## doing a loop
for col in ['col1', 'col2']:
    dftest[col] = dftest[col].astype('category')


dftest[['col3', 'col4', 'col5', 'col6']] = \
    dftest[['col3', 'col4', 'col5', 'col6']].astype(float)

dftest.dtypes
</code></pre>

<hr>

<p>output:</p>

<pre><code>col1    category
col2    category
col3     float64
col4     float64
col5     float64
col6     float64
dtype: object
</code></pre>

<p>== [update] ==</p>

<p>I don't have a problem using the loop now that I know the trick, but I asked the question because I wanted to learn/understand WHY I need to do a loop for 'category' and not for float, if there is no other way of doing it.</p>

<p>It's not immediately clear what the result of <code>dftest[['col1','col2']].astype('category')</code> should be, i.e. whether the resulting columns should share the same categories or not.</p>

<p>Looping over columns make each column have a separate set of categories. (I believe this is a desired result in your example.) </p>

<p>On the other hand, <code>.astype(float)</code> works differently: it ravels the underlying values to a 1d array, casts it to floats, and then reshape it back to the original shape. This way it may be faster than just iterating over columns. You can emulate this behaviour for <code>category</code> with higher level functions:</p>

<pre><code>result = dftest[['col1', 'col2']].stack().astype('category').unstack()
</code></pre>

<p>But then you get a single set of categories shared by the both columns:</p>

<pre><code>result['col1']
Out[36]: 
0     a
1     a
2    ab
3    ab
4    ab
5    cc
6    cc
7     d
8     d
9     g
Name: col1, dtype: category
Categories (8, object): [a &lt; ab &lt; cc &lt; d &lt; g &lt; xx &lt; yy &lt; zz]
</code></pre>

python pandas numpy dataframe categorization