如何在没有循环的情况下将多个 Pandas DF 列更改为分类
How to change multiple Pandas DF columns to categorical without a loop
我有一个 DataFrame,我想在其中将多个列从类型 'object' 更改为 'category'。
我可以同时为浮动更改多个列,
dftest[['col3', 'col4', 'col5', 'col6']] = \
dftest[['col3', 'col4', 'col5', 'col6']].astype(float)
对于'category'我不能做同样的事情,我需要一个一个地做(或者像一样循环)。
for col in ['col1', 'col2']:
dftest[col] = dftest[col].astype('category')
问题:是否有任何方法可以像 'float' 示例中那样一次对所有需要的列进行更改?
如果我尝试同时做几个专栏,我有:
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
== [更新] ==
既然我知道了诀窍,我使用循环没有问题,但我问这个问题是因为我想 learn/understand 为什么我需要为 'category' 做一个循环并且不是浮动的,如果没有其他方法的话。
你可以这样做:
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()
方法在幕后使用循环
目前还不清楚 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]
我有一个 DataFrame,我想在其中将多个列从类型 'object' 更改为 'category'。
我可以同时为浮动更改多个列,
dftest[['col3', 'col4', 'col5', 'col6']] = \
dftest[['col3', 'col4', 'col5', 'col6']].astype(float)
对于'category'我不能做同样的事情,我需要一个一个地做(或者像
for col in ['col1', 'col2']:
dftest[col] = dftest[col].astype('category')
问题:是否有任何方法可以像 'float' 示例中那样一次对所有需要的列进行更改?
如果我尝试同时做几个专栏,我有:
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
== [更新] ==
既然我知道了诀窍,我使用循环没有问题,但我问这个问题是因为我想 learn/understand 为什么我需要为 'category' 做一个循环并且不是浮动的,如果没有其他方法的话。
你可以这样做:
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()
方法在幕后使用循环
目前还不清楚 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]