如何在Python/Pandas中更新存在于另一个DataFrame中的指定行
Pandas批量更新DataFrame行(对应SQL UPDATE逻辑)
要实现你需要的基于id的批量更新,不用逐行循环,Pandas的loc结合布尔索引是最适合的方案——比at更贴合你基于列值(而非索引位置)的更新需求,而且性能远高于循环或列表推导。
下面是对应你三个SQL语句的Pandas实现:
1. 标记"Active Customer"(对应第一个UPDATE)
筛选user_id存在于logs且不为空的行,更新status:
# 条件:user_id不为空 且 在logs的user_id列表中 mask_active = users_df['user_id'].notna() & users_df['user_id'].isin(logs['user_id']) users_df.loc[mask_active, 'status'] = 'Active Customer'
2. 标记"Non Active Customer"(对应第二个UPDATE)
筛选user_id不在logs、不为空且当前status为Unknown的行:
# 条件:user_id不为空 + 不在logs列表中 + status仍为Unknown mask_non_active = users_df['user_id'].notna() & ~users_df['user_id'].isin(logs['user_id']) & (users_df['status'] == 'Unknown') users_df.loc[mask_non_active, 'status'] = 'Non Active Customer'
3. 标记"Active Customer (Calls)"(对应第三个UPDATE)
先构造calls测试数据,再筛选符合条件的行:
# 构造calls测试DF calls = pd.DataFrame({'user_id': ['50', '32']}) calls["user_id"] = pd.to_numeric(calls["user_id"]) # 条件:user_id>0 + 在calls列表中 + status仍为Unknown mask_calls_active = (users_df['user_id'] > 0) & users_df['user_id'].isin(calls['user_id']) & (users_df['status'] == 'Unknown') users_df.loc[mask_calls_active, 'status'] = 'Active Customer (Calls)'
完整示例代码
替换你原来的更新部分,完整代码如下:
import pandas as pd import numpy as np # 创建测试用户DF users_df = pd.DataFrame( {'name':['Bob','Olivia','Gustav','Bella', 'Fran', 'Marco'], 'user_id':['10',np.nan,'30','50','32',np.nan] } ) users_df["user_id"] = pd.to_numeric(users_df["user_id"]) users_df['status'] = 'Unknown' # 创建logs测试DF logs = pd.DataFrame( {'user_id':['10','20','30','32','55']} ) logs["user_id"] = pd.to_numeric(logs["user_id"]) # 1. 更新Active Customer mask_active = users_df['user_id'].notna() & users_df['user_id'].isin(logs['user_id']) users_df.loc[mask_active, 'status'] = 'Active Customer' # 2. 更新Non Active Customer mask_non_active = users_df['user_id'].notna() & ~users_df['user_id'].isin(logs['user_id']) & (users_df['status'] == 'Unknown') users_df.loc[mask_non_active, 'status'] = 'Non Active Customer' # 3. 更新Active Customer (Calls) calls = pd.DataFrame({'user_id': ['50', '32']}) calls["user_id"] = pd.to_numeric(calls["user_id"]) mask_calls_active = (users_df['user_id'] > 0) & users_df['user_id'].isin(calls['user_id']) & (users_df['status'] == 'Unknown') users_df.loc[mask_calls_active, 'status'] = 'Active Customer (Calls)' print(users_df)
为什么不用df.at?
df.at是用来定位单个元素的语法(需要指定索引位置+列名),适合修改单个值;而你需要批量更新符合条件的多行,loc支持布尔筛选,能高效完成批量操作,完全匹配你SQL中WHERE条件的逻辑,性能也比循环或列表推导好很多。
内容的提问来源于stack exchange,提问作者thenewbie
相关产品推荐
相关产品推荐

