Kolomtype wijzigen in panda’s

Ik wil een tabel, weergegeven als een lijst met lijsten, converteren naar een Pandas DataFrame. Als een extreem vereenvoudigd voorbeeld:

a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a)

Wat is de beste manier om de kolommen om te zetten in de juiste typen, in dit geval kolommen 2 en 3 in floats? Is er een manier om de typen te specificeren tijdens het converteren naar DataFrame? Of is het beter om eerst het DataFrame te maken en vervolgens door de kolommen te lopen om het type voor elke kolom te wijzigen? Idealiter zou ik dit op een dynamische manier willen doen omdat er honderden kolommen kunnen zijn en ik niet precies wil specificeren welke kolommen van welk type zijn. Ik kan alleen garanderen dat elke kolom waarden van hetzelfde type bevat.


Antwoord 1, autoriteit 100%

Je hebt vier hoofdopties voor het converteren van typen in panda’s:

  1. to_numeric() – biedt functionaliteit om niet-numerieke typen (bijv. strings) veilig te converteren naar een geschikt numeriek type. (Zie ook to_datetime() en to_timedelta().)

  2. astype() – converteer (bijna) elk type naar (bijna) elk ander type (zelfs als het niet per se verstandig is om dit te doen). Hiermee kunt u ook converteren naar categoriale-typen (erg handig).

  3. infer_objects() – een hulpprogrammamethode om objectkolommen met Python-objecten, indien mogelijk, om te zetten naar een panda-type.

  4. convert_dtypes() – converteer DataFrame-kolommen naar het “best mogelijke” dtype dat pd.NA ondersteunt (panda’s-object om een ​​ontbrekende waarde aan te geven).

Lees verder voor meer gedetailleerde uitleg en gebruik van elk van deze methoden.


1. to_numeric()

De beste manier om een ​​of meer kolommen van een DataFrame naar numerieke waarden te converteren, is door pandas.to_numeric().

Deze functie zal proberen niet-numerieke objecten (zoals tekenreeksen) te veranderen in gehele getallen of getallen met drijvende komma, al naar gelang.

Basisgebruik

De invoer voor to_numeric() is een Series of een enkele kolom van een DataFrame.

>>> s = pd.Series(["8", 6, "7.5", 3, "0.9"]) # mixed string and numeric values
>>> s
0      8
1      6
2    7.5
3      3
4    0.9
dtype: object
>>> pd.to_numeric(s) # convert everything to float values
0    8.0
1    6.0
2    7.5
3    3.0
4    0.9
dtype: float64

Zoals je kunt zien, wordt er een nieuwe serie geretourneerd. Vergeet niet om deze uitvoer toe te wijzen aan een variabele of kolomnaam om deze te blijven gebruiken:

# convert Series
my_series = pd.to_numeric(my_series)
# convert column "a" of a DataFrame
df["a"] = pd.to_numeric(df["a"])

Je kunt het ook gebruiken om meerdere kolommen van een DataFrame te converteren via de apply()-methode:

# convert all columns of DataFrame
df = df.apply(pd.to_numeric) # convert all columns of DataFrame
# convert just columns "a" and "b"
df[["a", "b"]] = df[["a", "b"]].apply(pd.to_numeric)

Zolang je waarden allemaal kunnen worden geconverteerd, is dat waarschijnlijk alles wat je nodig hebt.

Foutafhandeling

Maar wat als sommige waarden niet kunnen worden geconverteerd naar een numeriek type?

to_numeric() gebruikt ook een errors trefwoordargument waarmee u niet-numerieke waarden kunt forceren om NaN te zijn, of gewoon kolommen kunt negeren die deze waarden bevatten.

Hier is een voorbeeld met een reeks strings s met het object dtype:

>>> s = pd.Series(['1', '2', '4.7', 'pandas', '10'])
>>> s
0         1
1         2
2       4.7
3    pandas
4        10
dtype: object

Het standaardgedrag is om te verhogen als een waarde niet kan worden geconverteerd. In dit geval kan het de string ‘panda’s’ niet aan:

>>> pd.to_numeric(s) # or pd.to_numeric(s, errors='raise')
ValueError: Unable to parse string

In plaats van te mislukken, willen we misschien dat ‘panda’s’ worden beschouwd als een ontbrekende/slechte numerieke waarde. We kunnen als volgt ongeldige waarden tot NaN dwingen met behulp van het errors trefwoordargument:

>>> pd.to_numeric(s, errors='coerce')
0     1.0
1     2.0
2     4.7
3     NaN
4    10.0
dtype: float64

De derde optie voor errors is om de bewerking te negeren als er een ongeldige waarde wordt aangetroffen:

