071、Pandas 入门:Series 与 DataFrame 的创建、选择、过滤基础

发布时间:2026/6/29 0:48:10
071、Pandas 入门:Series 与 DataFrame 的创建、选择、过滤基础 071、Pandas 入门Series 与 DataFrame 的创建、选择、过滤基础一个让我熬夜到凌晨3点的bug上周帮同事排查一个数据清洗脚本代码逻辑看着没问题但输出结果总是少了几行。我盯着屏幕看了两个小时咖啡喝了三杯最后发现罪魁祸首是——他用列表索引的方式去取DataFrame的行结果索引值不连续直接跳过了好几条数据。这种坑新手踩一次能记一辈子。Pandas的Series和DataFrame看着像Excel表格用起来像Excel表格但底层逻辑完全不是那么回事。今天我把这些基础操作掰开揉碎了讲清楚顺便把我踩过的坑都标出来。Series一维数据但别当列表用创建Series的几种姿势importpandasaspdimportnumpyasnp# 最基础的创建方式s1pd.Series([1,3,5,np.nan,6,8])# 这里踩过坑np.nan是浮点数如果整列混入nan整列会变成float64# 别这样写pd.Series([1, 2, None]) # None会被自动转为NaN类型变成object# 带索引的创建s2pd.Series([10,20,30],index[a,b,c])# 索引可以是字符串、整数、甚至混合类型但别混合后面切片会疯掉# 从字典创建键自动变成索引data_dict{apple:3.5,banana:2.0,orange:4.0}s3pd.Series(data_dict)# 这个用法在数据映射时特别爽比如把商品名映射到价格Series的选择操作——这里最容易翻车spd.Series([10,20,30,40,50],index[a,b,c,d,e])# 位置索引从0开始print(s[0])# 10print(s[1:3])# 注意位置切片是左闭右开输出b和c# 标签索引用index取值print(s[a])# 10print(s[a:c])# 这里坑来了标签切片是闭区间输出a,b,c# 别这样写s[0]和s[a]混用代码维护时自己都看不懂# 推荐写法用.iloc和.loc明确意图print(s.iloc[0])# 明确用位置取print(s.loc[a:c])# 明确用标签取闭区间# 这个习惯养成了后面处理复杂索引时能少掉一半头发过滤操作spd.Series([15,22,8,30,12],index[a,b,c,d,e])# 布尔索引——最常用的过滤方式filter_conditions15print(s[filter_condition])# 输出b和d# 一行搞定print(s[s15])# 多条件过滤print(s[(s10)(s25)])# 注意括号不能省不能写成and# 这里踩过坑用and会报错因为Series的布尔运算必须用位运算符DataFrame二维表格但别当Excel用创建DataFrame的实战姿势# 从字典列表创建——最常用的方式data{name:[张三,李四,王五,赵六],age:[25,30,35,28],salary:[8000,12000,15000,9500],department:[技术部,市场部,技术部,财务部]}dfpd.DataFrame(data)# 列的顺序默认按字典插入顺序想控制顺序就指定columns参数# 从嵌套字典创建nested_data{张三:{age:25,salary:8000},李四:{age:30,salary:12000}}df2pd.DataFrame(nested_data).T# .T转置让名字变成行索引# 这个技巧在处理JSON数据时特别有用# 从CSV读取实际工作中90%的情况# df pd.read_csv(data.csv, encodingutf-8)# 别这样写不指定encoding遇到中文直接乱码列选择——最基础也最容易出错# 选择单列——返回Seriesname_coldf[name]# 返回Series# 或者用点号name_coldf.name# 也能用但列名有空格或特殊字符时炸裂# 选择多列——返回DataFramesubsetdf[[name,salary]]# 注意是双层括号# 别这样写df[name, salary] # 这是元组索引会报错# 选择行——用切片first_threedf[:3]# 前3行# 这里踩过坑df[0:3]和df.iloc[0:3]效果一样但df[0]和df.iloc[0]完全不同# df[0]会报错列名是0时才有效df.iloc[0]才是取第一行行选择——.loc和.iloc的终极对决# .loc基于标签行索引名和列名# .iloc基于位置整数索引# 选择单行print(df.loc[0])# 索引为0的行print(df.iloc[0])# 第一行如果索引不是0结果可能不同# 选择多行print(df.loc[0:2])# 标签切片闭区间包含0,1,2print(df.iloc[0:2])# 位置切片左闭右开包含0,1# 行列同时选择print(df.loc[0:2,[name,salary]])# 前3行的name和salary列print(df.iloc[0:2,0:2])# 前2行的前2列# 实战技巧用布尔索引选行再选列tech_deptdf[df[department]技术部]print(tech_dept[[name,salary]])# 这个组合拳能解决80%的数据筛选需求过滤操作——从入门到精通# 单条件过滤tech_staffdf[df[department]技术部]# 多条件过滤high_salary_techdf[(df[department]技术部)(df[salary]10000)]# 注意两边要加括号这是新手最容易犯的错误# 使用.isin()进行多值匹配tech_or_marketdf[df[department].isin([技术部,市场部])]# 字符串方法过滤name_contains_张df[df[name].str.contains(张)]# 这里踩过坑直接用df[name].contains(张)会报错必须用.str访问器# 空值处理df_with_nandf.copy()df_with_nan.loc[1,salary]np.nan valid_rowsdf_with_nan[df_with_nan[salary].notna()]# 别这样写df_with_nan[df_with_nan[salary] ! np.nan] # NaN不等于任何值包括自身一个真实场景的完整案例上周处理一份销售数据需求是找出技术部中工资高于平均水平的员工# 模拟数据sales_data{name:[张三,李四,王五,赵六,钱七],dept:[技术部,市场部,技术部,财务部,技术部],salary:[8000,12000,15000,9500,11000]}dfpd.DataFrame(sales_data)# 第一步筛选技术部tech_dfdf[df[dept]技术部]# 第二步计算技术部平均工资avg_salarytech_df[salary].mean()# 第三步筛选高于平均工资的resulttech_df[tech_df[salary]avg_salary]print(result)# 输出王五和钱七这个案例看起来简单但实际工作中数据量大了之后性能问题就出来了。如果数据有10万行建议用.query()方法resultdf.query(dept 技术部 and salary salary.mean())# 一行搞定而且底层用numexpr加速比布尔索引快30%左右个人经验总结永远用.iloc和.loc别偷懒用df[0]这种写法三个月后你自己都看不懂。明确告诉读者你是按位置还是按标签取数据。链式操作要谨慎df[df[a]0][b]这种写法会触发SettingWithCopyWarning正确做法是df.loc[df[a]0, b]。数据类型是隐形杀手创建Series时混入None或np.nan整列类型会变。用df.dtypes随时检查用pd.to_numeric()强制转换。索引重置是基本功过滤后的DataFrame索引可能不连续用reset_index(dropTrue)重置否则后面用.loc取行时会踩坑。调试时多用.shape和.head()每步操作后看一眼数据形状能快速定位问题。我见过太多人写了50行代码才发现第一步就错了。Pandas的学习曲线确实陡峭但掌握了Series和DataFrame的创建、选择、过滤这三个基础操作后面学groupby、merge、pivot_table就会顺畅很多。记住数据操作的核心就三件事——选行、选列、条件过滤所有复杂操作都是这三者的组合。