Python Pandas-zmiana niektórych typów kolumn na kategorie

Dodałem następujący plik CSV do notatnika iPython:

public = pd.read_csv("categories.csv")
public
Importowałem też pandy jako pd, numpy jako np i matplotlib.pyplot jako plt. Istnieją następujące typy danych (Poniżej jest podsumowanie - jest około 100 kolumn)
In [36]:   public.dtypes
Out[37]:   parks          object
           playgrounds    object
           sports         object
           roading        object               
           resident       int64
           children       int64

Chcę zmienić 'parki', 'place zabaw', ' Sport 'i' roading ' na kategorie (mają w nich odpowiedzi w skali Likerta - każda kolumna ma różne typy odpowiedzi Likerta (np.", "zgadzam się" itp., inny ma "bardzo ważne", "ważne" itp.), pozostawiając pozostałą część jako int64.

Udało mi się utworzyć oddzielną ramkę danych-public1 - I zmienić jedną z kolumn na typ kategorii za pomocą następującego kodu:

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

Jednak, gdy próbowałem zmienić numer na raz za pomocą tego kodu, nie udało mi się:

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

Niezależnie od tego, nie chcę tworzyć oddzielnej ramki danych z kolumnami kategorii. Chciałbym je zmienić w oryginalny dataframe.

Próbowałem wielu sposobów, aby to osiągnąć, a następnie wypróbowałem kod tutaj: Pandas: Zmień typ danych kolumn...

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

I otrzymałem następujący błąd:

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

Czy istnieje sposób, aby zmienić "parki", "place zabaw", "Sport", "roading" na kategorie (tak, aby można było analizować odpowiedzi skali Likerta), pozostawiając "rezydentów" i "dzieci" (I 94 inne kolumny, które są string, int + floats) nietknięte proszę? Czy jest na to lepszy sposób? Jeśli ktoś ma jakieś sugestie i / lub opinie byłbym najbardziej grateful....am powoli łysieję wyrywając mi włosy!

Z góry dziękuję.

Edited to add-używam Pythona 2.7.

Author: Community, 2015-03-07

7 answers

Czasami wystarczy użyć pętli for:

for col in ['parks', 'playgrounds', 'sports', 'roading']:
    public[col] = public[col].astype('category')
 111
Author: unutbu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-10 18:47:11

Możesz użyć metody pandas.DataFrame.apply wraz z wyrażeniem lambda, aby rozwiązać ten problem. W twoim przykładzie możesz użyć

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

Nie znam sposobu na wykonanie tego w miejscu, więc zazwyczaj skończę z czymś takim:

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

Oczywiście możesz zastąpić .select_dtypes jawnymi nazwami kolumn, jeśli nie chcesz wybierać wszystkich określonych typów danych (chociaż w twoim przykładzie wygląda na to, że chciałeś wszystkich typów object).

 45
Author: Derek Kaknes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-13 22:04:36

Nie ma potrzeby stosowania pętli, Pandy mogą to zrobić bezpośrednio teraz, po prostu podaj listę kolumn, które chcesz przekonwertować, a Pandy przekonwertują je wszystkie.

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
 44
Author: Maximilian Peters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-02-11 05:37:03

Od wersji pandas 0.19.0, Co nowego opisuje, że read_csv obsługuje bezpośrednio parsowanie kolumn Categorical. Ta odpowiedź ma zastosowanie tylko wtedy, gdy zaczynasz od read_csv w przeciwnym razie, myślę, że odpowiedź unutbu jest nadal najlepsza. Przykład na 10 000 rekordów:

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)

=19.0 bez podania 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

Dla mieszanego dtypes parsowanie jako Categorical może być zaimplementowane przez podanie słownika dtype={'colname' : 'category', ...} w 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

Wydajność

Lekki speed-up (local Jupyter notebook), jak wspomniano w Uwagach do wydania.

# 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
 12
Author: Kevin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-16 21:51:04

Żeby było łatwiej. Nie aplikuj. Nie ma mapy. Brak pętli.

cols=data.select_dtypes(exclude='int').columns.to_list()
data[cols]=data[cols].astype('category')
 3
Author: liangli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-13 13:52:15

Odkryłem, że używanie pętli for działa dobrze.

for col in ['col_variable_name_1', 'col_variable_name_2', ect..]:
    dataframe_name[col] = dataframe_name[col].astype(float)
 0
Author: NikoTumi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-19 17:47:48

Jupyter Notebook

W moim przypadku miałem dużą ramkę danych z wieloma obiektami, które chciałbym przekonwertować do kategorii.

Dlatego, co zrobiłem, to wybrałem kolumny obiektu i wypełniłem wszystko, czego brakuje NA, a następnie zapisałem je w oryginalnej ramce danych, jak w

# 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()

Mam nadzieję, że może to być pomocne źródło do późniejszego odniesienia

 -1
Author: rsc05,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55