偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

一文了解 Pandas 的 apply 函數(shù)妙用

開(kāi)發(fā)
在眾多方法中,apply() 函數(shù)以其靈活性脫穎而出,是處理復(fù)雜數(shù)據(jù)轉(zhuǎn)換和應(yīng)用自定義邏輯的強(qiáng)大工具。本文將介紹apply() 函數(shù)的用途、原理以及如何在實(shí)際工作中發(fā)揮它的“妙用”。

在數(shù)據(jù)處理和分析領(lǐng)域,Pandas DataFame 是我們最常用的數(shù)據(jù)結(jié)構(gòu)之一。它提供了豐富的功能來(lái)清洗、轉(zhuǎn)換和分析數(shù)據(jù)。在眾多方法中,apply() 函數(shù)以其靈活性脫穎而出,是處理復(fù)雜數(shù)據(jù)轉(zhuǎn)換和應(yīng)用自定義邏輯的強(qiáng)大工具。本文將介紹apply() 函數(shù)的用途、原理以及如何在實(shí)際工作中發(fā)揮它的“妙用”。

一、apply 函數(shù)介紹

apply() 是 Pandas Series 和 DataFrame 對(duì)象的一個(gè)方法,用于沿軸(axis)應(yīng)用函數(shù)。簡(jiǎn)單來(lái)說(shuō),就是把一個(gè)函數(shù)批量地作用于 DataFrame 的行、列或 Series 的元素。

DataFrame.apply(func, axis=0, raw=False, result_type=None, args=(), **kwds)
Series.apply(func, convert_dtype=True, args=(), **kwds)

其中最重要的參數(shù)是 axis:

  • axis=0 (默認(rèn)): 將函數(shù)應(yīng)用到 每一列。此時(shí),函數(shù)接收一個(gè) Series 對(duì)象(即 DataFrame 的每一列)。
  • axis=1: 將函數(shù)應(yīng)用到 每一行。此時(shí),函數(shù)接收一個(gè) Series 對(duì)象(即 DataFrame 的每一行)。

對(duì)于 Series 的 apply 方法,axis 參數(shù)不存在,函數(shù)直接作用于 Series 的每個(gè)元素(或 Series 本身,取決于函數(shù)定義)。

二、apply() 的應(yīng)用場(chǎng)景與優(yōu)勢(shì)

Pandas 提供了大量高度優(yōu)化的內(nèi)置函數(shù)(如 sum(), mean(), fillna(), str.contains() 等)和向量化操作(如直接的四則運(yùn)算 df['A'] + df['B'])。這些方法通常效率最高,應(yīng)優(yōu)先使用。

那么,什么時(shí)候需要 apply() 呢?apply() 的妙用體現(xiàn)在以下場(chǎng)景:

  • 函數(shù)無(wú)法直接向量化: 當(dāng)你需要應(yīng)用的邏輯比較復(fù)雜,無(wú)法用簡(jiǎn)單的數(shù)學(xué)運(yùn)算、布爾索引或 Pandas 內(nèi)置方法直接表示時(shí),可以將其封裝在一個(gè) Python 函數(shù)中,然后使用 apply() 應(yīng)用。
  • 處理行級(jí)別或列級(jí)別的復(fù)雜邏輯: 尤其是 axis=1 時(shí),你的函數(shù)可以訪(fǎng)問(wèn)到一整行的所有列的數(shù)據(jù),從而基于行內(nèi)多個(gè)值進(jìn)行判斷、計(jì)算或生成結(jié)果。這在需要上下文信息的處理中非常有用。
  • 返回值多樣化: apply() 可以返回一個(gè) Series (對(duì)應(yīng)原始 Series 或 DataFrame 的新一列/一行),也可以在特定配置下返回多個(gè)值(展開(kāi)為新的多列)。

相比于直接使用 Python 循環(huán)遍歷 DataFrame 的行(如 for index, row in df.iterrows():),apply() 在內(nèi)部通常會(huì)做一些優(yōu)化,雖然可能不如純粹的向量化操作快,但通常比顯式 Python 循環(huán)要高效且代碼更簡(jiǎn)潔、更具“Pandas風(fēng)格”。

三、apply() 函數(shù)的妙用示例

為了更好地理解 apply() 的強(qiáng)大之處,我們來(lái)看幾個(gè)實(shí)際案例。

首先,創(chuàng)建一個(gè)示例 DataFrame:

import pandas as pd
import numpy as np

data = {
    'StudentID': [1, 2, 3, 4, 5, 6, 7, 8],
    'Name': ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Henry'],
    'Gender': ['F', 'M', 'M', 'M', 'F', 'M', 'F', 'M'],
    'MathScore': [85, 90, 78, np.nan, 92, 70, 88, 95],
    'EnglishScore': [90, 88, 85, 92, np.nan, 75, 91, 89],
    'Class': ['A', 'B', 'A', 'C', 'B', 'C', 'A', 'B']
}
df = pd.DataFrame(data)
print("--- 原始 DataFrame ---")
print(df)
print("\n")

案例 1: 對(duì)列應(yīng)用統(tǒng)計(jì)函數(shù) (axis=0)

