【问题标题】:How to change multiple Pandas DF columns to categorical without a loop如何在没有循环的情况下将多个 Pandas DF 列更改为分类
【发布时间】:2016-08-29 14:54:32
【问题描述】:

我有一个 DataFrame,我想在其中将几列从“对象”类型更改为“类别”。

float可以同时改变几列,

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

== [更新] ==

既然我知道了诀窍,我在使用循环时没有问题,但我问这个问题是因为我想了解/理解为什么我需要为“类别”而不是浮点数做一个循环,如果有的话没有其他办法。

【问题讨论】:

  • 出于好奇,这有什么意义?速度?
  • @IanS 查看我的更新
  • “未实现”通常意味着它计划用于未来的版本。分类相对较新,因此我们预计 .astype('category) 将来可以用于超过 1 列。

标签: python pandas numpy dataframe categorization


【解决方案1】:

目前尚不清楚dftest[['col1','col2']].astype('category') 的结果应该是什么,即结果列是否应该共享相同的类别。

循环遍历列使每列都有一组单独的类别。 (我相信这是您示例中的预期结果。)

另一方面,.astype(float) 的工作方式不同:它将基础值分解为一维数组,将其转换为浮点数,然后将其重新整形为原始形状。这样它可能比仅迭代列更快。您可以使用更高级别的函数模拟 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]

【讨论】:

  • 谢谢@ptrj,我现在看到问题不在于转换为另一种类型,而是如何处理分类列的级别。我没有想到这一点,但现在对我来说很有意义。感谢您的启发。
【解决方案2】:

你可以这样做:

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() 方法在后台使用循环

【讨论】:

  • 感谢@MaxU,但问题的目的更多是关于“为什么我不能像浮点数一样将类型更改为类别?”。我想知道这是否是我对熊猫知识的限制。查看更新
猜你喜欢
  • 2019-02-08
  • 2019-03-01
  • 1970-01-01
  • 2011-11-02
  • 1970-01-01
  • 2013-07-16
  • 2021-11-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多