>>> pd.to_numeric(s, errors='ignore')
# the original Series is returned untouched

Deze laatste optie is met name handig als u uw volledige DataFrame wilt converteren, maar niet weet welke van onze kolommen betrouwbaar kunnen worden geconverteerd naar een numeriek type. Schrijf in dat geval gewoon:

df.apply(pd.to_numeric, errors='ignore')

De functie wordt toegepast op elke kolom van het DataFrame. Kolommen die kunnen worden geconverteerd naar een numeriek type, worden geconverteerd, terwijl kolommen die dat niet kunnen (bijv. ze bevatten niet-cijferige tekenreeksen of datums) met rust worden gelaten.

Downcasting

Standaard zal conversie met to_numeric() u ofwel een int64 of float64 dtype geven (of welk geheel getal dan ook dat eigen is aan uw platform).

Dat is meestal wat je wilt, maar wat als je wat geheugen wilt besparen en een compacter dtype wilt gebruiken, zoals float32 of int8?

to_numeric() geeft je de mogelijkheid om te downcasten naar ‘integer’, ‘signed’, ‘unsigned’ of ‘float’. Hier is een voorbeeld voor een eenvoudige reeks s van het type integer:

>>> s = pd.Series([1, 2, -7])
>>> s
0    1
1    2
2   -7
dtype: int64

Downcasting naar ‘integer’ gebruikt het kleinst mogelijke gehele getal dat de waarden kan bevatten:

>>> pd.to_numeric(s, downcast='integer')
0    1
1    2
2   -7
dtype: int8

Downcasting naar ‘zwevend’ kiest op dezelfde manier een kleiner dan normaal zwevend type:

>>> pd.to_numeric(s, downcast='float')
0    1.0
1    2.0
2   -7.0
dtype: float32

2. astype()

De astype()-methode kunt u expliciet zijn over het dtype dat u wilt dat uw DataFrame of Series heeft. Het is erg veelzijdig omdat je kunt proberen van het ene type naar het andere te gaan.

Basisgebruik

Kies gewoon een type: je kunt een NumPy dtype (bijv. np.int16), sommige Python-typen (bijv. bool) of panda-specifieke typen (zoals het categorische dtype) gebruiken.

p>

Bel de methode op het object dat u wilt converteren en astype() zal proberen het voor u te converteren:

# convert all DataFrame columns to the int64 dtype
df = df.astype(int)
# convert column "a" to int64 dtype and "b" to complex type
df = df.astype({"a": int, "b": complex})
# convert Series to float16 type
s = s.astype(np.float16)
# convert Series to Python strings
s = s.astype(str)
# convert Series to categorical type - see docs for more details
s = s.astype('category')

Merk op dat ik “probeer” zei – als astype() niet weet hoe een waarde in de Series of DataFrame moet worden geconverteerd, wordt er een fout gegenereerd. Als u bijvoorbeeld een NaN– of inf-waarde heeft, krijgt u een foutmelding bij het converteren naar een geheel getal.

Vanaf pandas 0.20.0 kan deze fout worden onderdrukt door errors='ignore' door te geven. Uw originele object wordt onaangeroerd geretourneerd.

Wees voorzichtig

astype() is krachtig, maar het converteert waarden soms “onjuist”. Bijvoorbeeld:

>>> s = pd.Series([1, 2, -7])
>>> s
0    1
1    2
2   -7
dtype: int64

Dit zijn kleine gehele getallen, dus hoe zit het met het converteren naar een niet-ondertekend 8-bits type om geheugen te besparen?

>>> s.astype(np.uint8)
0      1
1      2
2    249
dtype: uint8

De conversie werkte, maar de -7 werd omgedraaid en werd 249 (d.w.z. 28 – 7)!

Proberen te downcasten met behulp van pd.to_numeric(s, downcast='unsigned') kan deze fout helpen voorkomen.


3. infer_objects()

Versie 0.21.0 van panda’s introduceerde de methode infer_objects() voor het converteren van kolommen van een DataFrame met een objectgegevenstype naar een specifieker type (zachte conversies).

Hier is bijvoorbeeld een DataFrame met twee kolommen met objecttype. De ene bevat werkelijke gehele getallen en de andere bevat strings die gehele getallen vertegenwoordigen:

>>> df = pd.DataFrame({'a': [7, 1, 5], 'b': ['3','2','1']}, dtype='object')
>>> df.dtypes
a    object
b    object
dtype: object

Met infer_objects() kunt u het type kolom ‘a’ wijzigen in int64:

>>> df = df.infer_objects()
>>> df.dtypes
a     int64
b    object
dtype: object

