Pandas数据结构DataFrame详解


DataFrame是Pandas库中最核心的数据结构,它以一种表格形式组织数据,类似于 Excel 电子表格或 SQL 数据库表。这种二维数据结构特别适合处理结构化数据。

本文介绍了Pandas中DataFrame的核心功能,包括创建、基本操作(查看、选择、过滤、修改)、常用功能(统计、缺失值处理、排序、分组聚合、应用自定义函数、数据结构转换)、合并与分割方法等。

一、DataFrame主要构成

  • 行(Rows):每行代表一个独立的观测值或数据记录,例如一个人的完整信息
  • 列(Columns):每列代表一个特定的变量或特征,如"年龄"、"城市"等
  • 索引(Index):类似于行的身份证号,用于快速定位和识别特定行

二、创建DataFrame

1. 从字典创建

从字典创建最直观,字典的键自动成为列名,值成为对应列的数据。适合数据已经按列组织好的情况。

import pandas as pd

data = {
    'Name': ['Alice', 'Bob', 'Charlie'],
    'Age': [25, 30, 35],
    'City': ['New York', 'Paris', 'London']
}

df = pd.DataFrame(data)

2. 从列表创建

当数据是按行组织的记录时,这种方法更合适。需要显式指定列名,否则会自动生成数字列名(0,1,2…)。

data = [
    ['Alice', 25, 'New York'],  # 第一个人的完整信息
    ['Bob', 30, 'Paris'], 		# 第二个人的完整信息
    ['Charlie', 35, 'London']	# 第三个人的完整信息
]

# 将列表转换为DataFrame,并指定列名
df = pd.DataFrame(data, columns=['Name', 'Age', 'City'])

三、DataFrame基本操作

1. 查看数据

以下方法可以在不显示全部数据的情况下,快速了解DataFrame的概况。

df.head()      # 查看前5行
df.tail(3)     # 查看后3行
df.shape       # 查看维度(行数,列数)
df.columns     # 查看列名
df.dtypes      # 查看每列数据类型

2. 选择数据

df['Name']          # 选择单列,返回Series对象
df[['Name', 'Age']] # 选择多列,返回新的DataFrame
df.loc[0]           # 按标签选择第一行所有数据
df.iloc[0]          # 按位置(索引)选择第一行所有数据
  • loc 基于标签选择,适合已知行/列名的情况
  • iloc 基于位置选择,适合按数字索引访问

3. 过滤数据

布尔索引是DataFrame的筛选功能,可以使用复杂条件组合来精确选择所需数据。

df[df['Age'] > 30]            # 年龄大于30的记录
df[(df['Age'] > 25) & (df['City'] == 'Paris')]  # 多条件筛选:年龄>25且城市为Paris

4. 修改数据

DataFrame的列操作可以像操作普通变量一样修改列数据。

df['Age'] = df['Age'] + 1       # 年龄列全部加1
df['New_Column'] = range(3)     # 添加新列

四、DataFrame常用功能

1. 描述性统计

使用统计方法能快速了解数据的分布情况和基本特征。

df.info() # 快速查看DataFrame的摘要信息,包括列名、非空值数量、数据类型等
df.describe()       # 对数值列计算统计量(计数、均值、标准差等)
df.mean(numeric_only=True)    # 计算各数值列的均值
df['Age'].value_counts()  # 统计年龄列中每个值的出现次数

df.describe()

默认情况下只对数值列计算统计量,需要会对于非数值列计算,可以使用 include='all' 参数。

  • 对于数值列:计算计数(count)、均值(mean)、标准差(std)、最小值(min)、四分位数(25%、50%、75%)和最大值(max)
  • 对于非数值列:计算计数(count)、唯一值数量(unique)、出现频率最高的值(top)及其出现频率(freq)

参数

df.describe(
    percentiles=None,  # 指定要计算的分位数
    include=None,     # 指定包含的数据类型
    exclude=None,     # 指定排除的数据类型
    datetime_is_numeric=False  # 是否将datetime视为数值型
)

基本示例

import pandas as pd
import numpy as np

# 创建示例DataFrame
df = pd.DataFrame({
    '数值列': np.random.randn(100),
    '分类列': np.random.choice(['A', 'B', 'C'], 100),
    '缺失列': np.random.choice([1, 2, np.nan], 100)
})

# 默认describe
print(df.describe())

控制输出内容

