Pandas 是 Python 数据分析的核心库,提供了快速、灵活、易用的数据结构(Series 和 DataFrame),能够轻松处理结构化数据(如表格、时间序列等)。本教程将带你全面了解 Pandas 的常用功能,并通过丰富的示例代码帮助你快速上手Pandas简介:是什么,为什么用,主要数据结构(Series和DataFrame)。安装和导入。创建数据:从列表、字典、NumPy数组、文件读取等。数据查看:head(), info(), describe()等。数据选择:列选择、行选择(loc, iloc),条件筛选。数据清洗:处理缺失值(dropna, fillna),重复值,数据类型转换。数据操作:添加/删除列,apply函数,排序。数据聚合和分组:groupby,聚合函数。数据合并:concat, merge。时间序列处理(简要)。数据可视化(结合matplotlib简要)。导出数据
如果你还没有安装 Pandas,可以在终端执行以下命令:pip install pandas -i https://mirrors.aliyun.com/pypi/simple/
import pandas as pdprint(pd.__version__) # 输出当前版本号
一维带标签的数组,类似于 Excel 的一列或 Python 的字典import pandas as pd# 从列表创建s1 = pd.Series([10, 20, 30, 40])print(s1)# 输出:# 0 10# 1 20# 2 30# 3 40# dtype: int64# 指定索引s2 = pd.Series([10, 20, 30, 40], index=['a', 'b', 'c', 'd'])print(s2)# a 10# b 20# c 30# d 40# dtype: int64# 从字典创建(键自动成为索引)s3 = pd.Series({'apple': 5, 'banana': 3, 'orange': 8})print(s3)# apple 5# banana 3# orange 8# dtype: int64
二维表格型数据结构,由多个 Series 组成,有行索引和列索引# 从字典创建(键为列名,值为列表)data = { '姓名': ['张三', '李四', '王五', '赵六'], '年龄': [23, 28, 22, 35], '城市': ['北京', '上海', '广州', '深圳'], '工资': [8000, 12000, 9500, 15000]}df = pd.DataFrame(data)print(df)# 姓名 年龄 城市 工资# 0 张三 23 北京 8000# 1 李四 28 上海 12000# 2 王五 22 广州 9500# 3 赵六 35 深圳 15000# 指定列顺序df2 = pd.DataFrame(data, columns=['姓名', '城市', '工资', '年龄'])print(df2)# 从列表嵌套创建data2 = [['张三', 23, '北京'], ['李四', 28, '上海']]df3 = pd.DataFrame(data2, columns=['姓名', '年龄', '城市'])print(df3)
# 查看前几行(默认5行)print(df.head(2)) # 前2行print(df.tail(2)) # 后2行# 查看数据概览print(df.info()) # 列名、非空计数、数据类型print(df.shape) # (行数, 列数)# 描述性统计(数值列)print(df.describe()) # 计数、均值、标准差、分位数等# 查看列名和索引print(df.columns) # Index(['姓名', '年龄', '城市', '工资'], dtype='object')print(df.index) # RangeIndex(start=0, stop=4, step=1)# 转置print(df.T)
# 选择单列,返回 Seriesnames = df['姓名']print(type(names)) # <class 'pandas.core.series.Series'># 选择多列,返回 DataFramesubset = df[['姓名', '工资']]print(subset)# 使用点号访问(列名无空格且不与方法冲突)print(df.姓名) # 等同于 df['姓名']
# 通过行号切片(类似列表)print(df[1:3]) # 第2行到第3行(左闭右开)# 使用 loc(基于标签索引)print(df.loc[1]) # 选择索引为1的行(Series)print(df.loc[1:3]) # 索引1到3的行(包含两端)print(df.loc[[0, 2]]) # 选择索引0和2的行# 使用 iloc(基于整数位置)print(df.iloc[0]) # 第1行print(df.iloc[1:3]) # 第2行到第3行(左闭右开,不含第4行)print(df.iloc[[0, 2]]) # 第1行和第3行
# 筛选年龄大于25的行filtered = df[df['年龄'] > 25]print(filtered)# 多个条件(注意用小括号括起来,使用 & | 而不是 and or)filtered2 = df[(df['年龄'] > 25) & (df['工资'] < 13000)]print(filtered2)# 使用 isin 进行成员判断filtered3 = df[df['城市'].isin(['北京', '上海'])]print(filtered3)
# loc + 条件print(df.loc[df['年龄'] > 25, ['姓名', '工资']])# iloc 选取指定行和列的位置print(df.iloc[1:3, [0, 2]]) # 第2-3行,第1和3列
import numpy as np# 构造含缺失值的DataFramedf_missing = pd.DataFrame({ 'A': [1, 2, np.nan, 4], 'B': [5, np.nan, np.nan, 8], 'C': ['x', 'y', 'z', None]})print(df_missing)# 检查缺失值print(df_missing.isnull()) # True表示缺失print(df_missing.isnull().sum()) # 每列缺失个数# 删除含缺失值的行df_dropna = df_missing.dropna() # 默认删除任何含有NaN的行print(df_dropna)# 删除整行全为NaN的行(可选参数 how='all')df_dropna_all = df_missing.dropna(how='all')# 删除含缺失值的列df_dropna_col = df_missing.dropna(axis=1) # 删除含有NaN的列# 填充缺失值df_fill = df_missing.fillna(0) # 用0填充df_fill_ffill = df_missing.fillna(method='ffill') # 用前一个值填充df_fill_bfill = df_missing.fillna(method='bfill') # 用后一个值填充# 使用均值填充数值列df_missing['A'] = df_missing['A'].fillna(df_missing['A'].mean())print(df_missing)
# 构造重复数据df_dup = pd.DataFrame({ 'id': [1, 2, 2, 3, 3], 'value': ['a', 'b', 'b', 'c', 'd']})print(df_dup)# 检查重复行print(df_dup.duplicated()) # 返回布尔Series,标记重复行(除第一次出现外)# 删除重复行df_dup_drop = df_dup.drop_duplicates()print(df_dup_drop)# 基于特定列去重df_dup_drop_col = df_dup.drop_duplicates(subset=['id'])print(df_dup_drop_col)# 保留最后一次出现的重复df_dup_drop_last = df_dup.drop_duplicates(keep='last')
# 查看数据类型print(df.dtypes)# 转换列类型df['年龄'] = df['年龄'].astype(float) # 转为浮点型df['工资'] = pd.to_numeric(df['工资'], errors='coerce') # 强制转换,错误转为NaN# 将字符串列转为日期时间df['日期'] = pd.to_datetime(['2023-01-01', '2023-02-01', '2023-03-01', '2023-04-01'])print(df.dtypes)
# 添加新列(直接赋值)df['税后工资'] = df['工资'] * 0.9print(df)# 根据条件创建列df['年龄组'] = df['年龄'].apply(lambda x: '青年' if x < 30 else '中年')print(df)# 删除列df.drop('税后工资', axis=1, inplace=True) # axis=1表示列,inplace=True直接修改原df# 或使用 pop 删除并返回该列deleted_col = df.pop('年龄组')print(df)
# 对单列应用函数df['工资翻倍'] = df['工资'].apply(lambda x: x * 2)# 对多列应用函数,axis=1表示逐行df['描述'] = df.apply(lambda row: f"{row['姓名']}来自{row['城市']}", axis=1)print(df[['姓名', '城市', '描述']])
# 按年龄升序df_sorted = df.sort_values(by='年龄')print(df_sorted)# 按工资降序df_sorted_desc = df.sort_values(by='工资', ascending=False)print(df_sorted_desc)# 多列排序(先城市,再年龄)df_sorted_multi = df.sort_values(by=['城市', '年龄'])print(df_sorted_multi)# 按索引排序df_sorted_index = df.sort_index()
df.rename(columns={'姓名': 'Name', '年龄': 'Age'}, inplace=True)print(df)
# 删除行后索引可能不连续,重置df_reset = df.reset_index(drop=True) # drop=True 丢弃原索引print(df_reset)
# 创建示例数据:销售记录sales_data = { '产品': ['A', 'B', 'A', 'B', 'A', 'C'], '销售额': [100, 200, 150, 250, 300, 180], '地区': ['北', '南', '北', '南', '东', '东']}sales_df = pd.DataFrame(sales_data)print(sales_df)# 按产品分组,计算销售额总和grouped = sales_df.groupby('产品')['销售额'].sum()print(grouped)# 产品# A 550# B 450# C 180# Name: 销售额, dtype: int64# 多列分组,计算均值grouped_multi = sales_df.groupby(['产品', '地区'])['销售额'].mean()print(grouped_multi)# 对分组后应用多个聚合函数agg_result = sales_df.groupby('产品')['销售额'].agg(['sum', 'mean', 'max', 'min'])print(agg_result)
# 使用 pivot_table 创建类似Excel的数据透视表pivot = pd.pivot_table(sales_df, values='销售额', index='产品', columns='地区', aggfunc='sum', fill_value=0)print(pivot)# 地区 东 北 南# 产品 # A 300 250 0# B 0 0 450# C 180 0 0
# 统计频次cross = pd.crosstab(sales_df['产品'], sales_df['地区'])print(cross)# 地区 东 北 南# 产品 # A 1 2 0# B 0 0 2# C 1 0 0
# 构建两个DataFramedf1 = pd.DataFrame({'A': [1,2], 'B': [3,4]})df2 = pd.DataFrame({'A': [5,6], 'B': [7,8]})# 按行拼接(纵向)concat_rows = pd.concat([df1, df2], axis=0, ignore_index=True)print(concat_rows)# 按列拼接(横向)concat_cols = pd.concat([df1, df2], axis=1)print(concat_cols)
# 两个表left = pd.DataFrame({ 'key': ['K0', 'K1', 'K2', 'K3'], 'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3']})right = pd.DataFrame({ 'key': ['K0', 'K1', 'K2', 'K4'], 'C': ['C0', 'C1', 'C2', 'C4'], 'D': ['D0', 'D1', 'D2', 'D4']})# 内连接(默认)merged_inner = pd.merge(left, right, on='key')print(merged_inner)# 左连接merged_left = pd.merge(left, right, on='key', how='left')print(merged_left)# 右连接merged_right = pd.merge(left, right, on='key', how='right')print(merged_right)# 外连接merged_outer = pd.merge(left, right, on='key', how='outer')print(merged_outer)# 当连接键列名不同时,可以使用 left_on 和 right_onleft2 = pd.DataFrame({'lkey': ['K0','K1','K2'], 'A': [1,2,3]})right2 = pd.DataFrame({'rkey': ['K0','K0','K2'], 'B': [4,5,6]})merged_diff = pd.merge(left2, right2, left_on='lkey', right_on='rkey')print(merged_diff)
left3 = pd.DataFrame({'A': [1,2]}, index=['x','y'])right3 = pd.DataFrame({'B': [3,4]}, index=['x','z'])joined = left3.join(right3, how='outer')print(joined)
# 生成日期范围dates = pd.date_range('2023-01-01', periods=6, freq='D')print(dates)# 创建时间序列DataFramets_df = pd.DataFrame({'数值': np.random.randn(6)}, index=dates)print(ts_df)# 重采样(降采样)resampled = ts_df.resample('2D').mean() # 每2天取均值print(resampled)# 移动窗口计算rolling_mean = ts_df.rolling(window=3).mean()print(rolling_mean)# 时间偏移print(ts_df.shift(1)) # 数据向下移动一行print(ts_df.shift(-1, freq='D')) # 索引向前移动一天
Pandas 集成了 Matplotlib,可以快速绘图:import matplotlib.pyplot as plt# 简单折线图ts_df.plot()plt.show()# 条形图df.plot(kind='bar', x='姓名', y='工资')plt.show()# 直方图df['年龄'].plot(kind='hist', bins=5)plt.show()# 散点图sales_df.plot(kind='scatter', x='销售额', y='产品')plt.show()
# 读取 CSVdf_csv = pd.read_csv('data.csv')# 写入 CSVdf.to_csv('output.csv', index=False)# 读取 Excel(需要安装 openpyxl 或 xlrd)df_excel = pd.read_excel('data.xlsx', sheet_name='Sheet1')# 写入 Exceldf.to_excel('output.xlsx', sheet_name='结果', index=False)# 读取 JSONdf_json = pd.read_json('data.json')# 写入 JSONdf.to_json('output.json', orient='records')# 读取 SQL 数据库(需要 SQLAlchemy)from sqlalchemy import create_engineengine = create_engine('sqlite:///mydb.sqlite')df_sql = pd.read_sql('SELECT * FROM table', engine)df.to_sql('new_table', engine, if_exists='replace')
我们模拟一个学生成绩分析任务,综合运用上述知识点:import pandas as pdimport numpy as np# 1. 创建数据students = pd.DataFrame({ '学号': ['S001', 'S002', 'S003', 'S004', 'S005'], '姓名': ['张明', '李丽', '王磊', '赵华', '陈静'], '班级': ['一班', '二班', '一班', '三班', '二班'], '语文': [85, 92, 78, 88, 95], '数学': [90, 88, 82, 91, 89], '英语': [78, 95, 80, 85, 92]})print("原始数据:")print(students)# 2. 查看基本信息print("\n数据信息:")students.info()# 3. 计算总分和平均分students['总分'] = students[['语文', '数学', '英语']].sum(axis=1)students['平均分'] = students[['语文', '数学', '英语']].mean(axis=1).round(2)print("\n添加总分和平均分:")print(students)# 4. 按班级分组统计各科平均分class_stats = students.groupby('班级')[['语文', '数学', '英语']].mean().round(2)print("\n各班级平均分:")print(class_stats)# 5. 找出总分最高的学生top_student = students.loc[students['总分'].idxmax()]print("\n总分第一名:")print(top_student[['姓名', '班级', '总分']])# 6. 条件筛选:语文大于90且英语大于85的学生excellent = students[(students['语文'] > 90) & (students['英语'] > 85)]print("\n语文>90且英语>85的学生:")print(excellent[['姓名', '语文', '英语']])# 7. 添加成绩等级列def grade(score): if score >= 90: return 'A' elif score >= 80: return 'B' elif score >= 70: return 'C' else: return 'D'students['语文等级'] = students['语文'].apply(grade)students['数学等级'] = students['数学'].apply(grade)students['英语等级'] = students['英语'].apply(grade)print("\n添加等级后:")print(students[['姓名', '语文', '语文等级', '数学', '数学等级', '英语', '英语等级']])# 8. 生成透视表:各班级成绩等级分布pivot_grade = pd.crosstab(students['班级'], students['语文等级'])print("\n各班级语文等级分布:")print(pivot_grade)# 9. 排序:按总分降序students_sorted = students.sort_values('总分', ascending=False)print("\n按总分排序:")print(students_sorted[['姓名', '总分']])# 10. 保存结果到CSVstudents.to_csv('学生成绩分析.csv', index=False, encoding='utf-8-sig')print("\n结果已保存到 '学生成绩分析.csv'")
通过本教程,你应该掌握了 Pandas 的核心功能:数据合并(concat, merge, join)Pandas 是数据分析的基石,建议你多动手练习,结合真实数据集(如 Kaggle 上的数据)进行实践,逐步加深理解