Kolom ‘b’ is alleen gelaten omdat de waarden strings waren, geen gehele getallen. Als u de conversie van beide kolommen naar een geheel getal wilt forceren, kunt u in plaats daarvan df.astype(int) gebruiken.


4. convert_dtypes()

Versie 1.0 en hoger bevat een methode convert_dtypes() om Series- en DataFrame-kolommen te converteren naar het best mogelijke dtype dat de ontbrekende waarde pd.NA ondersteunt.

Hier betekent “best mogelijke” het type dat het meest geschikt is om de waarden vast te houden. Dit is bijvoorbeeld een geheel getal van panda’s als alle waarden gehele getallen zijn (of ontbrekende waarden): een objectkolom van Python integer-objecten wordt geconverteerd naar int64, een kolom NumPy Int32-waarden worden de panda’s dtype Int32.

Met ons object DataFrame df krijgen we het volgende resultaat:

>>> df.convert_dtypes().dtypes                                             
a     Int64
b    string
dtype: object

Aangezien kolom ‘a’ gehele waarden bevatte, is deze geconverteerd naar het type int64 (dat ontbrekende waarden kan bevatten, in tegenstelling tot int64).

Kolom ‘b’ bevatte tekenreeksobjecten, en is daarom gewijzigd in string dtype van panda’s.

Standaard leidt deze methode het type af uit objectwaarden in elke kolom. We kunnen dit veranderen door infer_objects=False door te geven:

>>> df.convert_dtypes(infer_objects=False).dtypes                          
a    object
b    string
dtype: object

Kolom ‘a’ bleef nu een objectkolom: panda’s weten dat het kan worden beschreven als een ‘integer’-kolom (intern liep het infer_dtype) maar leidde niet precies af welk dtype van geheel getal het zou moeten hebben, dus niet geconverteerd het. Kolom ‘b’ werd opnieuw geconverteerd naar ‘string’ dtype omdat het werd herkend als ‘string’-waarden.


Antwoord 2, autoriteit 27%

Hoe zit het hiermee?

a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a, columns=['one', 'two', 'three'])
df
Out[16]: 
  one  two three
0   a  1.2   4.2
1   b   70  0.03
2   x    5     0
df.dtypes
Out[17]: 
one      object
two      object
three    object
df[['two', 'three']] = df[['two', 'three']].astype(float)
df.dtypes
Out[19]: 
one       object
two      float64
three    float64

Antwoord 3, autoriteit 3%

deze onderstaande code verandert het gegevenstype van de kolom.

df[['col.name1', 'col.name2'...]] = df[['col.name1', 'col.name2'..]].astype('data_type')

in plaats van het gegevenstype kunt u uw gegevenstype .wat wilt u geven, zoals str,float,int enz.


Antwoord 4

Als ik alleen specifieke kolommen hoef op te geven en ik wil expliciet zijn, heb ik (per DOCS-LOCATIE):

dataframe = dataframe.astype({'col_name_1':'int','col_name_2':'float64', etc. ...})

Dus, gebruik de oorspronkelijke vraag, maar geef er kolomnamen aan …

a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a, columns=['col_name_1', 'col_name_2', 'col_name_3'])
df = df.astype({'col_name_2':'float64', 'col_name_3':'float64'})

Antwoord 5

Hier is een functie die als argumenten een DataFrame en een lijst met kolommen neemt en alle gegevens in de kolommen tot getallen dwingt.

# df is the DataFrame, and column_list is a list of columns as strings (e.g ["col1","col2","col3"])
# dependencies: pandas
def coerce_df_columns_to_numeric(df, column_list):
    df[column_list] = df[column_list].apply(pd.to_numeric, errors='coerce')

Dus, voor jouw voorbeeld:

import pandas as pd
def coerce_df_columns_to_numeric(df, column_list):
    df[column_list] = df[column_list].apply(pd.to_numeric, errors='coerce')
a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a, columns=['col1','col2','col3'])
coerce_df_columns_to_numeric(df, ['col2','col3'])

Antwoord 6

panda’s >= 1.0

Hier is een grafiek met een overzicht van enkele van de belangrijkste conversies in panda’s.

voer hier de afbeeldingsbeschrijving in

Conversies naar string zijn triviaal .astype(str) en worden niet getoond in de afbeelding.

‘Harde’ versus ‘Zachte’ conversies

Houd er rekening mee dat ‘conversies’ in deze context kunnen verwijzen naar het converteren van tekstgegevens naar hun werkelijke gegevenstype (harde conversie), of naar het afleiden van meer geschikte gegevenstypen voor gegevens in objectkolommen (zachte conversie). Om het verschil te illustreren, kijk eens op

