Pandas數(shù)據(jù)索引核心:loc與iloc的深度解析與實(shí)戰(zhàn)避坑指南
1. 項(xiàng)目概述為什么loc和iloc是Pandas的靈魂如果你用過Pandas處理數(shù)據(jù)那對loc和iloc這兩個(gè)方法一定不陌生。它們就像是打開數(shù)據(jù)寶庫的兩把鑰匙一把叫“標(biāo)簽”一把叫“位置”。但很多朋友包括我剛開始用的時(shí)候都容易把它們搞混或者只停留在“l(fā)oc用標(biāo)簽iloc用整數(shù)”這個(gè)淺層理解上。結(jié)果就是寫出來的代碼要么運(yùn)行報(bào)錯(cuò)要么選出來的數(shù)據(jù)不是自己想要的調(diào)試半天效率極低。我見過不少同事在處理一個(gè)簡單的數(shù)據(jù)篩選任務(wù)時(shí)因?yàn)閷@兩個(gè)方法的邊界條件理解不透寫出的df.loc[0:5]本意是想選前6行結(jié)果在索引不是默認(rèn)整數(shù)時(shí)選出來的數(shù)據(jù)完全不對導(dǎo)致后續(xù)分析全盤皆錯(cuò)。這不僅僅是浪費(fèi)了時(shí)間更可能因?yàn)閿?shù)據(jù)錯(cuò)誤得出誤導(dǎo)性的結(jié)論。所以今天我就想結(jié)合我這些年踩過的坑和積累的經(jīng)驗(yàn)把loc和iloc掰開了、揉碎了講清楚。這不僅僅是兩個(gè)函數(shù)的用法更是理解Pandas數(shù)據(jù)索引底層邏輯的基石。掌握了它們你才能說真正會(huì)“定位”Pandas里的數(shù)據(jù)無論是處理幾十行的測試數(shù)據(jù)還是操縱百萬行級別的商業(yè)數(shù)據(jù)都能得心應(yīng)手。簡單來說loc和iloc的核心區(qū)別在于索引的參照系不同。loc是基于軸標(biāo)簽index和columns的“名字”進(jìn)行選擇的而iloc是基于軸位置從0開始的整數(shù)位置進(jìn)行選擇的。這個(gè)根本性的差異衍生出了它們在切片、布爾索引、函數(shù)應(yīng)用等幾乎所有場景下的不同行為。接下來我們就從最基礎(chǔ)的場景開始一步步深入到高級用法和那些容易踩坑的細(xì)節(jié)里。2. 核心概念辨析標(biāo)簽與位置的本質(zhì)差異在深入代碼之前我們必須先建立正確的心理模型。你可以把DataFrame想象成一張Excel表格。這張表格有行和列Pandas為它們分別設(shè)置了“坐標(biāo)系統(tǒng)”。2.1 標(biāo)簽索引loc按“名字”找人loc使用的坐標(biāo)系統(tǒng)是標(biāo)簽。行的標(biāo)簽就是索引index列的標(biāo)簽就是列名columns。這就像你用“姓名”和“部門”來定位一個(gè)同事一樣。關(guān)鍵特性包含端點(diǎn)在使用切片時(shí)loc是包含起始和結(jié)束標(biāo)簽的。這是與Python原生列表切片以及iloc最顯著的區(qū)別之一。靈活的數(shù)據(jù)類型索引和列名可以是整數(shù)、字符串、甚至日期時(shí)間類型。loc不關(guān)心它們的實(shí)際值是什么類型只把它們當(dāng)作唯一的標(biāo)識(shí)符。與索引順序強(qiáng)相關(guān)loc的查找效率與索引的排序和唯一性有很大關(guān)系。如果索引是排序且唯一的Pandas會(huì)用更快的哈希查找否則可能需要遍歷。舉個(gè)例子假設(shè)我們有一個(gè)員工信息表import pandas as pd data { ‘姓名‘: [‘張三‘, ‘李四‘, ‘王五‘, ‘趙六‘], ‘部門‘: [‘技術(shù)部‘, ‘市場部‘, ‘技術(shù)部‘, ‘人事部‘], ‘年齡‘: [28, 32, 25, 35], ‘入職年份‘: [2019, 2017, 2020, 2015] } df pd.DataFrame(data) df.set_index(‘姓名‘, inplaceTrue) # 將‘姓名‘列設(shè)為索引 print(df)輸出部門 年齡 入職年份 姓名 張三 技術(shù)部 28 2019 李四 市場部 32 2017 王五 技術(shù)部 25 2020 趙六 人事部 35 2015現(xiàn)在我想獲取“李四”的信息并只看他的“部門”和“年齡”。用loc就是這樣# 選取單個(gè)標(biāo)簽行 print(df.loc[‘李四‘]) # 輸出一個(gè)Series部門-市場部 年齡-32 入職年份-2017 # 選取單個(gè)標(biāo)簽行和單個(gè)標(biāo)簽列 print(df.loc[‘李四‘, ‘部門‘]) # 輸出標(biāo)量‘市場部‘ # 選取單個(gè)標(biāo)簽行和多個(gè)標(biāo)簽列 print(df.loc[‘李四‘, [‘部門‘, ‘年齡‘]]) # 輸出一個(gè)Series2.2 位置索引iloc按“座位號(hào)”找人iloc使用的坐標(biāo)系統(tǒng)是整數(shù)位置。無論你的索引和列名是什么它只認(rèn)從0開始計(jì)數(shù)的第幾行、第幾列。這就像電影院里的座位第1排第3座不管坐的是誰位置是固定的。關(guān)鍵特性不包含端點(diǎn)在使用切片時(shí)iloc遵循Python的“左閉右開”規(guī)則。df.iloc[0:3]選取的是第0, 1, 2行不包括第3行。只接受整數(shù)iloc的索引器必須是整數(shù)、整數(shù)列表、整數(shù)切片或布爾數(shù)組。傳入字符串會(huì)直接報(bào)錯(cuò)。與數(shù)據(jù)順序強(qiáng)相關(guān)iloc的性能非常穩(wěn)定且高效因?yàn)樗苯痈鶕?jù)內(nèi)存偏移量計(jì)算位置與索引內(nèi)容無關(guān)。繼續(xù)用上面的df# 選取第2行位置1因?yàn)閺?開始 print(df.iloc[1]) # 輸出李四的信息 # 選取第2行第1列位置[1, 0] print(df.iloc[1, 0]) # 輸出‘市場部‘ # 選取前兩行所有列 print(df.iloc[0:2, :]) # 等價(jià)于 df.iloc[:2] # 輸出張三和李四的信息注意這里有一個(gè)新手超級易錯(cuò)點(diǎn)df.iloc[0:2]選取的是位置0和1的行而df.loc[0:2]如果索引是整數(shù)0,1,2,3選取的是標(biāo)簽為0,1,2的行。如果索引不是連續(xù)的整數(shù)或者有其他類型df.loc[0:2]的行為會(huì)完全不同。務(wù)必時(shí)刻清楚你用的是哪把“鑰匙”。2.3 何時(shí)該用loc何時(shí)該用iloc這個(gè)選擇沒有絕對的對錯(cuò)但有一些最佳實(shí)踐用loc當(dāng)你的索引有意義時(shí)如果你的行索引是ID、日期、姓名等有業(yè)務(wù)含義的標(biāo)簽?zāi)敲磍oc是更直觀、更安全的選擇。你的代碼讀起來就像在說“給我找‘張三’的數(shù)據(jù)”。用iloc當(dāng)你只關(guān)心順序位置時(shí)當(dāng)你需要“前100個(gè)樣本”、“每隔5行取一個(gè)”、“最后10行”時(shí)iloc是更直接的選擇。它不依賴于索引的具體內(nèi)容行為可預(yù)測。在循環(huán)或性能敏感代碼中考慮ilociloc的純整數(shù)索引通常比loc的標(biāo)簽查找更快尤其是在索引未排序或非唯一的情況下。修改數(shù)據(jù)時(shí)慎用鏈?zhǔn)劫x值無論是loc還是iloc都盡量避免df[‘a(chǎn)‘].loc[0] 1這種鏈?zhǔn)剿饕x值因?yàn)樗赡苡|發(fā)SettingWithCopyWarning。正確的做法是使用df.loc[0, ‘a(chǎn)‘] 1。3. 單維度與多維度的數(shù)據(jù)選取實(shí)戰(zhàn)理解了基本概念后我們來看看它們在實(shí)際選取數(shù)據(jù)時(shí)的各種花樣。選取可以分為單點(diǎn)選取、多點(diǎn)選取和區(qū)間切片選取。3.1 選取單個(gè)元素標(biāo)量這是最簡單的操作目的是獲取一個(gè)具體的值。使用loc:# 語法df.loc[行標(biāo)簽 列標(biāo)簽] value df.loc[‘李四‘, ‘年齡‘] print(value) # 輸出32如果只傳入行標(biāo)簽會(huì)返回該行的Series。如果行、列標(biāo)簽都傳入則返回該位置的標(biāo)量值。使用iloc:# 語法df.iloc[行位置 列位置] value df.iloc[1, 1] # 第2行第2列‘年齡‘列 print(value) # 輸出32實(shí)操心得在Jupyter Notebook或交互式環(huán)境中當(dāng)你用df.loc[‘某個(gè)標(biāo)簽‘]獲取一個(gè)Series時(shí)顯示可能很長。如果你只想快速看一眼某個(gè)特定列的值使用df.loc[‘某個(gè)標(biāo)簽‘, ‘特定列名‘]會(huì)更高效。另外當(dāng)索引是日期時(shí)間類型時(shí)loc可以直接用字符串查詢?nèi)鏳f.loc[‘2023-01-01‘]非常方便。3.2 選取單行或單列Series選取整行或整列會(huì)返回一個(gè)Pandas Series對象。選取單行# loc 按標(biāo)簽選行 row_by_name df.loc[‘王五‘] # 返回‘王五‘這一行的Series # iloc 按位置選行 row_by_position df.iloc[2] # 返回第3行的Series (位置2)選取單列雖然更常見的列選取方式是df[‘列名‘]但loc/iloc也能做而且在與行選擇結(jié)合時(shí)更統(tǒng)一。# loc 按標(biāo)簽選列 col_by_name df.loc[:, ‘年齡‘] # 選取‘年齡‘這一整列返回Series # 注意前面的冒號(hào)‘:‘表示選取所有行 # iloc 按位置選列 col_by_position df.iloc[:, 1] # 選取第2列位置1返回Series注意事項(xiàng)df[‘年齡‘]和df.loc[:, ‘年齡‘]在大多數(shù)情況下結(jié)果一樣但后者是更明確的“標(biāo)簽索引”操作。當(dāng)列名恰好是整數(shù)時(shí)df[1]會(huì)報(bào)錯(cuò)因?yàn)闀?huì)被解釋為選取列名為1的列而df.iloc[:, 1]則能正確選取第二列。為了代碼清晰我個(gè)人的習(xí)慣是選取列時(shí)簡單的用df[‘col‘]復(fù)雜的、需要行列組合的統(tǒng)一用loc/iloc。3.3 選取多行多列DataFrame子集這是數(shù)據(jù)分析中最常見的操作之一用于從原數(shù)據(jù)中裁剪出感興趣的部分。使用列表進(jìn)行多點(diǎn)選取# loc選取指定的多個(gè)行和列 sub_df df.loc[[‘張三‘, ‘趙六‘], [‘部門‘, ‘入職年份‘]] # 得到一個(gè)只包含張三和趙六的‘部門‘和‘入職年份‘的DataFrame # iloc選取指定的多個(gè)位置 sub_df df.iloc[[0, 3], [0, 2]] # 選取第1、4行第1、3列使用切片進(jìn)行區(qū)間選取這里是核心差異點(diǎn)# 假設(shè)df的索引是默認(rèn)的0,1,2,3 df_default_index df.reset_index() # 重置索引為0,1,2,3 # loc 切片包含結(jié)束點(diǎn) slice_loc df_default_index.loc[1:3] # 選取標(biāo)簽為1,2,3的行共3行 print(slice_loc.shape) # 可能是 (3, 4) # iloc 切片不包含結(jié)束點(diǎn) slice_iloc df_default_index.iloc[1:3] # 選取位置為1,2的行共2行 print(slice_iloc.shape) # (2, 4)高級切片與布爾索引結(jié)合布爾索引是過濾數(shù)據(jù)的利器loc與之結(jié)合是天作之合。# 選取‘技術(shù)部‘的所有員工 tech_employees df.loc[df[‘部門‘] ‘技術(shù)部‘] # df[‘部門‘] ‘技術(shù)部‘ 產(chǎn)生一個(gè)布爾Seriesloc用它來篩選行 # 選取‘技術(shù)部‘且年齡大于26的員工 tech_senior df.loc[(df[‘部門‘] ‘技術(shù)部‘) (df[‘年齡‘] 26)] # 注意多個(gè)條件要用括號(hào)括起來并用 與、|或、~非連接 # 在篩選的基礎(chǔ)上再選取特定列 tech_senior_info df.loc[(df[‘部門‘] ‘技術(shù)部‘) (df[‘年齡‘] 26), [‘年齡‘, ‘入職年份‘]]iloc也可以結(jié)合布爾索引但通常需要先通過條件計(jì)算出布爾數(shù)組列表。# 獲取‘年齡‘大于30的布爾序列 condition df[‘年齡‘] 30 # 將這個(gè)布爾序列轉(zhuǎn)換為列表用于iloc不常用更推薦用loc做布爾篩選 positions condition[condition].index.tolist() # 獲取為True的索引標(biāo)簽列表 # 但此時(shí)我們已經(jīng)有了標(biāo)簽直接用loc更簡單df.loc[condition]踩坑記錄布爾索引中的條件運(yùn)算符,|,~的優(yōu)先級高于,等比較運(yùn)算符。因此務(wù)必給每個(gè)條件加上括號(hào)否則會(huì)引發(fā)不可預(yù)知的錯(cuò)誤或報(bào)錯(cuò)。(df[‘A‘] 1) (df[‘B‘] 2)是正確的df[‘A‘] 1 df[‘B‘] 2是錯(cuò)誤的。4. 高級技巧與性能優(yōu)化指南當(dāng)你熟練掌握了基本選取后一些高級技巧可以讓你代碼更簡潔、運(yùn)行更高效。4.1 使用at和iat進(jìn)行快速標(biāo)量訪問如果你百分之百確定只是要獲取或設(shè)置一個(gè)單一單元格的值那么at標(biāo)簽和iat位置比loc和iloc更快。# 獲取單個(gè)值 fast_value_loc df.at[‘李四‘, ‘年齡‘] # 類比 df.loc[‘李四‘, ‘年齡‘] fast_value_iloc df.iat[1, 1] # 類比 df.iloc[1, 1] # 設(shè)置單個(gè)值 df.at[‘李四‘, ‘年齡‘] 33 # 比 df.loc[‘李四‘, ‘年齡‘] 33 稍快 df.iat[1, 1] 33它們的語法更簡潔并且在底層做了優(yōu)化對于在循環(huán)中頻繁訪問單個(gè)元素的情況性能提升明顯。但在可讀性上loc/iloc更勝一籌因?yàn)榇蠹腋煜ぁN覀€(gè)人的建議是在明確需要性能優(yōu)化的熱點(diǎn)代碼中使用at/iat在一般業(yè)務(wù)邏輯中使用loc/iloc以保持清晰。4.2 使用isin()進(jìn)行多值篩選當(dāng)需要篩選某列值屬于一個(gè)特定集合的記錄時(shí)isin()方法非常有用它比寫多個(gè)OR條件簡潔得多。# 篩選部門為‘技術(shù)部‘或‘市場部‘的員工 target_departments [‘技術(shù)部‘, ‘市場部‘] employees_in_target df.loc[df[‘部門‘].isin(target_departments)]4.3 利用query()方法進(jìn)行表達(dá)式查詢對于復(fù)雜的多條件篩選query()方法提供了一種更接近自然語言的寫法尤其適合條件很多的時(shí)候。# 使用query篩選 result df.query(‘部門 “技術(shù)部“ and 年齡 25‘) # 等價(jià)于 df.loc[(df[‘部門‘] ‘技術(shù)部‘) (df[‘年齡‘] 25)]query()的優(yōu)點(diǎn)是字符串表達(dá)式更清晰特別是列名包含空格或特殊字符時(shí)需要用反引號(hào)包裹。但它的性能在簡單條件下可能略遜于直接的布爾索引且表達(dá)式中的變量引用需要注意使用符號(hào)。在可讀性和簡單性要求高時(shí)推薦使用。4.4 性能考量與最佳實(shí)踐避免在循環(huán)中使用loc/iloc逐行處理這是Pandas性能的“頭號(hào)殺手”。Pandas是向量化計(jì)算的庫應(yīng)該盡量用整個(gè)Series或DataFrame的操作代替循環(huán)。例如不要用for i in range(len(df)): df.loc[i, ‘new_col‘] ...而應(yīng)該用df[‘new_col‘] df[‘old_col‘].apply(func)或向量化運(yùn)算。索引的重要性對于loc一個(gè)排序且唯一的索引能極大提升查詢速度。如果你的數(shù)據(jù)經(jīng)常需要按某個(gè)鍵查詢考慮使用set_index()將其設(shè)為索引。使用df.sort_index()對索引排序也能提升loc范圍查詢的性能。ilocvsloc性能在索引是簡單整數(shù)且已排序的情況下兩者性能差異不大。但如果索引是復(fù)雜的字符串或未排序iloc通常更快因?yàn)樗侵苯拥奈恢脤ぶ?。使?copy()避免鏈?zhǔn)劫x值警告當(dāng)你通過篩選得到一個(gè)子DataFrame并想修改它時(shí)Pandas可能會(huì)分不清你是想修改視圖還是副本。最安全的做法是顯式拷貝sub_df df.loc[condition].copy()。這樣后續(xù)對sub_df的修改就不會(huì)觸發(fā)SettingWithCopyWarning。5. 常見問題排查與避坑實(shí)錄即使理解了原理在實(shí)際編碼中還是會(huì)遇到各種奇怪的問題。下面是我總結(jié)的幾個(gè)高頻“坑點(diǎn)”及其解決方案。5.1 KeyError: ‘[label] not found in index‘這是使用loc時(shí)最常見的錯(cuò)誤。原因你試圖用loc訪問一個(gè)不存在的行或列標(biāo)簽。排查檢查標(biāo)簽拼寫是否正確包括大小寫和空格。使用df.index和df.columns查看當(dāng)前確切的索引和列名。如果標(biāo)簽是動(dòng)態(tài)生成的先使用label in df.index或label in df.columns進(jìn)行判斷。解決label_to_find ‘某個(gè)名字‘ if label_to_find in df.index: data df.loc[label_to_find] else: print(f“標(biāo)簽 ‘{label_to_find}‘ 不存在“) # 或者進(jìn)行其他處理如使用默認(rèn)值 data None5.2 使用切片時(shí)結(jié)果與預(yù)期不符問題df.loc[0:5]我以為選了6行為什么結(jié)果不對原因混淆了loc和iloc的切片語義或者索引不是連續(xù)的整數(shù)。loc[0:5]選取索引標(biāo)簽從0到5包含5的所有行。如果索引是[0,1,3,5,7]那么它會(huì)選取標(biāo)簽0,1,3,5。iloc[0:5]選取位置0到4不包含5的行即前5行。解決明確你的意圖是按標(biāo)簽選還是按位置選如果索引是整數(shù)但不是連續(xù)的想按位置選前N行務(wù)必使用iloc[:N]。打印df.index查看索引的實(shí)際值。5.3 SettingWithCopyWarning 警告問題在對數(shù)據(jù)進(jìn)行賦值時(shí)看到令人困惑的SettingWithCopyWarning。原因Pandas無法確定你的操作是在原始數(shù)據(jù)的視圖view上還是副本copy上進(jìn)行修改。在視圖上修改可能會(huì)影響原始數(shù)據(jù)這是不明確且危險(xiǎn)的行為。典型鏈?zhǔn)剿饕龍鼍? 危險(xiǎn)可能觸發(fā)警告 df[df[‘年齡‘] 30][‘新列‘] ‘高級‘ # 或 df.loc[df[‘年齡‘] 30][‘新列‘] ‘高級‘ # 注意這里有兩個(gè)‘[ ]‘解決使用單次loc賦值這是最推薦、最清晰的方式。df.loc[df[‘年齡‘] 30, ‘新列‘] ‘高級‘這條語句明確地通過loc在原始df上對滿足條件的行進(jìn)行賦值。需要副本時(shí)顯式拷貝如果你確實(shí)想在一個(gè)篩選后的副本上操作并保留原始數(shù)據(jù)不變請顯式使用.copy()。df_old df.copy() sub_df df_old.loc[df_old[‘年齡‘] 30].copy() # 顯式創(chuàng)建副本 sub_df[‘新列‘] ‘高級‘ # 安全地在副本上修改5.4 布爾索引條件組合錯(cuò)誤問題多個(gè)條件組合時(shí)結(jié)果不對或直接報(bào)錯(cuò)ValueError: The truth value of a Series is ambiguous...。原因使用了Python原生的and,or,not而不是Pandas的位運(yùn)算符,|,~并且沒有給條件加括號(hào)。錯(cuò)誤示例# 錯(cuò)誤1使用and/or df.loc[df[‘A‘] 1 and df[‘B‘] 2] # 報(bào)錯(cuò) # 錯(cuò)誤2條件未加括號(hào) df.loc[df[‘A‘] 1 df[‘B‘] 2] # 邏輯錯(cuò)誤先計(jì)算 1 df[‘B‘]正確示例# 正確使用 每個(gè)條件用括號(hào)包裹 df.loc[(df[‘A‘] 1) (df[‘B‘] 2)] # 復(fù)雜條件組合 df.loc[(df[‘部門‘] ‘技術(shù)部‘) ((df[‘年齡‘] 25) | (df[‘年齡‘] 35))]5.5 處理多層索引MultiIndex當(dāng)DataFrame有行和列的多層索引時(shí)loc的用法需要擴(kuò)展。示例# 創(chuàng)建一個(gè)簡單的多層索引DataFrame arrays [[‘A‘, ‘A‘, ‘B‘, ‘B‘], [1, 2, 1, 2]] index pd.MultiIndex.from_arrays(arrays, names(‘first‘, ‘second‘)) df_multi pd.DataFrame({‘value‘: [10, 20, 30, 40]}, indexindex) # 使用loc選取 print(df_multi.loc[‘A‘]) # 選取第一層索引為‘A‘的所有行 print(df_multi.loc[(‘A‘, 1)]) # 選取第一層為‘A‘第二層為1的行 print(df_multi.loc[‘A‘, :]) # 同上選取所有列 print(df_multi.loc[(‘A‘, 1), :]) # 選取特定組合對于多層索引loc的索引器可以是一個(gè)元組(level1_key, level2_key, ...)。你也可以使用slice(None)來指定某一層全選或者使用pd.IndexSlice進(jìn)行更復(fù)雜的切片。6. 綜合案例一個(gè)完整的數(shù)據(jù)清洗與篩選流程讓我們通過一個(gè)模擬的真實(shí)場景把loc和iloc的各種用法串起來。假設(shè)我們有一個(gè)銷售數(shù)據(jù)表sales_df。import pandas as pd import numpy as np # 創(chuàng)建示例數(shù)據(jù) np.random.seed(42) dates pd.date_range(‘20230101‘, periods100, freq‘D‘) products [‘Product_A‘, ‘Product_B‘, ‘Product_C‘] regions [‘North‘, ‘South‘, ‘East‘, ‘West‘] data { ‘Date‘: np.random.choice(dates, 200), ‘Product‘: np.random.choice(products, 200), ‘Region‘: np.random.choice(regions, 200), ‘Sales‘: np.random.randint(50, 500, 200), ‘Customer_ID‘: range(1000, 1200) # 假設(shè)有200個(gè)訂單 } sales_df pd.DataFrame(data) # 為了演示我們故意制造一些缺失值和異常值 sales_df.loc[10:15, ‘Sales‘] np.nan sales_df.loc[50, ‘Sales‘] 10000 # 一個(gè)異常高值 print(“原始數(shù)據(jù)概覽“) print(sales_df.head()) print(sales_df.info())任務(wù)清洗數(shù)據(jù)并分析“Product_A”在“North”地區(qū)2023年第一季度1-3月的銷售情況。步驟1設(shè)置合適的索引由于我們要按日期和產(chǎn)品查詢將Date和Product設(shè)為多層索引可能更高效。# 先按Date排序這對基于時(shí)間的切片很重要 sales_df.sort_values(‘Date‘, inplaceTrue) # 設(shè)置索引 sales_df.set_index([‘Date‘, ‘Product‘], inplaceTrue) print(“設(shè)置索引后的數(shù)據(jù)“) print(sales_df.head())步驟2處理缺失值和異常值# 1. 識(shí)別缺失值使用loc配合isna() missing_sales sales_df.loc[sales_df[‘Sales‘].isna()] print(f“有 {len(missing_sales)} 條銷售記錄缺失?!? # 用該產(chǎn)品在該地區(qū)的平均銷售額填充缺失值假設(shè)策略如此 # 先臨時(shí)重置索引方便分組計(jì)算 temp_df sales_df.reset_index() # 計(jì)算每個(gè)產(chǎn)品-地區(qū)的平均銷售額忽略NaN mean_sales temp_df.groupby([‘Product‘, ‘Region‘])[‘Sales‘].mean() # 定義一個(gè)填充函數(shù) def fill_na(row): if pd.isna(row[‘Sales‘]): key (row[‘Product‘], row[‘Region‘]) return mean_sales.get(key, row[‘Sales‘]) # 如果找不到對應(yīng)均值返回原值NaN return row[‘Sales‘] # 應(yīng)用填充這里為了演示我們創(chuàng)建一個(gè)新列。實(shí)際中可能直接修改 temp_df[‘Sales_Filled‘] temp_df.apply(fill_na, axis1) # 再設(shè)回索引 sales_df_filled temp_df.set_index([‘Date‘, ‘Product‘]) sales_df_filled.drop(columns‘Sales‘, inplaceTrue) sales_df_filled.rename(columns{‘Sales_Filled‘: ‘Sales‘}, inplaceTrue) # 2. 處理異常值假設(shè)我們認(rèn)為銷售額大于3000的是異常值 # 使用布爾索引定位異常值 outliers sales_df_filled.loc[sales_df_filled[‘Sales‘] 3000] print(f“識(shí)別到 {len(outliers)} 條異常銷售記錄“) print(outliers) # 策略將異常值截?cái)酁?9%分位數(shù) percentile_99 sales_df_filled[‘Sales‘].quantile(0.99) sales_df_filled.loc[sales_df_filled[‘Sales‘] 3000, ‘Sales‘] percentile_99 print(f“已將大于3000的銷售額替換為99%分位數(shù): {percentile_99:.2f}“)步驟3執(zhí)行核心篩選任務(wù)# 目標(biāo)篩選 Product_A 在 North 地區(qū)2023年第一季度的數(shù)據(jù) # 注意索引現(xiàn)在是 (Date, Product) # 方法A使用loc的多層索引查詢 # 我們需要篩選行Date在Q1且Product為‘Product_A‘列需要Region為‘North‘ # 對于行我們需要對第一層(Date)切片第二層(Product)精確匹配 start_date ‘2023-01-01‘ end_date ‘2023-03-31‘ # 由于索引是DatetimeIndexloc可以直接用字符串切片 # 但是我們的索引是MultiIndex需要用到pd.IndexSlice idx pd.IndexSlice target_data sales_df_filled.loc[idx[start_date:end_date, ‘Product_A‘], :] # 現(xiàn)在target_data包含了Q1所有Product_A的記錄 # 再從這些記錄中篩選Region為‘North‘的 target_data_north target_data.loc[target_data[‘Region‘] ‘North‘] print(f“Product_A在North地區(qū)Q1的銷售記錄有 {len(target_data_north)} 條。“) print(target_data_north.head()) # 方法B重置索引使用更直觀的布爾索引當(dāng)查詢條件復(fù)雜時(shí)可能更清晰 # sales_df_reset sales_df_filled.reset_index() # target_data_b sales_df_reset[ # (sales_df_reset[‘Product‘] ‘Product_A‘) # (sales_df_reset[‘Region‘] ‘North‘) # (sales_df_reset[‘Date‘] ‘2023-01-01‘) # (sales_df_reset[‘Date‘] ‘2023-03-31‘) # ] # 兩種方法結(jié)果一致選擇哪種取決于個(gè)人習(xí)慣和索引結(jié)構(gòu)。步驟4對篩選結(jié)果進(jìn)行分析if not target_data_north.empty: # 計(jì)算基本統(tǒng)計(jì)量 total_sales target_data_north[‘Sales‘].sum() avg_sales target_data_north[‘Sales‘].mean() max_sale target_data_north[‘Sales‘].max() min_sale target_data_north[‘Sales‘].min() print(f“\n分析結(jié)果“) print(f“總銷售額: {total_sales:.2f}“) print(f“平均每單銷售額: {avg_sales:.2f}“) print(f“最高單筆銷售額: {max_sale:.2f}“) print(f“最低單筆銷售額: {min_sale:.2f}“) # 也許我們還想看銷售額的分布使用iloc快速選取前幾行查看 print(f“\n銷售額前5的訂單“) # 先按銷售額降序排序 top_sales target_data_north.sort_values(by‘Sales‘, ascendingFalse) # 用iloc選取前5行 print(top_sales.iloc[:5]) else: print(“沒有找到符合條件的數(shù)據(jù)?!?通過這個(gè)案例你可以看到loc和iloc如何與Pandas的其他功能如缺失值處理、分組聚合、時(shí)間序列切片協(xié)同工作完成一個(gè)從數(shù)據(jù)準(zhǔn)備到分析的全流程。關(guān)鍵在于根據(jù)數(shù)據(jù)的結(jié)構(gòu)索引和你的查詢意圖靈活選擇最合適的“鑰匙”。當(dāng)索引設(shè)計(jì)得當(dāng)時(shí)loc能讓查詢語句非常直觀而當(dāng)需要進(jìn)行基于順序或位置的操作時(shí)iloc則無可替代。

