Converta dados categóricos no dataframe do pandas

102

Eu tenho um dataframe com este tipo de dados (muitas colunas):

col1        int64
col2        int64
col3        category
col4        category
col5        category

As colunas parecem assim:

Name: col3, dtype: category
Categories (8, object): [B, C, E, G, H, N, S, W]

Eu quero converter todos os valores em colunas para inteiros assim:

[1, 2, 3, 4, 5, 6, 7, 8]

Resolvi isso para uma coluna com o seguinte:

dataframe['c'] = pandas.Categorical.from_array(dataframe.col3).codes

Agora tenho duas colunas em meu dataframe - antigo col3e novo ce preciso descartar colunas antigas.

Essa é uma prática ruim. É trabalho, mas no meu dataframe muitas colunas e eu não quero fazer isso manualmente.

Como fazer isso pythônico e apenas inteligente?

Gilaztdinov Rustam
fonte

Respostas:

163

Primeiro, para converter uma coluna categórico aos seus códigos numéricos, você pode fazer isso mais fácil com: dataframe['c'].cat.codes.
Além disso, é possível selecionar automaticamente todas as colunas com um certo tipo de d em um dataframe usando select_dtypes. Dessa forma, você pode aplicar a operação acima em colunas múltiplas e selecionadas automaticamente.

Primeiro fazendo um exemplo de dataframe:

In [75]: df = pd.DataFrame({'col1':[1,2,3,4,5], 'col2':list('abcab'),  'col3':list('ababb')})

In [76]: df['col2'] = df['col2'].astype('category')

In [77]: df['col3'] = df['col3'].astype('category')

In [78]: df.dtypes
Out[78]:
col1       int64
col2    category
col3    category
dtype: object

Então, usando select_dtypespara selecionar as colunas e, em seguida, aplicando .cat.codesem cada uma dessas colunas, você pode obter o seguinte resultado:

In [80]: cat_columns = df.select_dtypes(['category']).columns

In [81]: cat_columns
Out[81]: Index([u'col2', u'col3'], dtype='object')

In [83]: df[cat_columns] = df[cat_columns].apply(lambda x: x.cat.codes)

In [84]: df
Out[84]:
   col1  col2  col3
0     1     0     0
1     2     1     1
2     3     2     0
3     4     0     1
4     5     1     1
Joris
fonte
14
existe uma maneira fácil de obter um mapeamento entre o código de categoria e os valores de string de categoria?
Allan Ruin
5
Você pode usar: df['col2'].cat.categoriespor exemplo.
ogrisel
13
Indicando para qualquer pessoa preocupada que isso será NaN-1
mapeado
2
Love the 2 liners;)
Jose A
Observe que, se o categórico for ordenado (um ordinal), os códigos numéricos retornados por cat.codesNÃO podem ser os que você vê na Série!
paulperry
27

Isso funciona para mim:

pandas.factorize( ['B', 'C', 'D', 'B'] )[0]

Resultado:

[0, 1, 2, 0]
Scottlittle
fonte
20

Se sua preocupação era apenas fazer uma coluna extra e excluí-la mais tarde, apenas não use uma nova coluna em primeiro lugar.

dataframe = pd.DataFrame({'col1':[1,2,3,4,5], 'col2':list('abcab'),  'col3':list('ababb')})
dataframe.col3 = pd.Categorical.from_array(dataframe.col3).codes

Você terminou. Agora, como Categorical.from_arrayestá obsoleto, use Categoricaldiretamente

dataframe.col3 = pd.Categorical(dataframe.col3).codes

Se você também precisa do mapeamento de volta do índice para o rótulo, há uma maneira ainda melhor para o mesmo

dataframe.col3, mapping_index = pd.Series(dataframe.col3).factorize()

verifique abaixo

print(dataframe)
print(mapping_index.get_loc("c"))
Abhishek
fonte
11

Aqui, várias colunas precisam ser convertidas. Então, uma abordagem que usei é ...

for col_name in df.columns:
    if(df[col_name].dtype == 'object'):
        df[col_name]= df[col_name].astype('category')
        df[col_name] = df[col_name].cat.codes

Isso converte todas as colunas de tipo de string / objeto em categóricas. Em seguida, aplica códigos a cada tipo de categoria.

Shantanu Pathak
fonte
3

Para converter dados categóricos na coluna C dos dados do conjunto de dados , precisamos fazer o seguinte:

from sklearn.preprocessing import LabelEncoder 
labelencoder= LabelEncoder() #initializing an object of class LabelEncoder
data['C'] = labelencoder.fit_transform(data['C']) #fitting and transforming the desired categorical column.
Fatemeh Asgarinejad
fonte
1

@ Quickbeam2k1, veja abaixo -

dataset=pd.read_csv('Data2.csv')
np.set_printoptions(threshold=np.nan)
X = dataset.iloc[:,:].values

Usando sklearn insira a descrição da imagem aqui

from sklearn.preprocessing import LabelEncoder
labelencoder_X=LabelEncoder()
X[:,0] = labelencoder_X.fit_transform(X[:,0])
Prohadoopiano
fonte
3
Por que você simplesmente não corrigiu sua resposta anterior? Surpreendentemente, você está usando fit_transformagora em vez de transform_fite corrigiu a definição do codificador de rótulos. Por que você usa iloc[:,:]? isso é inútil. Qual é a razão por trás da imagem? No caso de você querer me provar e @theGtknerd errado, você falhou.
Quickbeam2k1
1

O que eu faço é, eu replacevalorizo.

Como isso-

df['col'].replace(to_replace=['category_1', 'category_2', 'category_3'], value=[1, 2, 3], inplace=True)

Dessa forma, se a colcoluna tiver valores categóricos, eles serão substituídos pelos valores numéricos.

verdade
fonte
0

Para uma determinada coluna, se você não se importa com a ordem, use este

df['col1_num'] = df['col1'].apply(lambda x: np.where(df['col1'].unique()==x)[0][0])

Se você se preocupa com a ordem, especifique-os como uma lista e use este

df['col1_num'] = df['col1'].apply(lambda x: ['first', 'second', 'third'].index(x))
SaTa
fonte