df = pd.DataFrame({'a': ['1', '2', '3'], 'b': [4, 5, 6]}, dtype=object)
df.dtypes                                                                  
a    object
b    object
dtype: object
# Actually converts string to numeric - hard conversion
df.apply(pd.to_numeric).dtypes                                             
a    int64
b    int64
dtype: object
# Infers better data types for object data - soft conversion
df.infer_objects().dtypes                                                  
a    object  # no change
b     int64
dtype: object
# Same as infer_objects, but converts to equivalent ExtensionType
df.convert_dtypes().dtypes                                                     

Antwoord 7

Hoe zit het met het maken van twee dataframes, elk met verschillende gegevenstypen voor hun kolommen, en deze vervolgens aan elkaar toe te voegen?

d1 = pd.DataFrame(columns=[ 'float_column' ], dtype=float)
d1 = d1.append(pd.DataFrame(columns=[ 'string_column' ], dtype=str))

Resultaten

In[8}:  d1.dtypes
Out[8]: 
float_column     float64
string_column     object
dtype: object

Nadat het dataframe is gemaakt, kunt u het vullen met variabelen met drijvende komma in de 1e kolom en tekenreeksen (of elk gewenst gegevenstype) in de 2e kolom.


Antwoord 8

Vanaf pandas 1.0.0 hebben we pandas.DataFrame.convert_dtypes. Je kunt zelfs bepalen welke typen je wilt converteren!

In [40]: df = pd.DataFrame(
    ...:     {
    ...:         "a": pd.Series([1, 2, 3], dtype=np.dtype("int32")),
    ...:         "b": pd.Series(["x", "y", "z"], dtype=np.dtype("O")),
    ...:         "c": pd.Series([True, False, np.nan], dtype=np.dtype("O")),
    ...:         "d": pd.Series(["h", "i", np.nan], dtype=np.dtype("O")),
    ...:         "e": pd.Series([10, np.nan, 20], dtype=np.dtype("float")),
    ...:         "f": pd.Series([np.nan, 100.5, 200], dtype=np.dtype("float")),
    ...:     }
    ...: )
In [41]: dff = df.copy()
In [42]: df 
Out[42]: 
   a  b      c    d     e      f
0  1  x   True    h  10.0    NaN
1  2  y  False    i   NaN  100.5
2  3  z    NaN  NaN  20.0  200.0
In [43]: df.dtypes
Out[43]: 
a      int32
b     object
c     object
d     object
e    float64
f    float64
dtype: object
In [44]: df = df.convert_dtypes()
In [45]: df.dtypes
Out[45]: 
a      Int32
b     string
c    boolean
d     string
e      Int64
f    float64
dtype: object
In [46]: dff = dff.convert_dtypes(convert_boolean = False)
In [47]: dff.dtypes
Out[47]: 
a      Int32
b     string
c     object
d     string
e      Int64
f    float64
dtype: object

Antwoord 9

Ik dacht dat ik hetzelfde probleem had, maar eigenlijk heb ik een klein verschil waardoor het probleem gemakkelijker op te lossen is. Voor anderen die naar deze vraag kijken, is het de moeite waard om het formaat van uw invoerlijst te controleren. In mijn geval zijn de getallen aanvankelijk floats en geen strings zoals in de vraag:

a = [['a', 1.2, 4.2], ['b', 70, 0.03], ['x', 5, 0]]

maar door de lijst te veel te verwerken voordat ik het dataframe maak, verlies ik de typen en wordt alles een string.

Het dataframe maken via een numpy-array

df = pd.DataFrame(np.array(a))
df
Out[5]: 
   0    1     2
0  a  1.2   4.2
1  b   70  0.03
2  x    5     0
df[1].dtype
Out[7]: dtype('O')

geeft hetzelfde dataframe als in de vraag, waarbij de items in kolommen 1 en 2 als strings worden beschouwd. Maar aan het doen

df = pd.DataFrame(a)
df
Out[10]: 
   0     1     2
0  a   1.2  4.20
1  b  70.0  0.03
2  x   5.0  0.00
df[1].dtype
Out[11]: dtype('float64')

geeft inderdaad een dataframe met de kolommen in het juiste formaat


Antwoord 10

df.info() gives us initial datatype of temp which is float64
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   date    132 non-null    object 
 1   temp    132 non-null    float64
 Now, use this code to change the datatype to int64:  df['temp'] = df['temp'].astype('int64')
 if you do df.info() again, you will see:
  #   Column  Non-Null Count  Dtype 
 ---  ------  --------------  ----- 
  0   date    132 non-null    object
  1   temp    132 non-null    int64 
 this shows you have successfully changed the datatype of column temp. Happy coding!

LEAVE A REPLY

Please enter your comment!
Please enter your name here

five × four =

Other episodes