如何基于Pandas DataFrame的索引列表列移除单元格列表中对应位置的元素
嘿,这个需求其实很常见,我来给你分享两种高效的实现方式,你可以根据自己的数据规模来选择:
方法一:简洁直观的逐行处理(适合中小数据量)
这种方法用apply配合列表推导,代码简洁易懂,对于常规规模的数据完全够用:
首先先构造示例数据:
import pandas as pd df = pd.DataFrame({ 'a': [1, 5, 8], 'b': [2, 1, 2], 'vals': [[1,2,3,4,5], [1,7,2,4,9], [1,9,4,7,8]], 'locs': [[2,3], [0,1], [3]] })
然后生成new_vals列:
df['new_vals'] = df.apply( lambda row: [val for idx, val in enumerate(row['vals']) if idx not in row['locs']], axis=1 )
原理说明
我们遍历DataFrame的每一行,对vals列表里的每个元素,检查它的索引是否不在locs的排除列表中,只保留符合条件的元素,最终组成新的列表赋值给new_vals。
方法二:矢量化处理(适合大数据量)
如果你的DataFrame有几十万甚至上百万行,上面的apply本质是Python层面的逐行循环,性能会受影响。这时候可以用Pandas的矢量化操作来优化:
# 1. 展开vals列,记录原始行索引和元素的位置索引 vals_exploded = df['vals'].explode().reset_index(name='val') vals_exploded['elem_idx'] = vals_exploded.groupby('index').cumcount() # 2. 展开locs列,记录需要排除的行索引和位置索引 locs_exploded = df['locs'].explode().reset_index(name='exclude_idx') locs_exploded['exclude_idx'] = locs_exploded['exclude_idx'].astype(int) # 3. 生成过滤掩码:保留不在排除列表中的元素 exclude_indexes = locs_exploded.set_index(['index', 'exclude_idx']).index keep_mask = ~vals_exploded.set_index(['index', 'elem_idx']).index.isin(exclude_indexes) filtered_vals = vals_exploded[keep_mask] # 4. 重新分组聚合回列表,合并到原DataFrame df['new_vals'] = filtered_vals.groupby('index')['val'].apply(list)
原理说明
通过把嵌套列表展开成扁平的Series,利用Pandas的索引匹配来批量过滤元素,最后再聚合回列表。这种方式避免了Python循环,完全利用Pandas的C底层优化,在大数据量下性能提升明显。
验证结果
执行完上面任意一种方法后,打印df就能得到你想要的结果:
print(df)
输出:
| a | b | vals | locs | new_vals |
|---|---|---|---|---|
| 1 | 2 | [1,2,3,4,5] | [2,3] | [1,2,5] |
| 5 | 1 | [1,7,2,4,9] | [0,1] | [2,4,9] |
| 8 | 2 | [1,9,4,7,8] | [3] | [1,9,4,8] |
内容的提问来源于stack exchange,提问作者Cranjis
相关产品推荐
相关产品推荐