相關(guān)新聞

國產(chǎn)算力再迎突破!國產(chǎn)硬件順利適配超大參數(shù) MoE 大模型

國產(chǎn)算力再迎突破!國產(chǎn)硬件順利適配超大參數(shù) MoE 大模型

最近這段時(shí)間,國內(nèi)人工智能算力方面有了一定的技術(shù)進(jìn)步。我們國內(nèi)自主研發(fā)的算力硬件設(shè)備,已經(jīng)成功適配了參數(shù)規(guī)模很大的MoE混合專家大模型。這次的技術(shù)落地彌補(bǔ)了國產(chǎn)算力之前存在的一些不足,讓國內(nèi)自主算力體系變得更加完整,也給…

2026/8/1 10:10:03 閱讀更多
拋帳完成是什么意思

拋帳完成是什么意思

“拋賬完成”是企業(yè)管理軟件(尤其是ERP系統(tǒng))里的一個(gè)專業(yè)術(shù)語,簡單來說,就是指業(yè)務(wù)數(shù)據(jù)已經(jīng)成功地從業(yè)務(wù)部門流轉(zhuǎn)到了財(cái)務(wù)部門,并生成了相應(yīng)的會(huì)計(jì)憑證-3-5。 這個(gè)過程就像業(yè)務(wù)部門把工作成果“移交”給財(cái)務(wù)&#xff…

