Pandas-DataFrame 数据结构详解
DataFrame 数据结构详解
目录
- 什么是 DataFrame
- 创建 DataFrame
- DataFrame 的基本属性
- 查看和检查数据
- DataFrame 的索引和列
- DataFrame 的基本操作
- 选择和筛选数据
- 添加和删除列
- 添加和删除行
- 数据类型和转换
- 实际应用示例
什么是 DataFrame
DataFrame 是 Pandas 中最重要的数据结构,它是一个二维的、大小可变、可以包含异构数据的表格型数据结构。
DataFrame 的特点:
- 二维表格:有行和列
- 行索引(Index):每一行的标识
- 列索引(Columns):每一列的名称
- 数据类型:每一列可以有不同的数据类型
- 灵活:可以从多种数据源创建
DataFrame 类似于:
- Excel 电子表格
- SQL 表
- R 的 data.frame
创建 DataFrame
1. 从字典创建(最常用)
import pandas as pd# 字典的键作为列名
data = {'姓名': ['张三', '李四', '王五', '赵六'],'年龄': [25, 30, 35, 28],'城市': ['北京', '上海', '广州', '深圳'],'工资': [8000, 12000, 10000, 11000]
}df = pd.DataFrame(data)
print(df)
# 输出:
# 姓名 年龄 城市 工资
# 0 张三 25 北京 8000
# 1 李四 30 上海 12000
# 2 王五 35 广州 10000
# 3 赵六 28 深圳 11000# 指定索引
df = pd.DataFrame(data, index=['emp1', 'emp2', 'emp3', 'emp4'])
print(df)
2. 从列表的列表创建
import pandas as pd# 二维列表
data = [['张三', 25, '北京', 8000],['李四', 30, '上海', 12000],['王五', 35, '广州', 10000],['赵六', 28, '深圳', 11000]
]# 需要指定列名
df = pd.DataFrame(data, columns=['姓名', '年龄', '城市', '工资'])
print(df)# 指定索引
df = pd.DataFrame(data, columns=['姓名', '年龄', '城市', '工资'],index=['a', 'b', 'c', 'd'])
print(df)
3. 从字典列表创建
import pandas as pd# 每个字典代表一行数据
data = [{'姓名': '张三', '年龄': 25, '城市': '北京', '工资': 8000},{'姓名': '李四', '年龄': 30, '城市': '上海', '工资': 12000},{'姓名': '王五', '年龄': 35, '城市': '广州', '工资': 10000},{'姓名': '赵六', '年龄': 28, '城市': '深圳', '工资': 11000}
]df = pd.DataFrame(data)
print(df)
4. 从 NumPy 数组创建
import pandas as pd
import numpy as np# 创建 NumPy 数组
arr = np.array([[1, 2, 3],[4, 5, 6],[7, 8, 9]
])df = pd.DataFrame(arr, columns=['A', 'B', 'C'], index=['x', 'y', 'z'])
print(df)
# 输出:
# A B C
# x 1 2 3
# y 4 5 6
# z 7 8 9
5. 从 Series 创建
import pandas as pd# 多个 Series 组合成 DataFrame
s1 = pd.Series(['张三', '李四', '王五'], name='姓名')
s2 = pd.Series([25, 30, 35], name='年龄')
s3 = pd.Series(['北京', '上海', '广州'], name='城市')df = pd.DataFrame({'姓名': s1, '年龄': s2, '城市': s3})
print(df)
6. 创建空 DataFrame
import pandas as pd# 空 DataFrame
df_empty = pd.DataFrame()
print(df_empty)# 指定列名的空 DataFrame
df_empty = pd.DataFrame(columns=['姓名', '年龄', '城市'])
print(df_empty)# 添加数据
df_empty.loc[0] = ['张三', 25, '北京']
print(df_empty)
DataFrame 的基本属性
import pandas as pddata = {'姓名': ['张三', '李四', '王五', '赵六'],'年龄': [25, 30, 35, 28],'城市': ['北京', '上海', '广州', '深圳'],'工资': [8000, 12000, 10000, 11000]
}
df = pd.DataFrame(data)# 查看索引
print(df.index)
# 输出:RangeIndex(start=0, stop=4, step=1)# 查看列名
print(df.columns)
# 输出:Index(['姓名', '年龄', '城市', '工资'], dtype='object')# 查看数据值(返回 NumPy 数组)
print(df.values)
# 输出:
# [['张三' 25 '北京' 8000]
# ['李四' 30 '上海' 12000]
# ['王五' 35 '广州' 10000]
# ['赵六' 28 '深圳' 11000]]# 查看形状(行数,列数)
print(df.shape)
# 输出:(4, 4)# 查看大小(总元素数)
print(df.size)
# 输出:16# 查看维度
print(df.ndim)
# 输出:2# 查看数据类型
print(df.dtypes)
# 输出:
# 姓名 object
# 年龄 int64
# 城市 object
# 工资 int64
# dtype: object# 查看是否为空
print(df.empty)
# 输出:False# 查看内存使用情况
print(df.memory_usage())
查看和检查数据
1. 查看前几行和后几行
import pandas as pddata = {'姓名': ['张三', '李四', '王五', '赵六', '孙七'],'年龄': [25, 30, 35, 28, 32],'工资': [8000, 12000, 10000, 11000, 9500]
}
df = pd.DataFrame(data)# 查看前 n 行(默认 5 行)
print(df.head())
print(df.head(3)) # 查看前 3 行# 查看后 n 行(默认 5 行)
print(df.tail())
print(df.tail(2)) # 查看后 2 行# 查看随机几行
print(df.sample(2))
2. 查看基本信息
import pandas as pddata = {'姓名': ['张三', '李四', '王五', '赵六'],'年龄': [25, 30, 35, 28],'城市': ['北京', '上海', '广州', '深圳'],'工资': [8000, 12000, 10000, 11000]
}
df = pd.DataFrame(data)# 查看信息摘要
df.info()
# 输出:
# <class 'pandas.core.frame.DataFrame'>
# RangeIndex: 4 entries, 0 to 3
# Data columns (total 4 columns):
# # Column Non-Null Count Dtype
# --- ------ -------------- -----
# 0 姓名 4 non-null object
# 1 年龄 4 non-null int64
# 2 城市 4 non-null object
# 3 工资 4 non-null int64
# dtypes: int64(2), object(2)
# memory usage: 256.0+ bytes# 查看统计信息(仅数值列)
print(df.describe())
# 输出:
# 年龄 工资
# count 4.000000 4.000000
# mean 29.500000 10250.000000
# std 4.203173 1789.350849
# min 25.000000 8000.000000
# 25% 27.250000 9250.000000
# 50% 29.000000 10500.000000
# 75% 31.750000 11250.000000
# max 35.000000 12000.000000# 包含所有列的统计信息
print(df.describe(include='all'))
3. 检查缺失值
import pandas as pd
import numpy as npdata = {'姓名': ['张三', '李四', '王五', '赵六'],'年龄': [25, 30, np.nan, 28],'城市': ['北京', '上海', '广州', np.nan],'工资': [8000, 12000, 10000, 11000]
}
df = pd.DataFrame(data)# 检查缺失值(返回布尔 DataFrame)
print(df.isna())
# 输出:
# 姓名 年龄 城市 工资
# 0 False False False False
# 1 False False False False
# 2 False True False False
# 3 False False True False# 统计每列的缺失值数量
print(df.isna().sum())
# 输出:
# 姓名 0
# 年龄 1
# 城市 1
# 工资 0
# dtype: int64# 检查非缺失值
print(df.notna())# 检查是否有缺失值
print(df.isna().any().any()) # True
DataFrame 的索引和列
1. 设置和重置索引
import pandas as pddata = {'姓名': ['张三', '李四', '王五'],'年龄': [25, 30, 35],'工资': [8000, 12000, 10000]
}
df = pd.DataFrame(data)# 设置索引
df_indexed = df.set_index('姓名')
print(df_indexed)
# 输出:
# 年龄 工资
# 姓名
# 张三 25 8000
# 李四 30 12000
# 王五 35 10000# 重置索引
df_reset = df_indexed.reset_index()
print(df_reset)# 使用多列作为索引
df_multi = df.set_index(['姓名', '年龄'])
print(df_multi)
2. 重命名列和索引
import pandas as pddata = {'姓名': ['张三', '李四', '王五'],'年龄': [25, 30, 35],'工资': [8000, 12000, 10000]
}
df = pd.DataFrame(data)# 重命名列
df_renamed = df.rename(columns={'姓名': 'name', '年龄': 'age', '工资': 'salary'})
print(df_renamed)# 重命名索引
df_index_renamed = df.rename(index={0: 'a', 1: 'b', 2: 'c'})
print(df_index_renamed)# 重命名所有列
df.columns = ['Name', 'Age', 'Salary']
print(df)
选择和筛选数据
1. 选择列
import pandas as pddata = {'姓名': ['张三', '李四', '王五', '赵六'],'年龄': [25, 30, 35, 28],'城市': ['北京', '上海', '广州', '深圳'],'工资': [8000, 12000, 10000, 11000]
}
df = pd.DataFrame(data)# 选择单列(返回 Series)
col1 = df['姓名']
print(col1)
# 输出:
# 0 张三
# 1 李四
# 2 王五
# 3 赵六
# Name: 姓名, dtype: object# 选择单列(返回 DataFrame)
col1_df = df[['姓名']]
print(col1_df)# 选择多列
cols = df[['姓名', '工资']]
print(cols)# 使用点号访问(列名必须是有效的 Python 标识符)
col2 = df.年龄
print(col2)
2. 选择行
import pandas as pddata = {'姓名': ['张三', '李四', '王五', '赵六'],'年龄': [25, 30, 35, 28],'工资': [8000, 12000, 10000, 11000]
}
df = pd.DataFrame(data)# 使用 iloc(位置索引)
row1 = df.iloc[0] # 第一行
rows = df.iloc[0:2] # 前两行
row_last = df.iloc[-1] # 最后一行# 使用 loc(标签索引)
row_by_label = df.loc[0] # 索引为 0 的行
rows_range = df.loc[0:2] # 索引 0 到 2(包含结束位置)# 选择特定位置的值
value = df.iloc[0, 1] # 第 0 行,第 1 列
value2 = df.loc[0, '年龄'] # 索引 0,列名 '年龄'
3. 条件筛选
import pandas as pddata = {'姓名': ['张三', '李四', '王五', '赵六'],'年龄': [25, 30, 35, 28],'城市': ['北京', '上海', '广州', '深圳'],'工资': [8000, 12000, 10000, 11000]
}
df = pd.DataFrame(data)# 单条件筛选
filtered1 = df[df['年龄'] > 30]
print(filtered1)
# 输出:
# 姓名 年龄 城市 工资
# 2 王五 35 广州 10000# 多条件筛选(使用 & 和 |)
filtered2 = df[(df['年龄'] > 25) & (df['工资'] > 10000)]
print(filtered2)filtered3 = df[(df['城市'] == '北京') | (df['城市'] == '上海')]
print(filtered3)# 使用 isin 方法
filtered4 = df[df['城市'].isin(['北京', '上海'])]
print(filtered4)# 字符串包含筛选
filtered5 = df[df['姓名'].str.contains('三')]
print(filtered5)
4. 使用 query 方法
import pandas as pddata = {'姓名': ['张三', '李四', '王五', '赵六'],'年龄': [25, 30, 35, 28],'工资': [8000, 12000, 10000, 11000]
}
df = pd.DataFrame(data)# 使用 query 方法(类似 SQL)
result = df.query('年龄 > 30')
print(result)result2 = df.query('年龄 > 25 and 工资 > 10000')
print(result2)# 使用变量
age_threshold = 30
result3 = df.query('年龄 > @age_threshold')
print(result3)
添加和删除列
1. 添加列
import pandas as pddata = {'姓名': ['张三', '李四', '王五'],'年龄': [25, 30, 35],'工资': [8000, 12000, 10000]
}
df = pd.DataFrame(data)# 方法1:直接赋值
df['奖金'] = [1000, 2000, 1500]
print(df)# 方法2:使用 assign 方法
df = df.assign(总工资=df['工资'] + df.get('奖金', 0))
print(df)# 方法3:基于现有列计算
df['年薪'] = df['工资'] * 12
print(df)# 方法4:插入列到指定位置
df.insert(1, '部门', ['销售', '技术', '销售'])
print(df)
2. 删除列
import pandas as pddata = {'姓名': ['张三', '李四', '王五'],'年龄': [25, 30, 35],'工资': [8000, 12000, 10000],'奖金': [1000, 2000, 1500]
}
df = pd.DataFrame(data)# 方法1:使用 drop(返回新 DataFrame)
df_new = df.drop('奖金', axis=1)
print(df_new)# 方法2:修改原 DataFrame
df.drop('奖金', axis=1, inplace=True)
print(df)# 删除多列
df.drop(['年龄', '工资'], axis=1, inplace=True)
print(df)# 使用 del 关键字
df['临时列'] = [1, 2, 3]
del df['临时列']
print(df)
添加和删除行
1. 添加行
import pandas as pddata = {'姓名': ['张三', '李四'],'年龄': [25, 30],'工资': [8000, 12000]
}
df = pd.DataFrame(data)# 方法1:使用 loc
df.loc[2] = ['王五', 35, 10000]
print(df)# 方法2:使用 append(已弃用,推荐使用 concat)
new_row = pd.DataFrame({'姓名': ['赵六'], '年龄': [28], '工资': [11000]})
df = pd.concat([df, new_row], ignore_index=True)
print(df)# 方法3:使用字典
df.loc[len(df)] = {'姓名': '孙七', '年龄': 32, '工资': 9500}
print(df)
2. 删除行
import pandas as pddata = {'姓名': ['张三', '李四', '王五', '赵六'],'年龄': [25, 30, 35, 28],'工资': [8000, 12000, 10000, 11000]
}
df = pd.DataFrame(data)# 删除指定索引的行
df_new = df.drop(0) # 删除索引为 0 的行
print(df_new)# 删除多行
df_new = df.drop([0, 2])
print(df_new)# 修改原 DataFrame
df.drop(0, inplace=True)
print(df)# 根据条件删除
df = df[df['年龄'] < 35] # 保留年龄小于 35 的行
print(df)
数据类型和转换
import pandas as pddata = {'姓名': ['张三', '李四', '王五'],'年龄': ['25', '30', '35'], # 字符串类型'工资': [8000.5, 12000.3, 10000.7] # 浮点数
}
df = pd.DataFrame(data)# 查看数据类型
print(df.dtypes)# 转换单列数据类型
df['年龄'] = df['年龄'].astype(int)
print(df.dtypes)# 转换多列数据类型
df = df.astype({'年龄': int, '工资': int})
print(df.dtypes)# 转换为字符串
df['工资'] = df['工资'].astype(str)# 转换为日期
df['日期'] = ['2024-01-01', '2024-01-02', '2024-01-03']
df['日期'] = pd.to_datetime(df['日期'])
print(df.dtypes)# 转换为类别类型(节省内存)
df['姓名'] = df['姓名'].astype('category')
print(df.dtypes)
实际应用示例
示例 1:员工信息管理
import pandas as pd# 创建员工数据
employees = pd.DataFrame({'员工ID': ['E001', 'E002', 'E003', 'E004'],'姓名': ['张三', '李四', '王五', '赵六'],'部门': ['销售', '技术', '销售', '技术'],'年龄': [25, 30, 35, 28],'工资': [8000, 12000, 10000, 11000],'入职日期': ['2020-01-01', '2019-06-15', '2018-03-20', '2021-09-10']
})# 转换日期类型
employees['入职日期'] = pd.to_datetime(employees['入职日期'])# 添加工作年限列
from datetime import datetime
employees['工作年限'] = (datetime.now() - employees['入职日期']).dt.days // 365# 添加绩效评级列
employees['绩效评级'] = employees['工资'].apply(lambda x: 'A' if x >= 12000 else ('B' if x >= 10000 else 'C')
)# 筛选销售部门
sales_dept = employees[employees['部门'] == '销售']
print("销售部门员工:")
print(sales_dept)# 按工资排序
employees_sorted = employees.sort_values('工资', ascending=False)
print("\n按工资排序:")
print(employees_sorted)# 部门统计
dept_stats = employees.groupby('部门').agg({'工资': 'mean','年龄': 'mean','员工ID': 'count'
}).rename(columns={'员工ID': '人数'})
print("\n部门统计:")
print(dept_stats)
示例 2:销售数据分析
import pandas as pd# 创建销售数据
sales = pd.DataFrame({'日期': pd.date_range('2024-01-01', periods=10, freq='D'),'产品': ['A', 'B', 'A', 'C', 'B', 'A', 'C', 'B', 'A', 'C'],'销售额': [1000, 1500, 1200, 800, 1800, 1100, 900, 1600, 1300, 850],'数量': [10, 15, 12, 8, 18, 11, 9, 16, 13, 8.5]
})# 添加单价列
sales['单价'] = sales['销售额'] / sales['数量']# 按产品分组统计
product_stats = sales.groupby('产品').agg({'销售额': ['sum', 'mean', 'count'],'数量': 'sum'
})
print("产品统计:")
print(product_stats)# 每日销售额
daily_sales = sales.groupby('日期')['销售额'].sum()
print("\n每日销售额:")
print(daily_sales)# 找出销售额最高的日期
max_date = sales.loc[sales['销售额'].idxmax(), '日期']
print(f"\n销售额最高的日期: {max_date}")# 计算累计销售额
sales['累计销售额'] = sales['销售额'].cumsum()
print("\n累计销售额:")
print(sales[['日期', '销售额', '累计销售额']])
示例 3:学生成绩分析
import pandas as pd
import numpy as np# 创建学生成绩数据
np.random.seed(42)
scores = pd.DataFrame({'学号': [f'S{i:03d}' for i in range(1, 21)],'姓名': [f'学生{i}' for i in range(1, 21)],'数学': np.random.randint(60, 101, 20),'英语': np.random.randint(60, 101, 20),'物理': np.random.randint(60, 101, 20),'化学': np.random.randint(60, 101, 20)
})# 计算总分和平均分
scores['总分'] = scores[['数学', '英语', '物理', '化学']].sum(axis=1)
scores['平均分'] = scores[['数学', '英语', '物理', '化学']].mean(axis=1)# 添加等级
def get_grade(avg):if avg >= 90:return '优秀'elif avg >= 80:return '良好'elif avg >= 70:return '中等'elif avg >= 60:return '及格'else:return '不及格'scores['等级'] = scores['平均分'].apply(get_grade)# 统计各等级人数
grade_count = scores['等级'].value_counts()
print("等级分布:")
print(grade_count)# 找出各科最高分
print("\n各科最高分:")
for subject in ['数学', '英语', '物理', '化学']:max_idx = scores[subject].idxmax()print(f"{subject}: {scores.loc[max_idx, subject]} ({scores.loc[max_idx, '姓名']})")# 找出总分前 5 名
top5 = scores.nlargest(5, '总分')[['姓名', '总分', '平均分', '等级']]
print("\n总分前 5 名:")
print(top5)
总结
DataFrame 是 Pandas 的核心数据结构,掌握其使用方法至关重要:
- 创建方式多样:可以从字典、列表、NumPy 数组等多种方式创建
- 灵活的选择方法:使用
loc、iloc、条件筛选等 - 丰富的操作:添加/删除行列、数据类型转换等
- 强大的功能:数据查看、统计、筛选等
