08. 条件筛选
1. 概述
条件筛选是数据分析中最常用的操作之一。通过布尔表达式,可以快速筛选出满足特定条件的数据行,实现数据过滤、异常检测、子集提取等功能。
importpandasaspdimportnumpyasnp# 创建示例数据np.random.seed(42)df=pd.DataFrame({'姓名':['张三','李四','王五','赵六','钱七','孙八','周九','吴十'],'年龄':[25,30,28,32,35,27,29,31],'工资':[8000,12000,10000,15000,11000,9500,10500,12500],'部门':['技术','销售','技术','市场','销售','技术','市场','销售'],'绩效':['A','B','A','A','C','B','A','B'],'工作年限':[2,5,3,8,6,2,4,7]})print("原始数据:")print(df)2. 布尔索引基础
2.1 什么是布尔索引?
布尔索引使用布尔值(True/False)的 Series 或数组来筛选数据。
# 创建布尔条件condition=df['年龄']>30print("年龄 > 30 的布尔条件:")print(condition)# 使用布尔索引筛选filtered=df[condition]print("\n筛选结果:")print(filtered)2.2 筛选原理
原始 DataFrame: 姓名 年龄 工资 0 张三 25 8000 1 李四 30 12000 2 王五 28 10000 3 赵六 32 15000 条件: df['年龄'] > 30 结果: [False, False, False, True] 筛选后: 姓名 年龄 工资 3 赵六 32 150003. 单条件筛选
3.1 数值条件
# 大于high_salary=df[df['工资']>10000]print("工资 > 10000:")print(high_salary)# 小于young=df[df['年龄']<30]print("\n年龄 < 30:")print(young)# 等于tech_dept=df[df['部门']=='技术']print("\n部门 == '技术':")print(tech_dept)# 不等于not_tech=df[df['部门']!='技术']print("\n部门 != '技术':")print(not_tech)# 大于等于experienced=df[df['工作年限']>=5]print("\n工作年限 >= 5:")print(experienced)3.2 字符串条件
# 字符串包含excel_perf=df[df['绩效'].str.contains('A')]print("绩效包含 A:")print(excel_perf)# 字符串起始# df[df['姓名'].str.startswith('张')]# 字符串长度# df[df['姓名'].str.len() > 2]4. 多条件筛选
4.1 使用 &(与)
两个条件同时满足。
# 技术部门且工资 > 10000tech_high=df[(df['部门']=='技术')&(df['工资']>10000)]print("技术部门且工资 > 10000:")print(tech_high)# 年龄在 28-32 之间age_range=df[(df['年龄']>=28)&(df['年龄']<=32)]print("\n年龄在 28-32 之间:")print(age_range)注意:每个条件必须用括号括起来。
4.2 使用 |(或)
满足任意一个条件。
# 技术部门或市场部门tech_or_market=df[(df['部门']=='技术')|(df['部门']=='市场')]print("技术部门或市场部门:")print(tech_or_market)# 年龄小于 28 或大于 32age_outlier=df[(df['年龄']<28)|(df['年龄']>32)]print("\n年龄 < 28 或 > 32:")print(age_outlier)4.3 使用 ~(非)
取反操作。
# 非技术部门not_tech=df[~(df['部门']=='技术')]print("非技术部门:")print(not_tech)# 年龄不等于 30not_age_30=df[~(df['年龄']==30)]print("\n年龄不等于 30:")print(not_age_30)4.4 复杂组合
# 技术部门且(工资 > 10000 或 绩效为 A)complex_filter=df[(df['部门']=='技术')&((df['工资']>10000)|(df['绩效']=='A'))]print("技术部门且(工资>10000 或 绩效为A):")print(complex_filter)5. 使用 isin() 方法
isin()用于判断值是否在指定列表中。
# 筛选部门在列表中的行target_depts=['技术','市场']filtered=df[df['部门'].isin(target_depts)]print("部门是技术或市场:")print(filtered)# 筛选部门不在列表中的行filtered=df[~df['部门'].isin(target_depts)]print("\n部门不是技术或市场:")print(filtered)# 多列同时使用 isinfiltered=df[df['绩效'].isin(['A','B'])]print("\n绩效是 A 或 B:")print(filtered)6. 使用 between() 方法
between()用于筛选区间内的值(包含边界)。
# 年龄在 28 到 32 之间age_between=df[df['年龄'].between(28,32)]print("年龄在 28-32 之间:")print(age_between)# 工资在 9000 到 12000 之间salary_between=df[df['工资'].between(9000,12000)]print("\n工资在 9000-12000:")print(salary_between)7. 使用 where() 和 mask()
7.1 where() - 保留满足条件的,其他设为 NaN
# 保留工资 > 10000 的值,其他设为 NaNsalary_filtered=df['工资'].where(df['工资']>10000)print("where 筛选:")print(salary_filtered)# 保留原 DataFramefiltered_df=df.where(df['工资']>10000)print("\nDataFrame where:")print(filtered_df)7.2 mask() - 与 where 相反
# 将工资 > 10000 的值设为 NaNmasked=df['工资'].mask(df['工资']>10000)print("mask 筛选:")print(masked)8. 使用 query() 方法(下章详细介绍)
# query 使用字符串表达式filtered=df.query('工资 > 10000 and 部门 == "技术"')print("query 筛选:")print(filtered)9. 条件筛选的高级用法
9.1 筛选后选择特定列
# 筛选后只显示部分列result=df[df['工资']>10000][['姓名','工资','部门']]print("高薪员工的姓名、工资、部门:")print(result)# 使用 loc 同时筛选行和列result=df.loc[df['工资']>10000,['姓名','工资','部门']]print("\n使用 loc 同时筛选:")print(result)9.2 组合条件筛选
# 多条件组合的多种写法# 写法1:直接组合result1=df[(df['部门']=='技术')&(df['工资']>10000)]# 写法2:使用变量condition=(df['部门']=='技术')&(df['工资']>10000)result2=df[condition]# 写法3:使用 queryresult3=df.query('部门 == "技术" and 工资 > 10000')print("三种写法结果相同:")print(result1)9.3 筛选并修改
# 给符合条件的行添加标记df['是否高薪']=Falsedf.loc[df['工资']>10000,'是否高薪']=Trueprint("添加高薪标记:")print(df)# 批量修改符合条件的值df.loc[df['工作年限']>=5,'绩效']='A+'print("\n修改工作年限>=5的绩效:")print(df)10. 完整示例:员工数据分析
# 创建员工数据np.random.seed(42)employees=pd.DataFrame({'员工ID':range(1,51),'姓名':[f'员工_{i}'foriinrange(1,51)],'年龄':np.random.randint(22,60,50),'工资':np.random.randint(5000,25000,50),'部门':np.random.choice(['技术','销售','市场','人事','财务'],50),'绩效':np.random.choice(['A','B','C','D'],50,p=[0.3,0.4,0.2,0.1]),'工作年限':np.random.randint(0,30,50)})print("="*60)print("员工数据分析")print("="*60)# 1. 高薪员工(工资 > 15000)print("\n1. 高薪员工:")high_salary=employees[employees['工资']>15000]print(f"人数:{len(high_salary)}")print(high_salary[['姓名','部门','工资']])# 2. 技术部门绩效 A 的员工print("\n2. 技术部门绩效 A:")tech_a=employees[(employees['部门']=='技术')&(employees['绩效']=='A')]print(tech_a[['姓名','工资','绩效']])# 3. 年龄 > 40 且 工作年限 > 15print("\n3. 资深员工(年龄>40且工作年限>15):")senior=employees[(employees['年龄']>40)&(employees['工作年限']>15)]print(senior[['姓名','年龄','工作年限','部门']])# 4. 销售或市场部门的年轻员工(年龄 < 30)print("\n4. 销售/市场部门的年轻员工:")young_sales=employees[(employees['部门'].isin(['销售','市场']))&(employees['年龄']<30)]print(young_sales[['姓名','部门','年龄','工资']])# 5. 异常值检测:工资异常低或高print("\n5. 异常工资(<8000 或 >20000):")outliers=employees[(employees['工资']<8000)|(employees['工资']>20000)]print(outliers[['姓名','部门','工资']])# 6. 各维度统计print("\n6. 高薪员工部门分布:")print(high_salary['部门'].value_counts())print("\n7. 各绩效等级的平均工资:")print(employees.groupby('绩效')['工资'].mean().round(0))11. 常见陷阱
| 陷阱 | 说明 | 解决方案 |
|---|---|---|
| 忘记括号 | df[df['A'] > 1 & df['B'] < 5]报错 | 每个条件用括号:df[(df['A'] > 1) & (df['B'] < 5)] |
| 使用 and/or | Python 的and/or不能用于 Series | 使用&/` |
| 链式赋值 | df[df['A']>1]['B'] = 0可能无效 | 使用loc:df.loc[df['A']>1, 'B'] = 0 |
| 浮点数比较 | 浮点数精度问题 | 使用np.isclose() |
12. 总结
| 操作符 | 含义 | 示例 |
|---|---|---|
> | 大于 | df[df['年龄'] > 30] |
< | 小于 | df[df['年龄'] < 30] |
== | 等于 | df[df['部门'] == '技术'] |
!= | 不等于 | df[df['部门'] != '技术'] |
>= | 大于等于 | df[df['工资'] >= 10000] |
<= | 小于等于 | df[df['工资'] <= 5000] |
& | 与(AND) | (df['年龄']>30) & (df['工资']>10000) |
| ` | ` | 或(OR) |
~ | 非(NOT) | ~(df['部门'] == '技术') |
isin() | 在列表中 | df[df['部门'].isin(['技术','市场'])] |
between() | 在区间内 | df[df['年龄'].between(25, 35)] |