基于用户下拉框输入动态过滤Pandas DataFrame的技术问题
优雅解决Pandas DataFrame动态过滤问题
我完全懂你不想写一堆冗余if-else分支来覆盖所有过滤组合的心情!这里有个简洁的方法,通过动态组合布尔过滤条件实现需求——只对非"All"的选项应用过滤,自动跳过选择"All"的列。
步骤1:保留你的下拉框生成逻辑
你的unique函数和Streamlit下拉框渲染代码可以原样保留,这部分没问题:
import streamlit as st import pandas as pd def unique(df, col_nme, **kwargs): lst_nme = df[col_nme].unique().tolist() lst_nme.insert(0, "All") return lst_nme # 假设df是你的原始DataFrame # df = pd.read_csv("your_data.csv") # 渲染侧边栏下拉框 lst_rprt_status = unique(df, "Reporting Status") rprt_status = st.sidebar.selectbox("Reporting Status", lst_rprt_status) lst_src = unique(df, "Source") src = st.sidebar.selectbox("Source", lst_src) lst_cntrct_type = unique(df, "Contract Type") cntrct_type = st.sidebar.selectbox("Contract Type", lst_cntrct_type) lst_country = unique(df, "Country") country = st.sidebar.selectbox("Country", lst_country)
步骤2:动态组合过滤条件
我们把列名、选择值配对成一个列表,遍历后只筛选出选择值不是"All"的条件,最后用&(逻辑与)把所有有效条件组合起来:
# 把列名和对应的选择值打包成元组列表 filter_pairs = [ ("Reporting Status", rprt_status), ("Source", src), ("Contract Type", cntrct_type), ("Country", country) ] # 初始化过滤条件为全True(即不做任何过滤) final_filter = pd.Series([True] * len(df), index=df.index) # 遍历每个配对,动态叠加有效过滤条件 for col_name, selected_val in filter_pairs: if selected_val != "All": final_filter &= df[col_name] == selected_val # 应用过滤得到结果 filtered_df = df[final_filter]
为什么这个方法好用?
- 初始的
final_filter是全True的Series,相当于默认展示完整数据; - 每遇到非"All"的选择,就用
&叠加对应布尔条件,实现多条件同时过滤; - 不管哪个下拉框选"All",都会自动跳过该列的过滤,完全不用写分支判断;
- 后续要加新的下拉框,只需要在
filter_pairs里加一行元组就行,扩展性超强!
额外优化:用df.query的简化写法
如果你更喜欢SQL风格的查询写法,也可以动态拼接查询字符串:
query_parts = [] for col_name, selected_val in filter_pairs: if selected_val != "All": # 针对字符串类型的值添加引号,避免语法错误 if df[col_name].dtype == object: query_parts.append(f"`{col_name}` == '{selected_val}'") else: query_parts.append(f"`{col_name}` == {selected_val}") # 用and拼接所有查询条件,无过滤条件时直接返回原df final_query = " and ".join(query_parts) filtered_df = df.query(final_query) if query_parts else df
内容的提问来源于stack exchange,提问作者Mohamed Serag
相关产品推荐
相关产品推荐

