Python Pandas - Изменение некоторых типов столбцов по категориям

Я загрузил следующий CSV файл в iPython Notebook:

public = pd.read_csv("categories.csv")
public

Я также импортировал 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

Я хочу изменить "парки", "игровые площадки", "спорт" и "дорожное движение" на категории (в них есть похожие ответы на шкалу). Каждый столбец имеет разные типы ответов на личность (например, "сильно согласен" ), "соглашаться" и т.д., другой имеет "очень важный", "важный" и т.д.), оставив остаток как int64.

Мне удалось создать отдельный файл данных - public1 - и изменить один из столбцов на тип категории, используя следующий код:

public1 = {'parks': public.parks}
public1 = public1['parks'].astype('category')

Однако, когда я попытался изменить номер сразу с помощью этого кода, я не увенчался успехом:

public1 = {'parks': public.parks,
           'playgrounds': public.parks}
public1 = public1['parks', 'playgrounds'].astype('category')

Несмотря на это, я не хочу создавать отдельный фреймворк с только столбцами категорий. Я бы хотел, чтобы они были изменены в исходном фрейме данных.

Я попробовал множество способов добиться этого, а затем попробовал код здесь: Pandas: изменить тип данных столбцов...

public[['parks', 'playgrounds', 'sports', 'roading']] = public[['parks', 'playgrounds', 'sports', 'roading']].astype('category')

и получил следующую ошибку:

 NotImplementedError: > 1 ndim Categorical are not supported at this time

Есть ли способ изменить "парки", "игровые площадки", "спорт", "дорожное движение" по категориям (поэтому затем можно проанализировать ответы на шкалу ответов "), оставив" резидент "и" детей "(и 94 другие столбцы, которые являются строками, int + floats) нетронутыми, пожалуйста? Или, есть ли лучший способ сделать это? Если у кого-нибудь есть предложения и/или отзывы, я был бы очень благодарен.... Я медленно собираюсь лысым, вырывая мои волосы!

Большое спасибо заранее.

отредактирован для добавления - я использую Python 2.7.

Ответ 1

Иногда вам просто нужно использовать for-loop:

for col in ['parks', 'playgrounds', 'sports', 'roading']:
    public[col] = public[col].astype('category')

Ответ 2

Вы можете использовать метод pandas.DataFrame.apply вместе с выражением lambda, чтобы решить эту проблему. В вашем примере вы можете использовать

df[['parks', 'playgrounds', 'sports']].apply(lambda x: x.astype('category'))

Я не знаю, как это выполнить на месте, поэтому обычно я получаю что-то вроде этого:

df[df.select_dtypes(['object']).columns] = df.select_dtypes(['object']).apply(lambda x: x.astype('category'))

Очевидно, вы можете заменить .select_dtypes на явные имена столбцов, если вы не хотите выбирать все определенные типы данных (хотя в вашем примере кажется, что вам нужны все типы object).

Ответ 3

Как и в pandas 0.19.0, Что нового описывает, что 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)

< 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

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

Производительность

Небольшое ускорение (локальный блокнот jupyter), как указано в примечаниях к выпуску.

# unutbu 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

Ответ 4

Я обнаружил, что использование цикла for работает хорошо.

for col in ['col_variable_name_1', 'col_variable_name_2', ect..]:
    dataframe_name[col] = dataframe_name[col].astype(float)

Ответ 5

Блокнот Jupyter

В моем случае у меня был большой Dataframe со многими объектами, которые я хотел бы преобразовать в категорию.

Поэтому я выбрал столбцы объекта и заполнил все, что нет в NA, а затем сохранил его в исходном кадре данных, как в

# Convert Object Columns to Categories
obj_df =df.select_dtypes(include=['object']).copy()
obj_df=obj_df.fillna('Missing')
for col in obj_df:
    obj_df[col] = obj_df[col].astype('category')
df[obj_df.columns]=obj_df[obj_df.columns]
df.head()

Я надеюсь, что это может быть полезным ресурсом для дальнейшего использования

Ответ 6

Нет необходимости в циклах, Pandas может сделать это прямо сейчас, просто передайте список столбцов, которые вы хотите преобразовать, и Pandas преобразует их все.

cols = ['parks', 'playgrounds', 'sports', 'roading']:
public[cols] = public[cols].astype('category')

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