Pandas-DataFrame 数据结构详解

DataFrame 数据结构详解

目录


什么是 DataFrame

DataFrame 是 Pandas 中最重要的数据结构,它是一个二维的、大小可变、可以包含异构数据的表格型数据结构。

DataFrame 的特点:

  • 二维表格:有行和列
  • 行索引(Index):每一行的标识
  • 列索引(Columns):每一列的名称
  • 数据类型:每一列可以有不同的数据类型
  • 灵活:可以从多种数据源创建

DataFrame 类似于:

  • Excel 电子表格
  • SQL 表
  • R 的 data.frame

创建 DataFrame

1. 从字典创建(最常用)

python 复制代码
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. 从列表的列表创建

python 复制代码
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. 从字典列表创建

python 复制代码
import pandas as pd

# 每个字典代表一行数据
data = [
    {'姓名': '张三', '年龄': 25, '城市': '北京', '工资': 8000},
    {'姓名': '李四', '年龄': 30, '城市': '上海', '工资': 12000},
    {'姓名': '王五', '年龄': 35, '城市': '广州', '工资': 10000},
    {'姓名': '赵六', '年龄': 28, '城市': '深圳', '工资': 11000}
]

df = pd.DataFrame(data)
print(df)

4. 从 NumPy 数组创建

python 复制代码
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 创建

python 复制代码
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

python 复制代码
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 的基本属性

python 复制代码
import pandas as pd

data = {
    '姓名': ['张三', '李四', '王五', '赵六'],
    '年龄': [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. 查看前几行和后几行

python 复制代码
import pandas as pd

data = {
    '姓名': ['张三', '李四', '王五', '赵六', '孙七'],
    '年龄': [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. 查看基本信息

python 复制代码
import pandas as pd

data = {
    '姓名': ['张三', '李四', '王五', '赵六'],
    '年龄': [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. 检查缺失值

python 复制代码
import pandas as pd
import numpy as np

data = {
    '姓名': ['张三', '李四', '王五', '赵六'],
    '年龄': [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. 设置和重置索引

python 复制代码
import pandas as pd

data = {
    '姓名': ['张三', '李四', '王五'],
    '年龄': [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. 重命名列和索引

python 复制代码
import pandas as pd

data = {
    '姓名': ['张三', '李四', '王五'],
    '年龄': [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. 选择列

python 复制代码
import pandas as pd

data = {
    '姓名': ['张三', '李四', '王五', '赵六'],
    '年龄': [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. 选择行

python 复制代码
import pandas as pd

data = {
    '姓名': ['张三', '李四', '王五', '赵六'],
    '年龄': [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. 条件筛选

python 复制代码
import pandas as pd

data = {
    '姓名': ['张三', '李四', '王五', '赵六'],
    '年龄': [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 方法

python 复制代码
import pandas as pd

data = {
    '姓名': ['张三', '李四', '王五', '赵六'],
    '年龄': [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. 添加列

python 复制代码
import pandas as pd

data = {
    '姓名': ['张三', '李四', '王五'],
    '年龄': [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. 删除列

python 复制代码
import pandas as pd

data = {
    '姓名': ['张三', '李四', '王五'],
    '年龄': [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. 添加行

python 复制代码
import pandas as pd

data = {
    '姓名': ['张三', '李四'],
    '年龄': [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. 删除行

python 复制代码
import pandas as pd

data = {
    '姓名': ['张三', '李四', '王五', '赵六'],
    '年龄': [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)

数据类型和转换

python 复制代码
import pandas as pd

data = {
    '姓名': ['张三', '李四', '王五'],
    '年龄': ['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:员工信息管理

python 复制代码
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:销售数据分析

python 复制代码
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:学生成绩分析

python 复制代码
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 的核心数据结构,掌握其使用方法至关重要:

  1. 创建方式多样:可以从字典、列表、NumPy 数组等多种方式创建
  2. 灵活的选择方法 :使用 lociloc、条件筛选等
  3. 丰富的操作:添加/删除行列、数据类型转换等
  4. 强大的功能:数据查看、统计、筛选等

相关推荐
wudl55666 小时前
Pandas 简介与安装
pandas
_dindong8 小时前
牛客101:二叉树
数据结构·c++·笔记·学习·算法
潼心1412o12 小时前
数据结构(长期更新)第5讲:单链表算法题
数据结构
小十一再加一16 小时前
【数据结构初阶】单链表
数据结构
ZIM学编程18 小时前
「学长有话说」作为一个大三学长,我想对大一计算机专业学生说这些!
java·c语言·数据结构·c++·python·学习·php
子枫秋月19 小时前
单链表实现全解析
c语言·数据结构·c++
刀法自然19 小时前
栈实现表达式求值
数据结构·算法·图论
Yupureki21 小时前
从零开始的C++学习生活 19:C++复习课(5.4w字全解析)
c语言·数据结构·c++·学习·1024程序员节
ゞ 正在缓冲99%…21 小时前
leetcode1312.让字符串成为回文串的最少插入次数
数据结构·算法·leetcode·动态规划·记忆化搜索