2026/8/1 10:10:03 閱讀更多
環(huán)形隊(duì)列代替ISR狀態(tài)機(jī)——UART收幀重構(gòu)

環(huán)形隊(duì)列代替ISR狀態(tài)機(jī)——UART收幀重構(gòu)

一句話: ISR 里寫了 60 行狀態(tài)機(jī)解析串口幀——每個(gè)字節(jié)都在中斷里判斷、跳轉(zhuǎn)、存數(shù)組。換成 512 字節(jié)環(huán)形隊(duì)列 queue_push queue_find_cmd 后,ISR 縮減到 4 行只做字節(jié)推入,幀解析移到主循環(huán)。適合誰讀:ISR 越來越臃腫、串口收幀丟包不可復(fù)…

2026/8/1 11:20:37 閱讀更多
大模型時(shí)代程序員轉(zhuǎn)型:面試要點(diǎn)與學(xué)習(xí)路徑

大模型時(shí)代程序員轉(zhuǎn)型:面試要點(diǎn)與學(xué)習(xí)路徑

1. 大模型技術(shù)浪潮下的程序員轉(zhuǎn)型機(jī)遇 2023年被稱為"大模型元年",以ChatGPT為代表的生成式AI技術(shù)徹底改變了技術(shù)行業(yè)的格局。作為從業(yè)十年的技術(shù)老兵,我親眼見證了從傳統(tǒng)機(jī)器學(xué)習(xí)到深度學(xué)習(xí),再到如今大模型技術(shù)的三次技術(shù)躍遷。與前…