# 定義一個(gè)計(jì)算極差的函數(shù)
def range_score(col):
    # 需要處理缺失值,這里選擇忽略NaN
    return col.max() - col.min()

# 對(duì)數(shù)值列應(yīng)用 range_score 函數(shù) (axis=0 是默認(rèn)值,可省略)
# 僅選擇數(shù)值列進(jìn)行計(jì)算
numeric_cols = df.select_dtypes(include=np.number).columns
score_ranges = df[numeric_cols].apply(range_score, axis=0)

print("--- 各數(shù)值列的分?jǐn)?shù)極差 ---")
print(score_ranges)
print("\n")

當(dāng) axis=0 時(shí),apply() 會(huì)將 DataFrame 的每一列(作為一個(gè) Series)依次傳遞給 range_score 函數(shù)。函數(shù)計(jì)算后返回一個(gè)值,這些值最終組合成一個(gè)新的 Series,索引是原始 DataFrame 的列名。

案例 2: 對(duì)行應(yīng)用判斷邏輯 (axis=1)

根據(jù)一個(gè)學(xué)生的數(shù)學(xué)和英語(yǔ)成績(jī)總分來(lái)判斷其等級(jí)。這個(gè)邏輯需要同時(shí)考慮一行中的兩個(gè)列的值。

# 定義一個(gè)根據(jù)總分判斷等級(jí)的函數(shù)
def judge_grade(row):
    # 訪(fǎng)問(wèn)行中的列數(shù)據(jù)
    total_score = row['MathScore'] + row['EnglishScore']

    # 處理總分因缺失值而為 NaN 的情況
    if pd.isna(total_score):
        return'待定'# Or 'N/A', '未知'
    elif total_score >= 180:
        return'優(yōu)秀'
    elif total_score >= 150:
        return'良好'
    else:
        return'及格'

# 對(duì) DataFrame 的每一行應(yīng)用 judge_grade 函數(shù)
# axis=1 表示按行應(yīng)用,函數(shù)的輸入是每一行的數(shù)據(jù) (一個(gè) Series)
df['OverallGrade'] = df.apply(judge_grade, axis=1)

print("--- 添加等級(jí)列后的 DataFrame (部分) ---")
print(df[['StudentID', 'MathScore', 'EnglishScore', 'OverallGrade']])
print("\n")

axis=1 是此例的關(guān)鍵。它讓 apply() 將 DataFrame 的每一行作為參數(shù)(一個(gè) Series,其中索引是原始列名)傳遞給 judge_grade 函數(shù)。在函數(shù)內(nèi)部,我們可以方便地通過(guò) row['列名'] 的方式獲取該行對(duì)應(yīng)列的值,進(jìn)行復(fù)雜的邏輯判斷。函數(shù)的返回值(一個(gè)字符串)會(huì)組成新的 Series,被賦值給新列 'OverallGrade'。

案例 3: 行級(jí)別復(fù)雜計(jì)算并返回多個(gè)結(jié)果 (axis=1, result_type='expand')

有時(shí),一個(gè)行級(jí)別的計(jì)算或處理可能需要返回多個(gè)值,例如從一個(gè)包含全名的列中提取姓和名,或者計(jì)算某行數(shù)據(jù)的多個(gè)統(tǒng)計(jì)指標(biāo)。

# 定義一個(gè)函數(shù),從 Name 列中提取姓和名
def split_name_parts(row):
    full_name = row['Name']
    parts = full_name.split(' ', 1) # 最多分割一次
    first_name = parts[0]
    last_name = parts[1] if len(parts) > 1else''# 如果沒(méi)有空格,則姓為空

    # 返回一個(gè) Series 或 List
    return pd.Series([first_name, last_name])

# 對(duì) DataFrame 的每一行應(yīng)用 split_name_parts 函數(shù)
# axis=1 按行應(yīng)用
# result_type='expand' 將函數(shù)返回的 Series/List 展開(kāi)成多列
name_parts = df.apply(split_name_parts, axis=1, result_type='expand')

# 將新生成的列添加到原 DataFrame 中
df[['FirstName', 'LastName']] = name_parts
# 也可以直接這樣寫(xiě):
# df[['FirstName', 'LastName']] = df.apply(split_name_parts, axis=1, result_type='expand')


print("--- 添加姓和名列后的 DataFrame (部分) ---")
df[['Name', 'FirstName', 'LastName']]

函數(shù) split_name_parts 處理每一行的 'Name' 列,并返回一個(gè)包含兩個(gè)元素的 Series。通過(guò)設(shè)置 result_type='expand',Pandas 會(huì)將這個(gè) Series 的每個(gè)元素作為新列添加到結(jié)果中。這種方法非常適合批量解析、分解或從復(fù)雜數(shù)據(jù)中提取多個(gè)字段。

案例 4: 結(jié)合 Lambda 表達(dá)式的簡(jiǎn)潔用法

對(duì)于簡(jiǎn)單的、單行的函數(shù)邏輯,可以使用 Lambda 表達(dá)式與 apply() 結(jié)合,使代碼更簡(jiǎn)潔。

