Atklājiet pilnu Pandas potenciālu, apgūstot pielāgotās funkcijas. Šī rokasgrāmata detalizēti apraksta atšķirības, veiktspēju un labākos pielietojumus apply(), map() un applymap() profesionālai datu analīzei.
Pandas apgūšana: dziļa ieniršana pielāgotās funkcijās ar apply(), map() un applymap()
Datu zinātnes un analīzes pasaulē Python Pandas bibliotēka ir neaizstājams rīks. Tā nodrošina jaudīgas, elastīgas un efektīvas datu struktūras, kas izstrādātas, lai darbu ar strukturētiem datiem padarītu gan vieglu, gan intuitīvu. Lai gan Pandas piedāvā bagātīgu iebūvēto funkciju klāstu agregācijai, filtrēšanai un transformācijai, katra datu profesionāļa ceļā pienāk brīdis, kad ar tām nepietiek. Jums ir jāpielieto sava pielāgotā loģika, unikāls biznesa noteikums vai sarežģīta transformācija, kas nav viegli pieejama.Šeit spēja pielietot pielāgotas funkcijas kļūst par superspēju. Tomēr Pandas piedāvā vairākus veidus, kā to panākt, galvenokārt izmantojot metodes apply(), map() un applymap(). Iesācējam šīs funkcijas var šķist mulsinoši līdzīgas. Kuru no tām vajadzētu izmantot? Kad? Un kādas ir jūsu izvēles sekas attiecībā uz veiktspēju?
Šī visaptverošā rokasgrāmata atklās šo jaudīgo metožu noslēpumus. Mēs detalizēti izpētīsim katru no tām, sapratīsim to specifiskos pielietojuma gadījumus un, pats galvenais, iemācīsimies izvēlēties pareizo rīku, lai rakstītu tīru, efektīvu un lasāmu Pandas kodu. Mēs apskatīsim:
- Metode
map(): Ideāli piemērota elementu līmeņa transformācijai vienā Series (kolonnā). - Metode
apply(): Daudzpusīgs darba zirgs rindu vai kolonnu līmeņa operācijām ar DataFrame. - Metode
applymap(): Speciālists elementu līmeņa operācijām visā DataFrame. - Veiktspējas apsvērumi: Būtiskā atšķirība starp šīm metodēm un īstu vektorizāciju.
- Labākās prakses: Lēmumu pieņemšanas ietvars, kas palīdzēs jums katru reizi izvēlēties visefektīvāko metodi.
Sagatavošanās: Mūsu datu kopas paraugs
Lai mūsu piemēri būtu praktiski un skaidri, strādāsim ar konsekventu, globāli atbilstošu datu kopu. Mēs izveidosim DataFrame paraugu, kas atspoguļo tiešsaistes pārdošanas datus no fiktīva starptautiska e-komercijas uzņēmuma.
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)
Šis DataFrame sniedz mums labu datu tipu sajaukumu (skaitlisku, teksta un pat trūkstošu vērtību), lai demonstrētu mūsu mērķa funkciju pilnās iespējas.
Metode `map()`: Elementu līmeņa transformācija Series (kolonnai)
Kas ir `map()`?
Metode map() ir jūsu specializētais rīks vērtību modificēšanai vienā kolonnā (Pandas Series). Tā darbojas uz katra elementa pamata. Iedomājieties to kā teikumu: "Katram elementam šajā kolonnā, sameklē to vārdnīcā vai nodod šai funkcijai un aizstāj to ar rezultātu."
To galvenokārt izmanto diviem uzdevumiem:
- Vērtību aizstāšanai, pamatojoties uz vārdnīcu (kartēšanu).
- Vienkāršas funkcijas pielietošanai katram elementam.
1. pielietojuma gadījums: Vērtību kartēšana ar vārdnīcu
Šis ir visizplatītākais un efektīvākais map() pielietojums. Iedomājieties, ka mēs vēlamies izveidot plašāku kolonnu 'Department' (Nodaļa), pamatojoties uz mūsu 'Category' (Kategorija) kolonnu. Mēs varam definēt kartēšanu Python vārdnīcā un izmantot map(), lai to pielietotu.
category_to_department = {
'Electronics': 'Technology',
'Accessories': 'Peripherals',
'Audio': 'Technology'
}
df['Department'] = df['Category'].map(category_to_department)
print(df[['Category', 'Department']])
Izvade:
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
Ievērojiet, cik eleganti tas darbojas. Katra vērtība 'Category' Series tiek meklēta `category_to_department` vārdnīcā, un atbilstošā vērtība tiek izmantota, lai aizpildītu jauno 'Department' kolonnu. Ja atslēga vārdnīcā netiek atrasta, map() radīs NaN (Not a Number) vērtību, kas bieži vien ir vēlamā rīcība nekartētām kategorijām.
2. pielietojuma gadījums: Funkcijas pielietošana ar `map()`
Jūs varat arī nodot funkciju (ieskaitot lambda funkciju) metodei map(). Funkcija tiks izpildīta katram elementam Series. Izveidosim jaunu kolonnu, kas mums sniedz aprakstošu cenu zīmi.
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)
# Using a lambda function for a simpler task:
# df['Product_Length'] = df['Product'].map(lambda x: len(x))
print(df[['Product', 'Price_USD', 'Price_Label']])
Izvade:
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
Kad lietot `map()`: Īss kopsavilkums
- Jūs strādājat ar vienu kolonnu (Series).
- Jums ir jāaizstāj vērtības, pamatojoties uz vārdnīcu vai citu Series. Šī ir tās galvenā priekšrocība.
- Jums ir jāpielieto vienkārša elementu līmeņa funkcija vienai kolonnai.
Metode `apply()`: Daudzpusīgais darba zirgs
Kas ir `apply()`?
Ja map() ir speciālists, tad apply() ir vispārējas nozīmes spēkstacija. Tā ir elastīgāka, jo var darboties gan ar Series, gan ar DataFrame. Galvenais, lai saprastu apply(), ir parametrs axis, kas nosaka tās darbību:
- Series gadījumā: Tā darbojas elementu līmenī, līdzīgi kā
map(). - DataFrame gadījumā ar
axis=0(noklusējums): Tā pielieto funkciju katrai kolonnai. Funkcija saņem katru kolonnu kā Series. - DataFrame gadījumā ar
axis=1: Tā pielieto funkciju katrai rindai. Funkcija saņem katru rindu kā Series.
`apply()` lietošana Series
Lietojot Series, apply() darbojas ļoti līdzīgi kā map(). Tā pielieto funkciju katram elementam. Piemēram, mēs varētu atkārtot mūsu cenu zīmju piemēru.
df['Price_Label_apply'] = df['Price_USD'].apply(price_label)
print(df['Price_Label_apply'].equals(df['Price_Label'])) # Output: True
Lai gan šeit tās šķiet aizvietojamas, map() bieži ir nedaudz ātrāka vienkāršām vārdnīcu aizstāšanām un elementu līmeņa operācijām ar Series, jo tai ir optimizētāks ceļš šiem konkrētajiem uzdevumiem.
`apply()` lietošana DataFrame (pa kolonnām, `axis=0`)
Šis ir noklusējuma režīms DataFrame. Jūsu norādītā funkcija tiek izsaukta vienreiz katrai kolonnai. Tas ir noderīgi kolonnu līmeņa agregācijām vai transformācijām.
Atradīsim starpību starp maksimālo un minimālo vērtību (diapazonu) katrai mūsu skaitliskajai kolonnai.
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)
Izvade:
Price_USD 1175.0
Quantity 2.0
dtype: float64
Šeit get_range funkcija vispirms saņēma 'Price_USD' Series, aprēķināja tās diapazonu, pēc tam saņēma 'Quantity' Series un izdarīja to pašu, atgriežot jaunu Series ar rezultātiem.
`apply()` lietošana DataFrame (pa rindām, `axis=1`)
Šis, iespējams, ir visspēcīgākais un izplatītākais apply() pielietojuma gadījums. Kad jums ir jāaprēķina jauna vērtība, pamatojoties uz vairākām kolonnām vienā rindā, apply() ar axis=1 ir jūsu risinājums.
Funkcija, kuru jūs nodosiet, saņems katru rindu kā Series, kur indekss ir kolonnu nosaukumi. Aprēķināsim kopējās izmaksas katram pasūtījumam.
def calculate_total_cost(row):
# 'row' is a Series representing a single row
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']])
Izvade:
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
To map() vienkārši nevar izdarīt, jo tā ir ierobežota ar vienu kolonnu. Apskatīsim sarežģītāku piemēru. Mēs vēlamies kategorizēt katra pasūtījuma piegādes prioritāti, pamatojoties uz tā kategoriju un valsti.
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']])
Kad lietot `apply()`: Īss kopsavilkums
- Kad jūsu loģika ir atkarīga no vairākām kolonnām vienā rindā (izmantojiet
axis=1). Šī ir tās galvenā priekšrocība. - Kad jums ir jāpielieto agregācijas funkcija pa kolonnām vai rindām.
- Kā vispārējas nozīmes funkciju pielietošanas rīks, kad
map()nav piemērota.
Īpaša pieminēšana: Metode `applymap()`
Kas ir `applymap()`?
Metode applymap() ir vēl viens speciālists, bet tās domēns ir viss DataFrame. Tā pielieto funkciju katram atsevišķam elementam DataFrame. Tā nedarbojas ar Series — tā ir metode, kas paredzēta tikai DataFrame.
Iedomājieties to kā map() palaišanu katrai kolonnai vienlaicīgi. Tā ir noderīga plašām, visaptverošām transformācijām, piemēram, formatēšanai vai tipa konvertēšanai visās šūnās.
DataFrame.applymap() tiek novecojusi. Jaunais ieteicamais veids ir izmantot DataFrame.map(). Funkcionalitāte ir tāda pati. Šeit mēs izmantosim applymap() saderības dēļ, bet esiet informēti par šīm izmaiņām nākotnes kodā.
Praktisks piemērs
Pieņemsim, ka mums ir apakš-DataFrame tikai ar mūsu skaitliskajām kolonnām un mēs vēlamies tās visas formatēt kā valūtas virknes atskaitei.
numeric_df = df[['Price_USD', 'Quantity', 'Total_Cost']]
# Using a lambda function to format each number
formatted_df = numeric_df.applymap(lambda x: f'${x:,.2f}')
print(formatted_df)
Izvade:
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
Vēl viens izplatīts pielietojums ir sakopt DataFrame ar teksta datiem, piemēram, pārvēršot visu uz mazajiem burtiem.
string_df = df[['Product', 'Category', 'Country']].copy() # Create a copy to avoid SettingWithCopyWarning
# Ensure all values are strings to prevent errors
string_df = string_df.astype(str)
lower_df = string_df.applymap(str.lower)
print(lower_df)
Kad lietot `applymap()`: Īss kopsavilkums
- Kad jums ir jāpielieto viena, vienkārša funkcija katram elementam DataFrame.
- Uzdevumiem, piemēram, datu tipa konvertēšanai, virkņu formatēšanai vai vienkāršām matemātiskām transformācijām visā DataFrame.
- Atcerieties, ka jaunākajās Pandas versijās tā ir novecojusi par labu
DataFrame.map().
Veiktspējas analīze: Vektorizācija pret iterāciju
"Slēptais" cikls
Šis ir vissvarīgākais jēdziens, kas jāapgūst, lai rakstītu augstas veiktspējas Pandas kodu. Lai gan apply(), map() un applymap() ir ērtas, tās būtībā ir tikai eleganti ietvari ap Python ciklu. Kad jūs izmantojat df.apply(..., axis=1), Pandas iterē cauri jūsu DataFrame rindu pa rindai, nododot katru no tām jūsu funkcijai. Šim procesam ir ievērojamas pieskaitāmās izmaksas, un tas ir daudz lēnāks nekā operācijas, kas optimizētas C vai Cython.
Vektorizācijas spēks
Vektorizācija ir prakse veikt operācijas ar veseliem masīviem (vai Series) vienlaicīgi, nevis ar atsevišķiem elementiem. Pandas un tās pamatā esošā bibliotēka NumPy ir īpaši izstrādātas, lai būtu neticami ātras vektorizētās operācijās.
Atgriezīsimies pie mūsu 'Total_Cost' aprēķina. Mēs izmantojām apply(), bet vai pastāv vektorizēts veids?
# Method 1: Using apply() (Iteration)
df['Total_Cost'] = df.apply(lambda row: row['Price_USD'] * row['Quantity'], axis=1)
# Method 2: Vectorized Operation
df['Total_Cost_Vect'] = df['Price_USD'] * df['Quantity']
# Check if the results are the same
print(df['Total_Cost'].equals(df['Total_Cost_Vect'])) # Output: True
Otrā metode ir vektorizēta. Tā paņem visu 'Price_USD' Series un reizina to ar visu 'Quantity' Series vienā, augsti optimizētā operācijā. Ja jūs mērītu laiku šīm divām metodēm uz liela DataFrame (miljoniem rindu), vektorizētā pieeja būtu ne tikai ātrāka — tā būtu par vairākām kārtām ātrāka. Mēs runājam par sekundēm pret minūtēm, vai minūtēm pret stundām.
Kad no `apply()` nevar izvairīties?
Ja vektorizācija ir tik daudz ātrāka, kāpēc pastāv šīs citas metodes? Tāpēc, ka dažreiz jūsu loģika ir pārāk sarežģīta, lai to vektorizētu. apply() ir nepieciešamais un pareizais rīks, kad:
- Sarežģīta nosacījumu loģika: Jūsu loģika ietver sarežģītus `if/elif/else` apgalvojumus, kas atkarīgi no vairākām kolonnām, kā mūsu `assign_shipping_priority` piemērā. Lai gan daļu no tā var panākt ar `np.select()`, kods var kļūt nesalasāms.
- Ārējo bibliotēku funkcijas: Jums ir jāpielieto funkcija no ārējas bibliotēkas saviem datiem. Piemēram, pielietojot funkciju no ģeotelpiskās bibliotēkas, lai aprēķinātu attālumu, pamatojoties uz platuma un garuma kolonnām, vai funkciju no dabiskās valodas apstrādes bibliotēkas (piemēram, NLTK), lai veiktu noskaņojuma analīzi teksta kolonnai.
- Iteratīvi procesi: Aprēķins konkrētai rindai ir atkarīgs no vērtības, kas aprēķināta iepriekšējā rindā (lai gan tas ir reti un bieži vien liecina, ka ir nepieciešama cita datu struktūra).
Labākā prakse: Vispirms vektorizācija, pēc tam `apply()`
Tas noved pie Pandas veiktspējas zelta likuma:
Vienmēr vispirms meklējiet vektorizētu risinājumu. Izmantojiet apply() kā savu jaudīgo, elastīgo rezerves variantu, kad vektorizēts risinājums nav praktisks vai iespējams.
Kopsavilkums un galvenie secinājumi: Pareizā rīka izvēle
Apkoposim mūsu zināšanas skaidrā lēmumu pieņemšanas ietvarā. Saskaroties ar pielāgotu transformācijas uzdevumu, uzdodiet sev šos jautājumus:
Salīdzinājuma tabula
| Metode | Darbojas ar | Operācijas apjoms | Funkcija saņem | Primārais pielietojums |
|---|---|---|---|---|
| Vektorizācija | Series, DataFrame | Viss masīvs vienlaicīgi | N/A (operācija ir tieša) | Aritmētiskās, loģiskās operācijas. Visaugstākā veiktspēja. |
.map() |
Tikai Series | Elements pa elementam | Viens elements | Vērtību aizstāšana no vārdnīcas. |
.apply() |
Series, DataFrame | Rindu pa rindai vai kolonnu pa kolonnai | Series (rinda vai kolonna) | Sarežģīta loģika, izmantojot vairākas kolonnas vienā rindā. |
.applymap() |
Tikai DataFrame | Elements pa elementam | Viens elements | Katras šūnas formatēšana vai transformēšana DataFrame. |
Lēmumu pieņemšanas blokshēma
- Vai manu operāciju var izteikt, izmantojot pamata aritmētiku (+, -, *, /) vai loģiskos operatorus (&, |, ~) visām kolonnām?
→ Jā? Izmantojiet vektorizētu pieeju. Tā ir visātrākā. (piem., `df['col1'] * df['col2']`) - Vai es strādāju tikai ar vienu kolonnu, un mans galvenais mērķis ir aizstāt vērtības, pamatojoties uz vārdnīcu?
→ Jā? IzmantojietSeries.map(). Tā ir optimizēta šim nolūkam. - Vai man ir jāpielieto funkcija katram atsevišķam elementam visā manā DataFrame?
→ Jā? IzmantojietDataFrame.applymap()(vaiDataFrame.map()jaunākās Pandas versijās). - Vai mana loģika ir sarežģīta un prasa vērtības no vairākām kolonnām katrā rindā, lai aprēķinātu vienu rezultātu?
→ Jā? IzmantojietDataFrame.apply(..., axis=1). Šis ir jūsu rīks sarežģītai, rindu līmeņa loģikai.
Noslēgums
Navigācija pa pielāgoto funkciju pielietošanas iespējām Pandas ir ikviena datu praktiķa iniciācijas rituāls. Lai gan sākumā tās var šķist savstarpēji aizvietojamas, map(), apply() un applymap() ir atšķirīgi rīki, katrs ar savām stiprajām pusēm un ideāliem pielietojuma gadījumiem. Izprotot to atšķirības, jūs varat rakstīt kodu, kas ir ne tikai pareizs, bet arī lasāmāks, uzturamāks un ievērojami veiktspējīgāks.
Atcerieties hierarhiju: dodiet priekšroku vektorizācijai tās neapstrādātā ātruma dēļ, izmantojiet map() tās efektīvajai Series aizstāšanai, izvēlieties applymap() visaptverošām DataFrame transformācijām un izmantojiet apply() jaudu un elastību sarežģītai rindu vai kolonnu līmeņa loģikai, ko nevar vektorizēt. Apbruņojušies ar šīm zināšanām, jūs tagad esat labāk sagatavoti, lai risinātu jebkuru datu manipulācijas izaicinājumu, kas jums gadās ceļā, ar prasmi un efektivitāti pārveidojot neapstrādātus datus jaudīgās atziņās.