2016-08-29 6 views
6

У меня есть DataFrame, где я хочу изменить несколько столбцов от типа 'object' до 'category'.Как изменить несколько столбцов Pandas DF на категориальные без цикла

я могу изменить несколько столбцов одновременно для поплавка,

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

Для «категории» Я не могу это сделать то же самое, что мне нужно сделать один за другим (или в цикле, как here) ,

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

Вопрос: Есть ли способ сделать изменения для всех столбцов хотели сразу, как в примере «поплавок»?

Если я пытаюсь сделать несколько столбцов одновременно у меня есть:

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

Мой текущий код Дрессировка:

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: > 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 

выход:

col1 category 
col2 category 
col3  float64 
col4  float64 
col5  float64 
col6  float64 
dtype: object 

== [обновление] ==

У меня нет проблемы с использованием цикла теперь, когда я знаю трюк, но я задал вопрос, потому что я хотел узнать/понять, ПОЧЕМУ мне нужно сделать цикл для категории, а не для float, если там это не другой способ сделать это.

+3

из любопытства, какой смысл? Скорость? – IanS

+0

@IanS см. Мое обновление –

+1

«Не реализовано» обычно означает, что это планируется для будущей версии. Категориально относительно новые, поэтому мы можем ожидать, что '.astype ('category)' будет работать более чем в 1 столбце в будущем. – ayhan

ответ

2

Это не сразу понятно, что результат dftest[['col1','col2']].astype('category') должен быть, т. е. должны ли результирующие столбцы обладать одинаковыми категориями или нет.

Цитирование по столбцам делает каждый столбец отдельным набором категорий. (Я считаю, что это желаемый результат в вашем примере.)

С другой стороны, .astype(float) работает по-другому: он разделяет базовые значения на 1-й массив, отбрасывает его на плавающие и затем преобразует обратно в исходную форму , Таким образом, это может быть быстрее, чем просто перебирать столбцы. Вы можете эмулировать это поведение для category с высшими функциями уровня:

result = dftest[['col1', 'col2']].stack().astype('category').unstack() 

Но тогда вы получите один набор категорий разделяемого два колонками:

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 < ab < cc < d < g < xx < yy < zz] 
+0

Благодаря @ptrj, теперь я вижу, что проблема заключается не в кастинге на другой тип, а в том, как обрабатывать уровни в случае категориальных столбцов. Я не думал об этом, но теперь мне совершенно понятен. Спасибо за просветление. –

1

вы можете сделать это следующим образом:

In [99]: pd.concat([dftest[['col1', 'col2']].apply(lambda x: x.astype('category')), dftest.ix[:, 'col3':].astype('float')], axis=1) 
Out[99]: 
    col1 col2 col3 col4 col5 col6 
0 a xx 0.30 2.28 0.84 0.31 
1 a xx -0.13 2.04 2.62 0.49 
2 ab xx -0.34 -0.32 -1.87 1.49 
3 ab xx -1.18 -0.57 -0.57 0.87 
4 ab yy 0.66 0.65 0.96 0.07 
5 cc yy 0.88 2.43 0.76 1.93 
6 cc zz 1.81 -1.40 -2.29 -0.13 
7 d zz -0.05 0.60 -0.78 -0.28 
8 d zz -0.36 0.98 0.23 -0.17 
9 g zz -1.31 -0.84 0.02 0.47 

In [100]: pd.concat([dftest[['col1', 'col2']].apply(lambda x: x.astype('category')), dftest.ix[:, 'col3':].astype('float')], axis=1).dtypes 
Out[100]: 
col1 category 
col2 category 
col3  float64 
col4  float64 
col5  float64 
col6  float64 
dtype: object 

, но это не будет много быстрее, поскольку apply() метод использует цикл под капотом

+0

Спасибо @MaxU, но цель вопроса была больше о том, «почему я не могу изменить тип в категории для нескольких столбцов, например, в float?». Я хотел знать, было ли это ограничение моего панды.См. Update –