2026/8/1 11:20:37 閱讀更多
GEO供應(yīng)商十強(qiáng)到底怎么選?服務(wù)商實(shí)力大盤點(diǎn)與選型決策參考

GEO供應(yīng)商十強(qiáng)到底怎么選?服務(wù)商實(shí)力大盤點(diǎn)與選型決策參考

一、開篇引言:AI搜索迭代下,GEO已成企業(yè)數(shù)字化獲客剛需 GEO(生成式引擎優(yōu)化)核心定義:GEO是適配豆包、DeepSeek、文心一言、通義千問、Kimi、騰訊元寶等生成式AI平臺(tái)的新型營銷優(yōu)化體系,核心目標(biāo)是提升企業(yè)…

2026/8/1 11:20:37 閱讀更多
SIGABRT 進(jìn)程主動(dòng)終止故障模式詳解

SIGABRT 進(jìn)程主動(dòng)終止故障模式詳解

本原創(chuàng)文章帖發(fā)布在華為開發(fā)者聯(lián)盟社區(qū),歡迎開發(fā)者前往訪問評論交流,更多與該內(nèi)容相關(guān)討論,請點(diǎn)擊原帖查看: SIGABRT 進(jìn)程主動(dòng)終止故障模式詳解-華為開發(fā)者話題 | 華為開發(fā)者聯(lián)盟SIGABRT 進(jìn)程主動(dòng)終止故障模式詳解 前言 在Harmony…

