Chcem previesť tabuľku reprezentovanú ako zoznam zoznamov na Pandas DataFrame. Ako extrémne zjednodušený príklad:
a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a)
Aký je najlepší spôsob, ako previesť stĺpce na príslušné typy, v tomto prípade stĺpce 2 a 3 na floaty? Existuje spôsob, ako určiť typy pri konverzii na DataFrame? Alebo je lepšie najprv vytvoriť DataFrame a potom v cykle prechádzať stĺpce a meniť typ pre každý stĺpec? Ideálne by bolo, keby som to urobil dynamicky, pretože stĺpcov môžu byť stovky a nechcem presne špecifikovať, ktoré stĺpce sú akého typu. Jediné, čo môžem zaručiť, je, že každý stĺpec obsahuje hodnoty rovnakého typu.
V programe pandas máte tri hlavné možnosti konverzie typov:
to_numeric()
- poskytuje funkciu na bezpečný prevod nečíselných typov (napr. reťazcov) na vhodný číselný typ. (Pozri tiež to_datetime()
a to_timedelta()
.)astype()
- prevedie (takmer) ľubovoľný typ na (takmer) ľubovoľný iný typ (aj keď to'nie je nevyhnutne rozumné). Umožňuje tiež konvertovať na kategoriálne typy (veľmi užitočné).infer_objects()
- užitočná metóda na konverziu objektových stĺpcov, v ktorých sa nachádzajú objekty Pythonu, na typ pandas, ak je to možné.
Prečítajte si podrobnejšie vysvetlenie a použitie každej z týchto metód.to_numeric()
Najlepší spôsob, ako previesť jeden alebo viac stĺpcov DataFrame na číselné hodnoty, je použiť pandas.to_numeric()
.
Táto funkcia sa pokúsi zmeniť nečíselné objekty (napríklad reťazce) na celé čísla alebo čísla s pohyblivou rádovou čiarkou podľa potreby.
Vstupom do funkcie to_numeric()
je rad alebo jeden stĺpec rámca 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
Ako vidíte, vráti sa nová séria. Nezabudnite tento výstup priradiť k premennej alebo názvu stĺpca, aby ste ho mohli ďalej používať:
# convert Series
my_series = pd.to_numeric(my_series)
# convert column "a" of a DataFrame
df["a"] = pd.to_numeric(df["a"])
Môžete ho použiť aj na prevod viacerých stĺpcov DataFrame prostredníctvom metódy apply()
:
# 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)
Pokiaľ je možné konvertovať všetky hodnoty, pravdepodobne to stačí.
Ale čo ak sa niektoré hodnoty nedajú previesť na číselný typ?
Funkcia to_numeric()
prijíma aj argument kľúčového slova errors
, ktorý vám umožňuje vynútiť, aby sa hodnoty, ktoré nie sú číselné, stali NaN
, alebo jednoducho ignorovať stĺpce obsahujúce tieto hodnoty.
Tu'je príklad s použitím série reťazcov s
, ktorá má objektový typ d:
>>> s = pd.Series(['1', '2', '4.7', 'pandas', '10'])
>>> s
0 1
1 2
2 4.7
3 pandas
4 10
dtype: object
Predvolené správanie je upozorniť, ak nie je možné previesť hodnotu. V tomto prípade si nevie'poradiť s reťazcom 'pandas':
>>> pd.to_numeric(s) # or pd.to_numeric(s, errors='raise')
ValueError: Unable to parse string
Namiesto zlyhania by sme mohli chcieť, aby sa 'pandas' považovalo za chýbajúcu/zlú číselnú hodnotu. Neplatné hodnoty môžeme vynútiť na NaN
nasledovne pomocou argumentu kľúčového slova errors
:
>>> pd.to_numeric(s, errors='coerce')
0 1.0
1 2.0
2 4.7
3 NaN
4 10.0
dtype: float64
Treťou možnosťou pre errors
je jednoducho ignorovať operáciu, ak sa vyskytne neplatná hodnota:
>>> pd.to_numeric(s, errors='ignore')
# the original Series is returned untouched
Táto posledná možnosť je užitočná najmä vtedy, keď chceme konvertovať celý DataFrame, ale nevieme, ktoré z našich stĺpcov sa dajú spoľahlivo konvertovať na číselný typ. V takom prípade stačí napísať:
df.apply(pd.to_numeric, errors='ignore')
Funkcia sa použije na každý stĺpec DataFrame. Stĺpce, ktoré sa dajú previesť na číselný typ, sa prevedú, zatiaľ čo stĺpce, ktoré sa nedajú (napr. obsahujú neciferné reťazce alebo dátumy), sa ponechajú.
V predvolenom nastavení vám konverzia pomocou funkcie to_numeric()
poskytne buď dtyp int64
alebo float64
(alebo akúkoľvek šírku celého čísla, ktorá je pre vašu platformu prirodzená).
To je zvyčajne to, čo chcete, ale čo keby ste chceli ušetriť trochu pamäte a použiť kompaktnejší dtype, napríklad float32
alebo int8
?
Funkcia to_numeric()
vám dáva možnosť downcastu buď na 'integer', 'signed', 'unsigned', 'float'. Tu je príklad pre jednoduchý rad s
typu integer:
>>> s = pd.Series([1, 2, -7])
>>> s
0 1
1 2
2 -7
dtype: int64
Prevod na 'integer' používa najmenšie možné celé číslo, ktoré môže obsahovať hodnoty:
>>> pd.to_numeric(s, downcast='integer')
0 1
1 2
2 -7
dtype: int8
Prevrhnutie na 'float' podobne vyberie menší typ plávajúceho typu, než je obvyklé:
>>> pd.to_numeric(s, downcast='float')
0 1.0
1 2.0
2 -7.0
dtype: float32
astype()
Metóda astype()
vám umožňuje explicitne určiť dtype, ktorý má mať váš DataFrame alebo Series. Je'veľmi univerzálna v tom, že sa môžete pokúsiť prejsť z jedného typu na akýkoľvek iný.
Stačí si vybrať typ: môžete použiť dtyp NumPy (napr. np.int16
), niektoré typy Pythonu (napr. bool) alebo typy špecifické pre pandu (ako napríklad dtyp categorical).
Zavolajte metódu na objekt, ktorý chcete konvertovať, a astype()
sa ho pokúsi konvertovať za vás:
# 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')
Všimnite si, že som povedal "try" - ak astype()
nevie, ako konvertovať hodnotu v Series alebo DataFrame, vyhlási chybu. Napríklad ak máte hodnotu NaN
alebo inf
, pri pokuse o jej prevod na celé číslo sa zobrazí chyba.
Od verzie pandas 0.20.0 je možné túto chybu potlačiť zadaním errors='ignore'
. Váš pôvodný objekt sa vráti nedotknutý.
Funkcia astype()
je výkonná, ale niekedy prevedie hodnoty "nesprávne". Napríklad:
>>> s = pd.Series([1, 2, -7])
>>> s
0 1
1 2
2 -7
dtype: int64
Sú to malé celé čísla, takže čo tak konvertovať ich na 8-bitový typ bez znamienka, aby sa ušetrila pamäť?
>>> s.astype(np.uint8)
0 1
1 2
2 249
dtype: uint8
pd.to_numeric(s, downcast='unsigned')
namiesto toho by mohol pomôcť zabrániť tejto chybe.infer_objects()
Verzia pandas 0.21.0 zaviedla metódu infer_objects()
na konverziu stĺpcov DataFrame, ktoré majú dátový typ objektu, na špecifickejší typ (mäkké konverzie).
Napríklad tu je DataFrame s dvoma stĺpcami objektového typu. Jeden obsahuje skutočné celé čísla a druhý reťazce reprezentujúce celé čísla:
>>> df = pd.DataFrame({'a': [7, 1, 5], 'b': ['3','2','1']}, dtype='object')
>>> df.dtypes
a object
b object
dtype: object
Pomocou funkcie infer_objects()
môžete zmeniť typ stĺpca 'a' na int64:
>>> df = df.infer_objects()
>>> df.dtypes
a int64
b object
dtype: object
Stĺpec 'b' bol ponechaný na pokoji, pretože jeho hodnoty boli reťazce, nie celé čísla. Ak by ste sa chceli pokúsiť vynútiť konverziu oboch stĺpcov na celočíselný typ, mohli by ste namiesto toho použiť df.astype(int)
.
A čo toto?
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
Tu je funkcia, ktorá ako argumenty prijíma DataFrame a zoznam stĺpcov a všetky údaje v stĺpcoch premení na čísla.
# 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')
Takže pre váš príklad:
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'])