在 NumPy 中,數組(ndarray)中的數據不僅可以被訪問,還可以通過賦值操作直接被修改。所謂“數組元素修改”,是指在不重新創建結果數組的情況下,通過索引、切片或條件篩選等方式,直接改變數組中某些元素的值。
與 Python 列表類似,NumPy 允許通過下標定位后進行賦值;但與普通列表不同的是,NumPy 的修改行為同時受到數組形狀(shape)、數據類型(dtype)、廣播機制(broadcasting)以及視圖(view)與副本(copy)關系的影響。因此,理解數組元素修改,不只是學習“怎樣賦值”,更重要的是理解“賦值如何作用到內存中的真實數據”。
NumPy 中,不使用專門函數的數組元素修改,通常可以分為以下幾類:
(1)單個元素修改
(2)切片區域修改
(3)多維局部區域修改
(4)布爾條件修改
(5)整數數組索引位置修改
(6)基于視圖的間接修改
這些方式共同構成了 NumPy 中最常見的原地數據更新機制。
一、單個元素修改
最基本的數組修改方式,是通過整數索引定位單個元素,然后直接賦新值。
1、修改一維數組中的單個元素
示例:
# [10 99 30 40]a[1] = 99 表示將索引位置為 1 的元素改寫為 99。
NumPy 也支持負索引,因此可以從數組末尾開始修改元素。
示例:
# [10 99 30 0]a[-1] 表示最后一個元素,因此該語句將最后一個元素改寫為 0。
2、修改多維數組中的單個元素
對于多維數組,可以使用逗號分隔的多維索引定位某個具體位置。
示例:
# [ 4 5 6]]a[0, 1] 表示第 0 行第 1 列的元素,因此該位置的值由 2 改為 99。
3、賦值時的數據類型轉換
NumPy 數組中的元素類型通常是統一的,因此賦值時,新值需要能夠轉換為數組的 dtype。如果可以轉換,則按該類型存儲;如果不能安全轉換,則可能報錯或發生截斷。
示例:
# [3 2 3]數組類型為整數,3.8 在賦值時會被轉換為整數,因此結果為 3,而不是 3.8。
再如:
# 會報錯:字符串無法轉換為整數提示:
數組修改時,目標值必須與數組的數據類型兼容。否則賦值可能失敗,或產生類型截斷現象。
二、切片區域修改
切片不僅可以用于訪問連續區域,也可以直接用于批量修改數組中的一段連續元素。
1、使用標量修改一段連續元素
示例:
# [1 0 0 0 5]a[1:4] 表示索引 1 到 3 的元素。將其整體賦值為標量 0 時,NumPy 會把該標量擴展到切片區域中的每個位置。
這本質上體現了廣播機制在賦值中的應用。
2、使用序列修改一段連續元素
示例:
# [ 1 20 30 40 5]切片長度為 3,因此右側賦值對象也必須能與長度 3 匹配。這里 [20, 30, 40] 與切片長度一致,所以逐元素完成替換。
如果長度不一致,則通常會報錯。比如:
# 通常會報錯:無法把長度為 2 的序列賦給長度為 3 的切片3、帶步長切片的修改
示例:
# [9 1 9 3 9 5]a[::2] 表示所有偶數位置元素。賦值為 9 后,這些位置全部被改寫。
也可以用等長序列進行替換。
示例:
# [10 1 20 3 30 5]a[::2] 共選中 3 個位置,因此右側序列長度也必須為 3。
4、反向切片修改
示例:
# [1 2 3 4 5]因為左側是反向視圖 a[::-1],右側序列會按該反向順序依次寫入原數組對應位置,所以最終原數組變為 [1, 2, 3, 4, 5]。
由于反向切片仍然指向原數組,因此修改會直接作用到原數組。
三、多維局部區域修改
對于二維及更高維數組,可以通過多維切片修改某一行、某一列或某個子區域。
1、修改整行
示例:
# [ 7 8 9]]a[1] 表示第 1 行。由于這一行長度為 3,因此可以用長度為 3 的序列整體替換。
也可以賦一個標量:
# [7 8 9]]標量會被廣播到整行。
2、修改整列
示例:
# [ 7 80 9]]a[:, 1] 表示第 1 列,共有 3 個元素,因此右側序列長度必須與之匹配。
同樣也可以賦標量:
# [ 7 -1 9]]標量會被廣播到該列中的每個位置,因此這一列全部被改寫為 -1。
3、修改子數組區域
示例:
# [7 8 9]]a[0:2, 1:3] 選中前兩行、后兩列構成的一個 2×2 子區域。將其賦值為標量 0 時,整個區域都會被改寫。
也可以用形狀匹配的二維數據進行替換。
示例:
# [ 7 8 9]]右側數組形狀為 (2, 2),與切片區域形狀一致,因此可以逐元素對應賦值。
4、多維賦值中的廣播
在多維數組修改中,只要右側數據形狀與目標區域兼容,就可以發生廣播。
示例:
# [10 20 30]]左側區域形狀為 (2, 3),右側一維數組形狀為 (3,)。NumPy 會將右側按行廣播到每一行,因此兩行都被替換為 [10, 20, 30]。
再如:
# [200 5 6]]a[:, :1] 的形狀為 (2, 1),右側形狀也為 (2, 1),因此能夠準確對應賦值。
四、布爾條件修改
布爾條件修改,是指先通過條件表達式構造布爾數組,再將條件為 True 的位置統一改寫。這是數據清洗與條件替換中最常見的修改方式之一。
1、根據條件修改一維數組
示例:
# [1 2 3 0 0]表達式 a > 3 會生成如下布爾數組:
[False, False, False, True, True]然后只對其中為 True 的位置賦值 0。
2、根據條件修改二維數組
示例:
# [-1 5 -1]]條件 a % 2 == 0 會生成與原數組同形狀的布爾數組。所有滿足條件的偶數元素都會被替換為 -1。
3、多條件組合修改
示例:
# [ 1 2 99 99 99 6]這里用 & 將兩個布爾條件組合起來,表示同時滿足“大于 2”且“小于 6”的元素會被改寫為 99。
提示:
對數組條件進行組合時,應使用 & 和 |,而不能使用 Python 的 and 和 or。同時,每個條件表達式通常都應使用括號包裹。
4、布爾修改的本質
布爾索引在“取值”時返回的是副本;但在“賦值”語境中,a[mask] = value 的含義不是“先取出副本再修改副本”,而是“將右側值寫回到原數組中滿足條件的位置”。
這說明:
b = a[a > 3] 得到的是一個新數組;
a[a > 3] = 0 則是對原數組中對應位置進行原地寫入。
這一點非常重要。
示例:
# [1 2 3 0 0]前者修改的是副本 b;后者修改的是原數組 a 中滿足條件的位置。
五、整數數組索引位置修改
除了用切片修改連續區域,也可以用整數數組索引修改若干不連續位置。
1、修改一維數組中的多個離散位置
示例:
# [99 20 99 40 99]整數數組 [0, 2, 4] 指定了要修改的離散位置。這些位置都會被改寫為 99。
也可以逐個賦不同的值。
示例:
# [100 20 300 40 500]右側序列長度與被選中的位置數量一致,因此可以逐位置賦值。
2、修改二維數組中的指定位置
示例:
# [50 6]]這里兩個整數數組共同決定若干坐標位置:
a[2, 0]它們分別被賦值為 20 和 50。
3、重復索引的賦值現象
當整數數組索引中出現重復位置時,賦值結果需要特別小心。
示例:
# [20 1 30 3]位置 0 被寫入了兩次,后一次賦值覆蓋前一次賦值,因此最終為 20。
這說明整數數組索引賦值是“按索引位置寫回原數組”的過程;若目標位置重復,后寫入的值會覆蓋前寫入的值。
六、通過視圖進行間接修改
NumPy 中,基本切片通常返回視圖。視圖本身不復制數據,而是與原數組共享同一塊內存。因此,修改視圖往往也會連帶修改原數組。
1、切片視圖修改原數組
示例:
# [ 1 99 3 4 5]b 不是獨立副本,而是 a[1:4] 形成的視圖。因此修改 b[0],實際上也就是修改 a[1]。
2、多維切片視圖的修改傳播
示例:
# [ 4 5 6]]b = a[:, 1:] 選中的是后兩列,通常仍為視圖,因此對 b 的修改會反映到原數組 a 中。
3、何時需要顯式復制
如果希望修改某個局部區域,但又不影響原數組,應先復制再改。
示例:
# [1 2 3 4 5].copy() 會創建一個獨立的新數組,因此后續修改不會再影響原數組。
七、修改時的形狀匹配與廣播規則
數組賦值不是任意進行的。左側目標區域與右側賦值對象之間,必須滿足形狀匹配或廣播兼容關系。
1、完全同形狀賦值
示例:
# [30 40]]左右兩側形狀一致,因此可以逐元素賦值。
2、標量廣播賦值
示例:
# [0 0]]標量可以廣播到任意形狀的目標區域。
3、可廣播形狀賦值
示例:
# [7 8 9]]右側形狀為 (3,),可按行廣播到左側形狀 (2, 3)。
4、形狀不兼容時會報錯
示例:
# 通常會報錯:形狀不匹配,無法廣播到 (2, 3)右側長度為 2,無法與 (2, 3) 的目標區域對齊,因此賦值失敗。
提示:
在數組修改中,右側值既可以是標量,也可以是數組或序列;關鍵不在于“類型是否一樣”,而在于“形狀是否兼容”。
八、數組元素修改的常見注意事項
1、基本切片修改通常是原地修改
如:
a[1:4] = 0這類寫法通常直接作用于原數組,不會額外生成新的數據塊。
2、視圖修改可能產生連帶影響
如果某個變量只是原數組的視圖,那么修改它時,原數組也會隨之改變。因此在數據預處理過程中,應特別留意“是否共享內存”。
3、高級索引的取值結果與賦值語義要區分
比如,b = a[[1, 3]] 得到的是副本;a[[1, 3]] = 0 則表示修改原數組中對應位置。這兩者不能混為一談。
4、賦值要關注 dtype
如果數組是整數類型,那么浮點數、小數、字符串等在賦值時可能發生截斷、轉換失敗或報錯。因此在修改前,應清楚數組的 dtype。
5、賦值要關注 shape
當右側不是標量時,應檢查其形狀能否與左側目標區域一致或廣播兼容。必要時可以先查看:
print(value.shape)以確認賦值是否成立。
九、數組元素修改相關函數
除了使用索引、切片和條件表達式直接修改數組元素外,NumPy 還提供了一組專門用于元素替換、條件寫入和局部更新的函數或方法。
? 條件選擇與條件寫入:where()、putmask()、copyto()、place()
? 按位置寫入元素:put()
? 基于索引進行局部更新:put_along_axis()
? 指定區域填充值:fill()
? 處理重復索引的累積寫入:ufunc.at()(如 np.add.at())
這些函數共同構成了 NumPy 數組修改操作的重要工具體系。
詳情請參閱:
小結
NumPy 的數組元素修改,本質上是通過索引表達式將新值寫入數組的指定位置。單元素賦值、切片賦值、條件修改與多維局部更新,都建立在統一的索引機制之上。需要特別注意的是,修改行為不僅受索引方式影響,還與數組的 dtype、shape、廣播規則以及 view/copy 關系密切相關。理解這些規則,是安全而高效地處理數組數據的重要基礎。
“點贊有美意,贊賞是鼓勵”
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.