2026/8/1 11:10:37 閱讀更多
AMAT 0100-02186 I/O 分配 PCB

AMAT 0100-02186 I/O 分配 PCB

AMAT 0100-02186 I/O分配PCB板是應(yīng)用材料(Applied Materials)公司生產(chǎn)的一款用于半導(dǎo)體設(shè)備的I/O信號(hào)分配電路板。該型號(hào)(0100-02186)的核心特點(diǎn)如下:專用于Endura等半導(dǎo)體工藝腔室。集成信號(hào)路由與分配功能。連接控制…

2026/8/1 0:09:33 閱讀更多
Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動(dòng)機(jī)

Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動(dòng)機(jī)

Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動(dòng)機(jī)是日本日清(Nissei)品牌的一款工業(yè)用三相異步電機(jī),適用于自動(dòng)化設(shè)備及通用機(jī)械驅(qū)動(dòng)。該型號(hào)(FFMN-32L-10-T0 40AX)的核心特點(diǎn)如下:三相交流異步電動(dòng)機(jī)。額定…

2026/8/1 0:09:33 閱讀更多
AMAT 0100-02186 I/O 分配 PCB

AMAT 0100-02186 I/O 分配 PCB

AMAT 0100-02186 I/O分配PCB板是應(yīng)用材料(Applied Materials)公司生產(chǎn)的一款用于半導(dǎo)體設(shè)備的I/O信號(hào)分配電路板。該型號(hào)(0100-02186)的核心特點(diǎn)如下:專用于Endura等半導(dǎo)體工藝腔室。集成信號(hào)路由與分配功能。連接控制…

2026/8/1 0:09:33 閱讀更多
Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動(dòng)機(jī)

Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動(dòng)機(jī)

Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動(dòng)機(jī)是日本日清(Nissei)品牌的一款工業(yè)用三相異步電機(jī),適用于自動(dòng)化設(shè)備及通用機(jī)械驅(qū)動(dòng)。該型號(hào)(FFMN-32L-10-T0 40AX)的核心特點(diǎn)如下:三相交流異步電動(dòng)機(jī)。額定…

2026/8/1 0:09:33 閱讀更多