Hyödynnä Pandasin koko potentiaali hallitsemalla mukautetut funktiot. Tämä opas kertoo apply(), map() ja applymap() -menetelmien eroista, suorituskyvystä ja parhaista käyttötavoista ammattimaisessa data-analyysissä.
Pandasin hallinta: Syväluotaus mukautettuihin funktioihin apply(), map() ja applymap() -menetelmillä
Data science- ja analyysimaailmassa Pythonin Pandas-kirjasto on korvaamaton työkalu. Se tarjoaa tehokkaita, joustavia ja tehokkaita tietorakenteita, jotka on suunniteltu tekemään strukturoidun datan käsittelystä sekä helppoa että intuitiivista. Vaikka Pandas sisältää runsaasti sisäänrakennettuja funktioita aggregaatioon, suodatukseen ja muuntamiseen, tulee jokaisen data-ammattilaisen matkalla aika, jolloin nämä eivät riitä. Sinun on sovellettava omaa mukautettua logiikkaasi, ainutlaatuista liiketoimintasääntöä tai monimutkaista muunnosta, joka ei ole helposti saatavilla.
Tässä kohtaa kyky soveltaa mukautettuja funktioita tulee supervoimaksi. Pandas tarjoaa kuitenkin useita tapoja tämän saavuttamiseksi, pääasiassa apply()-, map()- ja applymap()-menetelmillä. Aloittelijalle nämä funktiot voivat tuntua hämmentävän samanlaisilta. Mitä pitäisi käyttää? Milloin? Ja mitä ovat valintasi suorituskykyvaikutukset?
Tämä kattava opas selventää näitä tehokkaita menetelmiä. Tutkimme jokaisen niistä yksityiskohtaisesti, ymmärrämme niiden erityiset käyttötapaukset ja ennen kaikkea opimme valitsemaan oikean työkalun työhön kirjoittamaan siistiä, tehokasta ja luettavaa Pandas-koodia. Käsittelemme:
map()-menetelmä: Ihanteellinen elementtipohjaiseen muunnokseen yhdellä Series-objektilla.apply()-menetelmä: Monipuolinen työkalu rivi- tai sarakekohtaisiin operaatioihin DataFrame-objektilla.applymap()-menetelmä: Asiantuntija elementtipohjaisiin operaatioihin koko DataFrame-objektissa.- Suorituskykyyn liittyvät näkökohdat: Kriittinen ero näiden menetelmien ja todellisen vektorisoinnin välillä.
- Parhaat käytännöt: Päätöksentekokehys, joka auttaa sinua valitsemaan tehokkaimman menetelmän joka kerta.
Lavastus: Esimerkki Datasarjamme
Jotta esimerkkimme olisivat käytännöllisiä ja selkeitä, työskennellään johdonmukaisen, maailmanlaajuisesti merkityksellisen datasarjan kanssa. Luomme esimerkin DataFrame-objektin, joka edustaa fiktiivisen kansainvälisen verkkokauppayrityksen verkkokauppatiedot.
import pandas as pd
import numpy as np
data = {
'OrderID': [1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008],
'Product': ['Laptop', 'Mouse', 'Keyboard', 'Monitor', 'Webcam', 'Headphones', 'Docking Station', 'Mouse'],
'Category': ['Electronics', 'Accessories', 'Accessories', 'Electronics', 'Accessories', 'Audio', 'Electronics', 'Accessories'],
'Price_USD': [1200, 25, 75, 300, 50, 150, 250, 30],
'Quantity': [1, 2, 1, 2, 1, 1, 1, 3],
'Country': ['USA', 'Canada', 'USA', 'Germany', 'Japan', 'Canada', 'Germany', np.nan]
}
df = pd.DataFrame(data)
print(df)
Tämä DataFrame antaa meille mukavan sekoituksen tietotyyppejä (numeerisia, merkkijonoja ja jopa puuttuva arvo) osoittaaksemme kohdefunktioidemme täydet ominaisuudet.
map()-menetelmä: Elementtipohjainen muunnos sarjalle
Mikä on map()?
map()-menetelmä on erikoistunut työkalusi arvojen muokkaamiseen yhdessä sarakkeessa (Pandas Series-objektissa). Se toimii elementti kerrallaan. Ajattele sitä kuin sanoisit: "Jokaiselle tämän sarakkeen kohteelle, etsi se sanakirjasta tai siirrä se tämän funktion kautta ja korvaa se tuloksella."
Sitä käytetään pääasiassa kahteen tehtävään:
- Arvojen korvaaminen sanakirjan (kartoituksen) perusteella.
- Yksinkertaisen funktion soveltaminen jokaiseen elementtiin.
Käyttötapaus 1: Arvojen kartoitus sanakirjalla
Tämä on map()-menetelmän yleisin ja tehokkain käyttö. Kuvittele, että haluamme luoda laajemman 'Department'-sarakkeen 'Category'-sarakkeemme perusteella. Voimme määrittää kartoituksen Python-sanakirjassa ja käyttää map()-menetelmää sen soveltamiseen.
category_to_department = {
'Electronics': 'Technology',
'Accessories': 'Peripherals',
'Audio': 'Technology'
}
df['Department'] = df['Category'].map(category_to_department)
print(df[['Category', 'Department']])
Tuloste:
Category Department
0 Electronics Technology
1 Accessories Peripherals
2 Accessories Peripherals
3 Electronics Technology
4 Accessories Peripherals
5 Audio Technology
6 Electronics Technology
7 Accessories Peripherals
Huomaa, miten elegantisti tämä toimii. Jokainen arvo 'Category'-sarjassa etsitään `category_to_department`-sanakirjasta, ja vastaavaa arvoa käytetään uuden 'Department'-sarakkeen täyttämiseen. Jos avainta ei löydy sanakirjasta, map() tuottaa NaN (Not a Number) -arvon, mikä on usein haluttu käyttäytyminen kartoittamattomille kategorioille.
Käyttötapaus 2: Funktion soveltaminen map()-menetelmällä
Voit myös välittää funktion (mukaan lukien lambda-funktion) map()-menetelmälle. Funktio suoritetaan jokaiselle sarjan elementille. Luodaan uusi sarake, joka antaa meille kuvailevan merkinnän hinnasta.
def price_label(price):
if price > 200:
return 'High-Value'
elif price > 50:
return 'Mid-Value'
else:
return 'Low-Value'
df['Price_Label'] = df['Price_USD'].map(price_label)
# Lambda-funktion käyttäminen yksinkertaisempaan tehtävään:
# df['Product_Length'] = df['Product'].map(lambda x: len(x))
print(df[['Product', 'Price_USD', 'Price_Label']])
Tuloste:
Product Price_USD Price_Label
0 Laptop 1200 High-Value
1 Mouse 25 Low-Value
2 Keyboard 75 Mid-Value
3 Monitor 300 High-Value
4 Webcam 50 Low-Value
5 Headphones 150 Mid-Value
6 Docking Station 250 High-Value
7 Mouse 30 Low-Value
Milloin map()-menetelmää käytetään: Nopea yhteenveto
- Työskentelet yhdellä sarakkeella (Series-objektilla).
- Sinun on korvattava arvot sanakirjan tai toisen Series-objektin perusteella. Tämä on sen ensisijainen vahvuus.
- Sinun on sovellettava yksinkertaista elementtipohjaista funktiota yhteen sarakkeeseen.
apply()-menetelmä: Monipuolinen työkalu
Mikä on apply()?
Jos map() on asiantuntija, apply() on yleiskäyttöinen voimanpesä. Se on joustavampi, koska se voi toimia sekä Series-objektilla että DataFrame-objektilla. Avain apply()-menetelmän ymmärtämiseen on axis-parametri, joka ohjaa sen toimintaa:
- Series-objektilla: Se toimii elementti kerrallaan, aivan kuten
map(). - DataFrame-objektilla
axis=0(oletus): Se soveltaa funktiota jokaiseen sarakkeeseen. Funktio saa jokaisen sarakkeen Series-objektina. - DataFrame-objektilla
axis=1: Se soveltaa funktiota jokaiseen riviin. Funktio saa jokaisen rivin Series-objektina.
apply() Series-objektilla
Kun sitä käytetään Series-objektilla, apply() käyttäytyy hyvin samalla tavalla kuin map(). Se soveltaa funktiota jokaiseen elementtiin. Voimme esimerkiksi toistaa hinta-esimerkkimme.
df['Price_Label_apply'] = df['Price_USD'].apply(price_label)
print(df['Price_Label_apply'].equals(df['Price_Label'])) # Tuloste: True
Vaikka ne näyttävät täällä vaihdettavilta, map() on usein hieman nopeampi yksinkertaisille sanakirjojen korvaamisille ja elementtipohjaisille operaatioille Series-objektilla, koska sillä on optimoidumpi polku näille erityisille tehtäville.
apply() DataFrame-objektilla (Sarakekohtaisesti, axis=0)
Tämä on DataFrame-objektin oletustila. Antamasi funktio kutsutaan kerran jokaiselle sarakkeelle. Tämä on hyödyllistä sarakekohtaisille aggregaatioille tai muunnoksille.
Etsitään numeeristen sarakkeidemme jokaisen maksimi- ja minimiarvon (alueen) välinen ero.
numeric_cols = df[['Price_USD', 'Quantity']]
def get_range(column_series):
return column_series.max() - column_series.min()
column_ranges = numeric_cols.apply(get_range, axis=0)
print(column_ranges)
Tuloste:
Price_USD 1175.0
Quantity 2.0
dtype: float64
Tässä get_range-funktio sai ensin 'Price_USD'-sarjan, laski sen alueen, sitten sai 'Quantity'-sarjan ja teki saman, palauttaen uuden sarjan tuloksilla.
apply() DataFrame-objektilla (Rivikohtaisesti, axis=1)
Tämä on kiistatta apply()-menetelmän tehokkain ja yleisin käyttötapaus. Kun sinun on laskettava uusi arvo useista sarakkeista samalla rivillä, apply() ja axis=1 on ratkaisu.
Funktio, jonka välität, saa jokaisen rivin Series-objektina, jossa indeksi on sarakkeen nimet. Lasketaan jokaisen tilauksen kokonaiskustannukset.
def calculate_total_cost(row):
# 'row' on Series, joka edustaa yhtä riviä
price = row['Price_USD']
quantity = row['Quantity']
return price * quantity
df['Total_Cost'] = df.apply(calculate_total_cost, axis=1)
print(df[['Product', 'Price_USD', 'Quantity', 'Total_Cost']])
Tuloste:
Product Price_USD Quantity Total_Cost
0 Laptop 1200 1 1200
1 Mouse 25 2 50
2 Keyboard 75 1 75
3 Monitor 300 2 600
4 Webcam 50 1 50
5 Headphones 150 1 150
6 Docking Station 250 1 250
7 Mouse 30 3 90
Tämän map() ei yksinkertaisesti pysty tekemään, koska se on rajoitettu yhteen sarakkeeseen. Katsotaanpa monimutkaisempi esimerkki. Haluamme luokitella jokaisen tilauksen toimitusprioriteetin kategorian ja maan perusteella.
def assign_shipping_priority(row):
if row['Category'] == 'Electronics' and row['Country'] == 'USA':
return 'High Priority'
elif row['Total_Cost'] > 500:
return 'High Priority'
elif row['Country'] == 'Japan':
return 'Medium Priority'
else:
return 'Standard'
df['Shipping_Priority'] = df.apply(assign_shipping_priority, axis=1)
print(df[['Category', 'Country', 'Total_Cost', 'Shipping_Priority']])
Milloin apply()-menetelmää käytetään: Nopea yhteenveto
- Kun logiikkasi riippuu useista sarakkeista rivillä (käytä
axis=1). Tämä on sen tappava ominaisuus. - Kun sinun on sovellettava aggregaatiofunktiota sarakkeisiin tai rivien yli.
- Yleiskäyttöisenä funktion soveltamistyökaluna, kun
map()ei sovi.
Erityismaininta: applymap()-menetelmä
Mikä on applymap()?
applymap()-menetelmä on toinen asiantuntija, mutta sen alue on koko DataFrame. Se soveltaa funktiota jokaiseen elementtiin DataFrame-objektissa. Se ei toimi Series-objektilla – se on vain DataFrame-objektin menetelmä.
Ajattele sitä kuin ajatteleisit map()-menetelmän suorittamista jokaisella sarakkeella samanaikaisesti. Se on hyödyllinen laajoille, kattaville muunnoksille, kuten muotoilulle tai tyyppimuunnoksille, kaikissa soluissa.
DataFrame.applymap() on poistumassa käytöstä. Uusi suositeltava tapa on käyttää DataFrame.map()-menetelmää. Toiminnallisuus on sama. Käytämme tässä applymap()-menetelmää yhteensopivuuden vuoksi, mutta ole tietoinen tästä muutoksesta tulevaa koodia varten.
Käytännön esimerkki
Oletetaan, että meillä on alustaulukko, jossa on vain numeeriset sarakkeet, ja haluamme muotoilla ne kaikki valuuttajonoiksi raporttia varten.
numeric_df = df[['Price_USD', 'Quantity', 'Total_Cost']]
# Lambda-funktion käyttäminen jokaisen numeron muotoiluun
formatted_df = numeric_df.applymap(lambda x: f'${x:,.2f}')
print(formatted_df)
Tuloste:
Price_USD Quantity Total_Cost
0 $1,200.00 $1.00 $1,200.00
1 $25.00 $2.00 $50.00
2 $75.00 $1.00 $75.00
3 $300.00 $2.00 $600.00
4 $50.00 $1.00 $50.00
5 $150.00 $1.00 $150.00
6 $250.00 $1.00 $250.00
7 $30.00 $3.00 $90.00
Toinen yleinen käyttötarkoitus on siivota merkkijonodata DataFrame-objektista muuntamalla esimerkiksi kaikki pieniksi kirjaimiksi.
string_df = df[['Product', 'Category', 'Country']].copy() # Luo kopio SettingWithCopyWarning-varoituksen välttämiseksi
# Varmista, että kaikki arvot ovat merkkijonoja virheiden estämiseksi
string_df = string_df.astype(str)
lower_df = string_df.applymap(str.lower)
print(lower_df)
Milloin applymap()-menetelmää käytetään: Nopea yhteenveto
- Kun sinun on sovellettava yhtä, yksinkertaista funktiota jokaiseen elementtiin DataFrame-objektissa.
- Tehtäviin, kuten tietotyyppien muuntamiseen, merkkijonojen muotoiluun tai yksinkertaisiin matemaattisiin muunnoksiin koko DataFrame-objektissa.
- Muista sen poistuminen käytöstä
DataFrame.map()-menetelmän hyväksi uusimmissa Pandas-versioissa.
Suorituskyvyn syväluotaus: Vektorisointi vs. Iterointi
"Piilotettu" silmukka
Tämä on kriittisin käsite, joka on otettava haltuun korkean suorituskyvyn Pandas-koodin kirjoittamiseksi. Vaikka apply(), map() ja applymap() ovat käteviä, ne ovat olennaisesti vain hienoja kääreitä Python-silmukan ympärillä. Kun käytät df.apply(..., axis=1), Pandas iteroi DataFrame-objektisi rivi riviltä ja välittää jokaisen funktion. Tällä prosessilla on merkittäviä kustannuksia, ja se on paljon hitaampi kuin operaatiot, jotka on optimoitu C:ssä tai Cythonissa.
Vektorisoinnin voima
Vektorisointi on käytäntö, jossa operaatiot suoritetaan kokonaisille taulukoille (tai Series-objekteille) kerralla, eikä yksittäisille elementeille. Pandas ja sen taustalla oleva kirjasto, NumPy, on suunniteltu nimenomaan olemaan uskomattoman nopea vektorisoiduissa operaatioissa.
Palataan 'Total_Cost'-laskentaamme. Käytimme apply()-menetelmää, mutta onko vektorisoitua tapaa?
# Menetelmä 1: Käyttämällä apply() (Iterointi)
df['Total_Cost'] = df.apply(lambda row: row['Price_USD'] * row['Quantity'], axis=1)
# Menetelmä 2: Vektorisointi
df['Total_Cost_Vect'] = df['Price_USD'] * df['Quantity']
# Tarkista, ovatko tulokset samat
print(df['Total_Cost'].equals(df['Total_Cost_Vect'])) # Tuloste: True
Toinen menetelmä on vektorisoitu. Se ottaa koko 'Price_USD'-sarjan ja kertoo sen koko 'Quantity'-sarjalla yhdellä, erittäin optimoidulla operaatiolla. Jos aikoit nämä kaksi menetelmää suurella DataFrame-objektilla (miljoonilla riveillä), vektorisoitu lähestymistapa ei olisi vain nopeampi – se olisi suuruusluokkia nopeampi. Puhumme sekunneista minuutteihin tai minuuteista tunteihin.
Milloin apply()-menetelmää ei voi välttää?
Jos vektorisointi on niin paljon nopeampaa, miksi näitä muita menetelmiä on olemassa? Koska joskus logiikkasi on liian monimutkainen vektorisoitavaksi. apply() on tarpeellinen ja oikea työkalu, kun:
- Monimutkainen ehdollinen logiikka: Logiikkasi sisältää monimutkaisia `if/elif/else`-lauseita, jotka riippuvat useista sarakkeista, kuten `assign_shipping_priority`-esimerkki. Vaikka osa tästä voidaan saavuttaa `np.select()`-menetelmällä, siitä voi tulla lukukelvoton.
- Ulkoiset kirjastofunktiot: Sinun on sovellettava ulkoisen kirjaston funktiota tietoihisi. Esimerkiksi maantieteellisen kirjaston funktion soveltaminen etäisyyden laskemiseksi leveys- ja pituusaste-sarakkeiden perusteella tai luonnollisen kielen käsittelykirjaston (kuten NLTK:n) funktion soveltaminen tunneanalyysin suorittamiseksi tekstisarakkeessa.
- Iteratiiviset prosessit: Annetun rivin laskenta riippuu edellisellä rivillä lasketusta arvosta (vaikka tämä on harvinaista ja usein merkki siitä, että tarvitaan eri tietorakenne).
Paras käytäntö: Vektorisoi ensin, apply() toiseksi
Tämä johtaa Pandasin suorituskyvyn kultaiseen sääntöön:
Etsi aina ensin vektorisoitu ratkaisu. Käytä apply()-menetelmää tehokkaana, joustavana vaihtoehtona, kun vektorisoitu ratkaisu ei ole käytännöllinen tai mahdollinen.
Yhteenveto ja keskeiset opit: Oikean työkalun valitseminen
Käyttäkäämme tietomme selkeään päätöksentekokehykseen. Kun sinulla on mukautettu muunnostehtävä, kysy itseltäsi nämä kysymykset:
Vertailutaulukko
| Menetelmä | Toimii | Toiminnan laajuus | Funktio saa | Ensisijainen käyttötapaus |
|---|---|---|---|---|
| Vektorisointi | Series, DataFrame | Koko taulukko kerralla | Ei ole (operaatio on suora) | Aritmeettiset, loogiset operaatiot. Korkein suorituskyky. |
.map() |
Vain Series | Elementti kerrallaan | Yksi elementti | Arvojen korvaaminen sanakirjasta. |
.apply() |
Series, DataFrame | Rivi riviltä tai sarake sarakkeelta | Series (rivi tai sarake) | Monimutkainen logiikka käyttäen useita sarakkeita riviä kohti. |
.applymap() |
Vain DataFrame | Elementti kerrallaan | Yksi elementti | Muotoilu tai muuntaminen jokaisessa solussa DataFrame-objektissa. |
Päätöksen kulku
- Voidaanko operaationi ilmaista käyttämällä peruslaskutoimituksia (+, -, *, /) tai loogisia operaattoreita (&, |, ~) kokonaisille sarakkeille?
→ Kyllä? Käytä vektorisoitua lähestymistapaa. Tämä on nopein. (esim. `df['sarake1'] * df['sarake2']`) - Työskentelenkö vain yhden sarakkeen kanssa, ja onko päätavoitteeni korvata arvot sanakirjan perusteella?
→ Kyllä? KäytäSeries.map()-menetelmää. Se on optimoitu tähän. - Onko minun sovellettava funktiota jokaiseen elementtiin koko DataFrame-objektissani?
→ Kyllä? KäytäDataFrame.applymap()-menetelmää (taiDataFrame.map()-menetelmää uudemmissa Pandas-versioissa). - Onko logiikkani monimutkaista ja vaatii arvoja useista sarakkeista jokaisella rivillä yhden tuloksen laskemiseksi?
→ Kyllä? KäytäDataFrame.apply(..., axis=1)-menetelmää. Tämä on työkalusi monimutkaiseen, rivikohtaiseen logiikkaan.
Johtopäätös
Vaihtoehtojen navigoiminen mukautettujen funktioiden soveltamiseksi Pandasissa on siirtymäriitti kaikille datan harjoittajille. Vaikka ne saattavat aluksi vaikuttaa vaihdettavilta, map(), apply() ja applymap() ovat erillisiä työkaluja, joista jokaisella on omat vahvuutensa ja ihanteelliset käyttötapaukset. Ymmärtämällä niiden erot voit kirjoittaa koodia, joka ei ole vain oikea, vaan myös luettavampi, ylläpidettävämpi ja huomattavasti suorituskykyisempi.
Muista hierarkia: suosi vektorisointia sen raa'an nopeuden vuoksi, käytä map()-menetelmää sen tehokkaaseen Series-korvaamiseen, valitse applymap() DataFrame-laajuisille muunnoksille ja hyödynnä apply()-menetelmän voimaa ja joustavuutta monimutkaiseen rivi- tai sarakekohtaiseen logiikkaan, jota ei voida vektorisoida. Tämän tiedon avulla olet nyt paremmin varustautunut kohtaamaan kaikki datan manipulointihaasteet, jotka tulevat tielle, muuntamalla raakadatan tehokkaiksi oivalluksiksi taidolla ja tehokkuudella.