# 場(chǎng)景:根據(jù) MathScore 是否大于等于 90 創(chuàng)建一個(gè)布爾列 'MathExcellent'
# 使用 apply 結(jié)合 lambda 和 axis=1
df['MathExcellent_apply'] = df.apply(lambda row: row['MathScore'] >= 90 if pd.notna(row['MathScore']) else False, axis=1)

# (對(duì)比向量化寫(xiě)法,通常更簡(jiǎn)潔高效)
# df['MathExcellent_vec'] = df['MathScore'] >= 90 # 會(huì)將 NaN 結(jié)果為 False/True, 需額外處理 NaN

print("--- 使用 Lambda 和 apply 添加布爾列 (部分) ---")
print(df[['StudentID', 'MathScore', 'MathExcellent_apply']]) # , 'MathExcellent_vec'
print("\n")

Lambda 表達(dá)式提供了一種創(chuàng)建小型匿名函數(shù)的快捷方式。在 apply() 中,尤其是在 axis=1 需要快速訪(fǎng)問(wèn)單行數(shù)據(jù)時(shí),Lambda 表達(dá)式非常方便。雖然此處向量化寫(xiě)法更優(yōu),但對(duì)于涉及更復(fù)雜條件或多列組合判斷的布爾邏輯,apply(lambda row: ..., axis=1) 結(jié)合 if/else 是常見(jiàn)的模式。

四、使用 apply() 的注意事項(xiàng)

盡管 apply() 非常靈活,但需要注意其潛在的性能問(wèn)題:

  • 優(yōu)先使用向量化操作: Pandas 的許多操作都是經(jīng)過(guò)高度優(yōu)化的 C 實(shí)現(xiàn)。如果你的任務(wù)可以通過(guò)向量化運(yùn)算、Pandas 內(nèi)置方法或 Numpy 函數(shù)直接完成,應(yīng)優(yōu)先考慮它們,它們通常比 apply() 快得多。
  • apply() 與循環(huán): 在許多情況下,apply() 比顯式的 Python for 循環(huán)遍歷行要快,因?yàn)樗诘讓涌赡苓M(jìn)行了部分向量化或更好的內(nèi)存管理。但在某些極端場(chǎng)景或非常簡(jiǎn)單的操作中,性能差異可能不明顯。
  • apply(axis=1) 的開(kāi)銷(xiāo): 對(duì)行應(yīng)用函數(shù) (axis=1) 通常比對(duì)列應(yīng)用 (axis=0) 開(kāi)銷(xiāo)更大,因?yàn)樗枰獮槊恳恍袆?chuàng)建一個(gè) Series 對(duì)象并調(diào)用 Python 函數(shù)。
  • 避免在 apply 中進(jìn)行昂貴的重復(fù)計(jì)算: 如果函數(shù)內(nèi)部有可以在外部一次性計(jì)算并傳入的參數(shù),盡量這樣做。

總的來(lái)說(shuō),apply() 是一個(gè)強(qiáng)大的工具,尤其適用于處理那些無(wú)法簡(jiǎn)單向量化,需要訪(fǎng)問(wèn)行或列的全部上下文的復(fù)雜邏輯。在處理大型數(shù)據(jù)集對(duì)性能要求極高時(shí),可以考慮 Numba 或 Cython 等更底層的優(yōu)化工具,但對(duì)于大多數(shù)日常任務(wù),apply() 提供的便利性是無(wú)可替代的。

責(zé)任編輯:趙寧寧 來(lái)源: Python數(shù)智工坊
相關(guān)推薦

2020-08-27 07:34:50

Zookeeper數(shù)據(jù)結(jié)構(gòu)

2019-08-06 09:00:00

JavaScript函數(shù)式編程前端

2024-02-01 11:57:31

this指針代碼C++

2023-11-20 08:18:49

Netty服務(wù)器

2023-04-26 15:43:24

容器編排容器編排工具

2020-04-21 10:37:41

Apply數(shù)據(jù)參數(shù)

2022-02-25 07:34:36

MQTT協(xié)議RabbitMQ

2022-06-08 08:11:56

威脅建模網(wǎng)絡(luò)安全網(wǎng)絡(luò)攻擊

2025-05-23 09:38:54

JWT開(kāi)發(fā)Go

2022-11-11 19:09:13

架構(gòu)

2023-11-06 08:16:19

APM系統(tǒng)運(yùn)維

2021-09-27 07:39:52

Go初始化函數(shù)package

2023-12-26 07:33:45

Redis持久化COW

2022-10-28 13:48:24

Notebook數(shù)據(jù)開(kāi)發(fā)機(jī)器學(xué)習(xí)

2024-01-19 11:53:29

文件系統(tǒng)操作系統(tǒng)存儲(chǔ)

2022-02-24 07:34:10

SSL協(xié)議加密

2023-11-08 08:15:48

服務(wù)監(jiān)控Zipkin

2023-08-26 20:56:02

滑動(dòng)窗口協(xié)議

2023-10-27 08:15:45

2024-07-26 00:00:10

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)