Python Pandas - 将一些列类型更改为类别

gin*_*ard 42 python numpy multiple-columns categories pandas

我已将以下CSV文件输入iPython Notebook:

public = pd.read_csv("categories.csv")
public
Run Code Online (Sandbox Code Playgroud)

我还将pandas导入为pd,将numpy导入为np,将matplotlib.pyplot导入为plt.存在以下数据类型(以下是摘要 - 大约有100列)

In [36]:   public.dtypes
Out[37]:   parks          object
           playgrounds    object
           sports         object
           roading        object               
           resident       int64
           children       int64
Run Code Online (Sandbox Code Playgroud)

我希望将"公园","游乐场","体育"和"漫游"更改为类别(他们在其中有类似的比例反应 - 每列都有不同类型的喜欢的回应(例如,一个人"非常同意","同意"等等,另一个具有"非常重要","重要"等等,其余部分为int64.

我能够创建一个单独的数据框 - public1 - 并使用以下代码将其中一列更改为类别类型:

public1 = {'parks': public.parks}
public1 = public1['parks'].astype('category')
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试使用此代码一次更改数字时,我没有成功:

public1 = {'parks': public.parks,
           'playgrounds': public.parks}
public1 = public1['parks', 'playgrounds'].astype('category')
Run Code Online (Sandbox Code Playgroud)

尽管如此,我不想仅使用类别列创建单独的数据框.我想在原始数据框中更改它们.

我尝试了很多方法来实现这一点,然后在这里尝试了代码:Pandas:更改列的数据类型 ...

public[['parks', 'playgrounds', 'sports', 'roading']] = public[['parks', 'playgrounds', 'sports', 'roading']].astype('category')
Run Code Online (Sandbox Code Playgroud)

并得到以下错误:

 NotImplementedError: > 1 ndim Categorical are not supported at this time
Run Code Online (Sandbox Code Playgroud)

有没有办法改变"公园","游乐场","体育","漫步"到类别(这样可以分析比特率的反应),留下"常驻"和"儿童"(以及94个其他列是字符串,int +浮动)请原谅?或者,有更好的方法吗?如果有人有任何建议和/或反馈我会非常感激....我慢慢地去秃头撕开我的头发!

提前谢谢了.

编辑添加 - 我使用的是Python 2.7.

unu*_*tbu 73

有时,您只需使用for循环:

for col in ['parks', 'playgrounds', 'sports', 'roading']:
    public[col] = public[col].astype('category')
Run Code Online (Sandbox Code Playgroud)

  • 如果我遇到错误怎么办?/Users/air/anaconda/lib/python2.7/site-packages/ipykernel/__main__.py:7:SettingWithCopyWarning:尝试在 DataFrame 切片的副本上设置值。尝试使用 .loc[row_indexer,col_indexer] = value 代替 请参阅文档中的警告:http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy (4认同)
  • @JanSila:如果`public`是另一个DataFrame的子DataFrame并且有*从其他DataFrame复制*的数据,你可能会得到'UserWarning`.出于谨慎的考虑,Pandas会发出一个"UserWarning"来警告你修改`public`不会修改其他DataFrame.如果修改其他DataFrame不是您打算做或不是问题,那么您可以自由地忽略UserWarning.如果您希望[沉默UserWarning](http://stackoverflow.com/a/38810015/190597),请在进行"public [col] = ..."形式的分配之前放置`public.is_copy = False`. . (4认同)
  • @JanSila:是的,是的。public.copy()也可以,但是请注意,如果public是一个大型DataFrame,public.copy()可能会比设置flag public.is_copy = False慢得多。(此外,仅当“ public”是副本时,UserWarning才是相关的,因此讽刺的是,为了使警告静音,我们需要再创建一个副本。)另一方面,我不认为“ public.is_copy” =错误的记录在案。我通过阅读源代码找到了它。因此,如果坚持使用记录在案的API是优先事项,则您可能希望使用“ public = public.copy()”。 (3认同)
  • 非常感谢@unutbu,这是一种享受.我简直不敢相信,我觉得现在真的很蠢! (2认同)

小智 36

您可以将该pandas.DataFrame.apply方法与lambda表达式一起使用来解决此问题.在您的示例中,您可以使用

df[['parks', 'playgrounds', 'sports']].apply(lambda x: x.astype('category'))
Run Code Online (Sandbox Code Playgroud)

我不知道有一种方法来执行这个,所以通常我会得到这样的东西:

df[df.select_dtypes(['object']).columns] = df.select_dtypes(['object']).apply(lambda x: x.astype('category'))
Run Code Online (Sandbox Code Playgroud)

显然.select_dtypes,如果您不想选择所有特定数据类型,则可以使用显式列名替换(尽管在您的示例中,您似乎想要所有object类型).


Kev*_*vin 12

从pandas 0.19.0开始,What's New描述了read_csv支持Categorical直接解析列.这个答案只适用于你从read_csv另一个开始,我认为unutbu的答案仍然是最好的.10,000条记录的示例:

import pandas as pd
import numpy as np

# Generate random data, four category-like columns, two int columns
N=10000
categories = pd.DataFrame({
            'parks' : np.random.choice(['strongly agree','agree', 'disagree'], size=N),
            'playgrounds' : np.random.choice(['strongly agree','agree', 'disagree'], size=N),
            'sports' : np.random.choice(['important', 'very important', 'not important'], size=N),
            'roading' : np.random.choice(['important', 'very important', 'not important'], size=N),
            'resident' : np.random.choice([1, 2, 3], size=N),
            'children' : np.random.choice([0, 1, 2, 3], size=N)
                       })
categories.to_csv('categories_large.csv', index=False)
Run Code Online (Sandbox Code Playgroud)

<0.19.0(或> = 19.0,未指定dtype)

pd.read_csv('categories_large.csv').dtypes # inspect default dtypes

children        int64
parks          object
playgrounds    object
resident        int64
roading        object
sports         object
dtype: object
Run Code Online (Sandbox Code Playgroud)

> = 0.19.0

对于混合dtypes解析为Categorical可以通过传递一个字典来实现dtype={'colname' : 'category', ...}read_csv.

pd.read_csv('categories_large.csv', dtype={'parks': 'category',
                                           'playgrounds': 'category',
                                           'sports': 'category',
                                           'roading': 'category'}).dtypes
children          int64
parks          category
playgrounds    category
resident          int64
roading        category
sports         category
dtype: object
Run Code Online (Sandbox Code Playgroud)

性能

稍微加速(本地jupyter笔记本),如发行说明中所述.

# unutbu's answer
%%timeit
public = pd.read_csv('categories_large.csv')
for col in ['parks', 'playgrounds', 'sports', 'roading']:
    public[col] = public[col].astype('category')
10 loops, best of 3: 20.1 ms per loop

# parsed during read_csv
%%timeit
category_cols = {item: 'category' for item in ['parks', 'playgrounds', 'sports', 'roading']}
public = pd.read_csv('categories_large.csv', dtype=category_cols)
100 loops, best of 3: 14.3 ms per loop
Run Code Online (Sandbox Code Playgroud)


Max*_*ers 10

无需循环,Pandas现在可以直接进行操作,只需传递要转换的列列表,Pandas便可以将它们全部转换。

cols = ['parks', 'playgrounds', 'sports', 'roading']:
public[cols] = public[cols].astype('category')
Run Code Online (Sandbox Code Playgroud)
df = pd.DataFrame({'a': ['a', 'b', 'c'], 'b': ['c', 'd', 'e']})

>>     a  b
>>  0  a  c
>>  1  b  d
>>  2  c  e

df.dtypes
>> a    object
>> b    object
>> dtype: object

df[df.columns] = df[df.columns].astype('category')
df.dtypes
>> a    category
>> b    category
>> dtype: object
Run Code Online (Sandbox Code Playgroud)


lia*_*gli 9

让事情变得更容易。不适用。没有地图。没有循环。

cols=data.select_dtypes(exclude='int').columns.to_list()
data[cols]=data[cols].astype('category')
Run Code Online (Sandbox Code Playgroud)