
np.insert 是 numpy 库中一个用于在指定位置插入值或行的函数。它的基本语法是 np.insert(arr, obj, values, axis=none),其中:
然而,一个经常被忽视的关键点是 np.insert 不会原地修改原始数组。相反,它会返回一个包含插入值的新数组。如果不对这个新数组进行赋值操作,原始数组将保持不变,导致看似“插入失败”或“替换”的现象。
在尝试向文件中添加行的场景中,开发者可能会遇到 np.insert 似乎替换了现有行而非插入新行的问题。这通常源于以下两个主要原因:
原始代码片段:
np.insert(file, row, [temp], 0) # 尝试插入新行
这里的 np.insert 调用会生成一个包含新行的新数组,但这个新数组并没有被赋值给任何变量。因此,file 变量仍然指向原始数组,导致后续操作(如 pd.DataFrame(file).to_csv())仍然基于未修改的原始数据。
解决方案: 必须将 np.insert 的结果重新赋值给原始数组变量:
file = np.insert(file, row + 1, [temp], axis=0) # 将新数组赋值回 'file'
这里我们将插入位置调整为 row + 1,因为我们希望在当前行 row 的下一行(即 row + 1 索引处)插入新数据。同时,明确指定 axis=0 表示按行插入。
原始代码片段:
temp = file[row+1] # 获取下一行数据 temp[5] = "" # 修改 temp
当执行 temp = file[row+1] 时,temp 并没有创建 file[row+1] 的一个独立副本。相反,temp 只是 file 数组中第 row+1 行的一个视图(view)。这意味着对 temp 的任何修改都会直接反映到 file 数组的相应行中。
因此,当 temp[5] = "" 执行时,实际上是修改了 file 数组中第 row+1 行的第 5 列数据。如果随后又在 row+1 处插入了一个基于这个被修改过的 temp 的新行,那么原始的 file[row+1] 已经被改变了,这可能不是我们期望的行为,尤其是在后续循环中如果 file[row+1] 被再次访问时。
解决方案: 在获取切片数据时,使用 .copy() 方法创建数据的深拷贝:
temp = file[row+1].copy() # 使用 .copy() 创建一个独立副本 temp[5] = "" # 对副本的修改不会影响原始数组
这样,对 temp 的修改将只影响 temp 自身,而不会影响 file 数组中的原始行。
综合上述分析,以下是修正后的代码,它能够正确地在满足条件时插入新行:
import numpy as np
import pandas as pd
# 模拟一个CSV文件,包含标题行
# ccType,number,date,payee,total,indAmt,memo,category
# mastercard,30,11/21/2022,Bluejam,287.24,44.33,,Sports
# mastercard,30,11/23/2022,Fanoodle,287.24,95.95,,Health
# mastercard,30,11/25/2022,Eazzy,287.24,1.2,,Automotive
# mastercard,30,11/26/2022,Dabfeed,287.24,68.97,,Games
# mastercard,30,11/30/2022,Jaloo,287.24,76.79,,Games
# mastercard,50,7/4/2023,Shufflebeat,317.13,91.91,,Sports
# mastercard,50,7/4/2023,Meembee,317.13,94.69,,Toys
# mastercard,50,7/5/2023,Jabberbean,317.13,67.01,,Computers
# mastercard,50,7/28/2023,Wikibox,317.13,33.18,,Movies
# mastercard,50,7/29/2023,Shufflebeat,317.13,30.34,,Automotive
# 假设 'name.csv' 文件存在,并与上述数据结构一致
try:
file = np.loadtxt("name.csv", skiprows=1, dtype='<U70', delimiter =',')
except FileNotFoundError:
print("Error: 'name.csv' not found. Please create the dummy file or adjust path.")
# Create a dummy file for demonstration if not found
dummy_data = """ccType,number,date,payee,total,indAmt,memo,category
mastercard,30,11/21/2022,Bluejam,287.24,44.33,,Sports
mastercard,30,11/23/2022,Fanoodle,287.24,95.95,,Health
mastercard,30,11/25/2022,Eazzy,287.24,1.2,,Automotive
mastercard,30,11/26/2022,Dabfeed,287.24,68.97,,Games
mastercard,30,11/30/2022,Jaloo,287.24,76.79,,Games
mastercard,50,7/4/2023,Shufflebeat,317.13,91.91,,Sports
mastercard,50,7/4/2023,Meembee,317.13,94.69,,Toys
mastercard,50,7/5/2023,Jabberbean,317.13,67.01,,Computers
mastercard,50,7/28/2023,Wikibox,317.13,33.18,,Movies
mastercard,50,7/29/2023,Shufflebeat,317.13,30.34,,Automotive"""
with open("name.csv", "w") as f:
f.write(dummy_data)
file = np.loadtxt("name.csv", skiprows=1, dtype='<U70', delimiter =',')
# 获取行和列的数量。注意:在循环中插入行会改变 'rows' 的值,
# 因此需要动态获取或调整循环逻辑。这里我们使用一个 while 循环来适应动态行数。
row_idx = 0
while row_idx < file.shape[0] - 1: # 循环直到倒数第二行,因为要比较当前行和下一行
# 假设我们只关心第5列(索引为4)的变化
current_col_val = file[row_idx, 4]
next_col_val = file[row_idx + 1, 4]
# 如果当前行的第5列与下一行的第5列不相等,则插入新行
if current_col_val != next_col_val:
# 1. 创建下一行的独立副本,避免修改原始数据
temp_row_to_insert = file[row_idx + 1].copy()
# 2. 修改副本的第6列(索引为5)为空字符串
temp_row_to_insert[5] = ""
# 3. 使用 np.insert 插入新行,并将其结果重新赋值给 'file'
# 插入位置是 row_idx + 1,即在当前行和下一行之间
file = np.insert(file, row_idx + 1, temp_row_to_insert, axis=0)
# 由于插入了一行,数组的长度增加了,我们需要调整循环索引,
# 使其在下一次迭代时检查新插入行后的元素
row_idx += 1
# 无论是否插入,都前进到下一行进行检查
row_idx += 1
# 将最终的 NumPy 数组转换为 Pandas DataFrame 并输出到 CSV
# 注意:np.loadtxt 默认不会保留标题,如果需要标题,需要单独处理或使用 pd.read_csv
outfile = pd.DataFrame(file)
outfile.to_csv("OutFile.csv", index=False, header=False) # 不输出索引和标题,以匹配原始输出格式
print("Processed data saved to OutFile.csv")
# 打印输出结果以供验证
print("\n--- Generated OutFile.csv Content ---")
with open("OutFile.csv", "r") as f:
print(f.read())代码说明:
经过上述修正,OutFile.csv 将包含插入的新行,例如:
mastercard,30,11/21/2022,Bluejam,287.24,44.33,,Sports mastercard,30,11/23/2022,Fanoodle,287.24,95.95,,Health mastercard,30,11/25/2022,Eazzy,287.24,1.2,,Automotive mastercard,30,11/26/2022,Dabfeed,287.24,68.97,,Games mastercard,30,11/30/2022,Jaloo,287.24,76.79,,Games mastercard,50,7/4/2023,Shufflebeat,317.13,,,Sports mastercard,50,7/4/2023,Shufflebeat,317.13,91.91,,Sports mastercard,50,7/4/2023,Meembee,317.13,94.69,,Toys mastercard,50,7/5/2023,Jabberbean,317.13,67.01,,Computers mastercard,50,7/28/2023,Wikibox,317.13,33.18,,Movies mastercard,50,7/29/2023,Shufflebeat,317.13,30.34,,Automotive
可以看到,在 mastercard,30,... 系列和 mastercard,50,... 系列之间,由于第5列(索引4)的值从 287.24 变为 317.13,程序成功插入了一行,其第5列(索引5)为空。总行数也从10行增加到11行,符合预期。
通过遵循这些原则,可以有效避免在使用 np.insert 及其他 NumPy 函数时常见的陷阱,确保数据处理的准确性和代码的健壮性。
以上就是理解 NumPy np.insert 的正确使用:避免替换而非插入的陷阱的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号