# 只计算特定分位数
df.describe(percentiles=[0.1, 0.5, 0.9])

# 只包含数值列
df.describe(include=[np.number])

# 包含所有列
df.describe(include='all')

# 排除数值列
df.describe(exclude=[np.number])

df.mean()

df.mean()可以对 DataFrame 或 Series 中的数值数据计算算术平均值。
参数

df.mean(
    axis=0,            # 计算方向:0-列方向,1-行方向
    skipna=True,       # 是否跳过NaN值
    numeric_only=True, # 是否只计算数值列
    **kwargs          # 其他参数
)

对DataFrame使用

import pandas as pd

df = pd.DataFrame({
    'A': [1, 2, 3, 4],
    'B': [1.5, 2.5, 3.5, 4.5],
    'C': ['a', 'b', 'c', 'd']  # 非数值列
})

# 计算各列的平均值
print(df.mean())

对Series使用

s = pd.Series([10, 20, 30, 40])
print(s.mean())  # 输出: 25.0

常见场景

# 计算每列的平均值
column_means = df.mean()  # 默认axis=0

# 计算每行的平均值
row_means = df.mean(axis=1)

# 只计算数值列(推荐方式)
df.mean(numeric_only=True)
df_with_nan = pd.DataFrame({'A': [1, 2, np.nan, 4]})

# 跳过NaN计算
df_with_nan.mean()  # 输出A列平均值:(1+2+4)/3 ≈ 2.333

# 包含NaN计算
df_with_nan.mean(skipna=False)  # 输出NaN

2. 处理缺失值

处理缺失值是数据清洗的重要步骤,根据情况选择删除或填充。

df.dropna()         # 删除含缺失值的整行
df.fillna(0)        # 用0填充缺失值
df.isna().sum()     # 统计每列的缺失值数量

3. 排序

排序可以快速发现数据的极值等等。

df.sort_values('Age', ascending=False)  # 按年龄降序排列

4. 分组聚合

分组聚合可以计算各组的统计量。

print(df.groupby('City')['Age'].mean())  # 按城市分组计算平均年龄

5. 应用自定义函数

对DataFrame的行或列应用自定义函数。

df['Age'].apply(lambda x: x * 2)  # 对Age列的值进行加倍

6. 数据结构转换

DataFrame转列表

# 返回所有数据(不含列名)的二维列表。
data = df.values.tolist()

# 提取某一列的数据,转换为列表。
names = df['Name'].tolist()

DataFrame转字典

# 默认返回 {列名: {索引: 值}} 的嵌套字典结构。
dict_data = df.to_dict()

# 返回 [{列名: 值}, ...] 格式的字典列表,适合 JSON 转换。
dict_records = df.to_dict('records')

DataFrame转NumPy数组

# 返回 DataFrame 的 NumPy 数组形式(不包含列名)。
numpy_array = df.to_numpy()

DataFrame转JSON

# 将 DataFrame 转换为 JSON 字符串。
json_str = df.to_json()

# 指定格式(orient 参数)
json_records = df.to_json(orient='records')

五、DataFrame合并

1. concat连接合并

concat是最简单的合并方法,适合结构相同的数据集简单拼接。

import pandas as pd

# 创建示例DataFrame
df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
                    'B': ['B0', 'B1', 'B2']},
                   index=[0, 1, 2])

df2 = pd.DataFrame({'A': ['A3', 'A4', 'A5'],
                    'B': ['B3', 'B4', 'B5']},
                   index=[3, 4, 5])

# 纵向连接(默认axis=0)
result = pd.concat([df1, df2])

# 横向连接
result_h = pd.concat([df1, df2], axis=1)

2. merge键值合并

merge是基于列的合并,类似于SQL的JOIN操作,根据键值合并相关数据。

left = pd.DataFrame({'key': ['K0', 'K1', 'K2'],
                     'A': ['A0', 'A1', 'A2'],
                     'B': ['B0', 'B1', 'B2']})

right = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],
                      'C': ['C0', 'C1', 'C2', 'C3'],
                      'D': ['D0', 'D1', 'D2', 'D3']})

# 内连接(默认)
result = pd.merge(left, right, on='key')

# 左连接
result_left = pd.merge(left, right, how='left', on='key')

# 右连接
result_right = pd.merge(left, right, how='right', on='key')

# 外连接
result_outer = pd.merge(left, right, how='outer', on='key')

3. join索引合并

join是基于索引的合并方法,适合索引有意义的场景。

left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
                     'B': ['B0', 'B1', 'B2']},
                    index=['K0', 'K1', 'K2'])

right = pd.DataFrame({'C': ['C0', 'C1', 'C2'],
                      'D': ['D0', 'D1', 'D2']},
                     index=['K0', 'K1', 'K3'])

# 左连接(默认)
result = left.join(right)

# 右连接
result_right = left.join(right, how='right')

# 内连接
result_inner = left.join(right, how='inner')

# 外连接
result_outer = left.join(right, how='outer')

4. 多键合并

当需要多个字段共同确定关联关系时,可以使用多键合并。

left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],
                     'key2': ['K0', 'K1', 'K0', 'K1'],
                     'A': ['A0', 'A1', 'A2', 'A3'],
                     'B': ['B0', 'B1', 'B2', 'B3']})

right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],
                      'key2': ['K0', 'K0', 'K0', 'K0'],
                      'C': ['C0', 'C1', 'C2', 'C3'],
                      'D': ['D0', 'D1', 'D2', 'D3']})

result = pd.merge(left, right, on=['key1', 'key2'])

5. 合并时处理重复列名

当两个DataFrame有相同列名但不是连接键时,添加后缀避免冲突。

# 合并时对重复列名添加后缀区分
result = pd.merge(left, right, on='key1', suffixes=('_left', '_right'))

6. 合并时添加指示列

indicator列会显示每行是来自"left_only"、“right_only"还是"both”,便于追踪合并结果。

# 合并后添加一列指示每行数据的来源
result = pd.merge(left, right, on='key1', how='outer', indicator=True)

六、DataFrame分割

1. 按行分割

行分割常用于将大数据集分成多个部分处理,或提取符合条件的子集。

# 创建示例DataFrame
df = pd.DataFrame({'A': range(10),
                   'B': range(10, 20),
                   'C': range(20, 30)})

# 取前3行
df_head = df.head(3)

# 取后3行
df_tail = df.tail(3)

# 按位置分割
df_part1 = df.iloc[:5]  # 前5行
df_part2 = df.iloc[5:]  # 第6行到最后

# 按条件分割
df_filtered = df[df['A'] > 5]  # A列大于5的行

2. 按列分割

列分割常用于特征选择,提取感兴趣的变量或特定类型的数据。

# 选择单列(返回Series)
col_a = df['A']

# 选择多列(返回DataFrame)
cols_ab = df[['A', 'B']]

# 按数据类型选择:只选择数值型列
numeric_cols = df.select_dtypes(include=['number'])

3. 随机分割

随机分割常用于创建训练集和测试集,或进行随机抽样分析。

# 随机抽取30%的数据
df_sample = df.sample(frac=0.3)

# 随机抽取固定数量(5行)
df_sample_fixed = df.sample(n=5)

4. 分组后分割

分组后分割可以让我们分别处理每个组的数据。

# 创建分组对象
grouped = df.groupby('A')

# 获取特定组
group_5 = grouped.get_group(5)

# 遍历所有组
for name, group in grouped:
    print(f"Group {name}:")
    print(group)

七、DataFrame与原生数据结构比较

DataFrame适合场景

  • 结构化数据处理(表格、CSV、SQL 表等):天然适合处理行-列结构的数据,更直观
  • 数据清洗与转换:内置方法丰富,处理缺失值、数据归一化、分类聚合等
  • 数据分析与统计计算:内置 mean()、sum()、describe() 等方法,便捷。
  • 大数据处理:底层基于 NumPy/C,运算速度比纯 Python list 快(特别是百万级数据)。
  • 数据可视化支持:可直接对接 Matplotlib、Seaborn 等库。
  • 数据库/文件交互:支持直接读取/写入 CSV、Excel、SQL、JSON、Parquet 等格式,比手动解析更简单。

原生数据结构适合场景

  • 非结构化数据(如嵌套 JSON、树形数据):如果数据不是表格形式,dict 或 list 更灵活。
  • 小规模数据:如果数据量极小,DataFrame 可能显得“杀鸡用牛刀”。
  • 需要低内存开销:list 和 dict 的内存占用通常比 DataFrame 更小(但牺牲了计算速度)。
  • 需要定制化操作:Python 原生结构可能更易控制。

八、相关文章

Pandas读写Excel文件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI手记叨叨

解锁“精神股东”称号!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值