Pandas 从入门到精通:完整数据分析指南

第一部分:Pandas 基础与核心概念

1.1 Pandas 简介与安装

Pandas 是 Python 的核心数据分析库,提供快速、灵活、易用的数据结构,特别适合处理表格数据和时间序列数据。

1.1.1 安装方法:

bash 复制代码
# 基础安装
pip install pandas

# 完整安装(包含可选依赖)
pip install pandas[all]

# 通过conda安装
conda install pandas

# 安装指定版本
pip install pandas==2.1.0

1.1.2 安装验证:

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

print(f"Numpy版本: {np.__version__}")
print(f"Pandas版本: {pd.__version__}")
复制代码
Numpy版本: 2.3.3
Pandas版本: 2.3.3

1.2 核心数据结构:Series 和 DataFrame

1.2.1 Series:一维带标签数组

1.2.1.1 创建Series
  1. 从列表创建
python 复制代码
# 1. 从列表创建
s1 = pd.Series([1, 3, 5, 7, 9])
print("基本Series:")
print(s1)
print(f"索引: {s1.index}")
print(f"值: {s1.values}")
复制代码
基本Series:
0    1
1    3
2    5
3    7
4    9
dtype: int64
索引: RangeIndex(start=0, stop=5, step=1)
值: [1 3 5 7 9]
  1. 指定索引
python 复制代码
# 2. 指定索引
s2 = pd.Series([10, 20, 30, 40], 
               index=['a', 'b', 'c', 'd'])
print("\n带自定义索引的Series:")
print(s2)
复制代码
带自定义索引的Series:
a    10
b    20
c    30
d    40
dtype: int64
  1. 从字典创建
python 复制代码
# 3. 从字典创建
data_dict = {'A': 100, 'B': 200, 'C': 300}
s3 = pd.Series(data_dict)
print("\n从字典创建的Series:")
print(s3)
复制代码
从字典创建的Series:
A    100
B    200
C    300
dtype: int64
  1. 从标量创建
python 复制代码
# 4. 从标量创建
s4 = pd.Series(5.0, index=['x', 'y', 'z'])
print("\n从标量创建的Series:")
print(s4)
复制代码
从标量创建的Series:
x    5.0
y    5.0
z    5.0
dtype: float64
1.2.1.2 Series属性与方法
python 复制代码
# Series属性
print("\n=== Series属性 ===")
print(f"数据类型: {s2.dtype}")
print(f"形状: {s2.shape}")
print(f"大小: {s2.size}")
print(f"索引类型: {type(s2.index)}")
print(f"是否唯一: {s2.is_unique}")
print(f"是否单调递增: {s2.is_monotonic_increasing}")
复制代码
=== Series属性 ===
数据类型: int64
形状: (4,)
大小: 4
索引类型: <class 'pandas.core.indexes.base.Index'>
是否唯一: True
是否单调递增: True
python 复制代码
# Series基本操作
print("\n=== Series操作 ===")
print(f"前2个元素:\n{s2.head(2)}")
print(f"后2个元素:\n{s2.tail(2)}")
print(f"描述性统计:\n{s2.describe()}")
print(f"求和: {s2.sum()}")
print(f"均值: {s2.mean()}")
print(f"标准差: {s2.std()}")
复制代码
=== Series操作 ===
前2个元素:
a    10
b    20
dtype: int64
后2个元素:
c    30
d    40
dtype: int64
描述性统计:
count     4.000000
mean     25.000000
std      12.909944
min      10.000000
25%      17.500000
50%      25.000000
75%      32.500000
max      40.000000
dtype: float64
求和: 100
均值: 25.0
标准差: 12.909944487358056
python 复制代码
# Series索引
print("\n=== Series索引 ===")
print(f"位置索引 s2.iloc[0]: {s2.iloc[0]}")
print(f"标签索引 s2['a']: {s2['a']}")
print(f"切片 s2[1:3]:\n{s2[1:3]}")
print(f"布尔索引 s2[s2 > 20]:\n{s2[s2 > 20]}")
复制代码
=== Series索引 ===
位置索引 s2.iloc[0]: 10
标签索引 s2['a']: 10
切片 s2[1:3]:
b    20
c    30
dtype: int64
布尔索引 s2[s2 > 20]:
c    30
d    40
dtype: int64
python 复制代码
# Series运算
s5 = pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])
s6 = pd.Series([10, 20, 30, 40], index=['a', 'b', 'c', 'd'])

print("\n=== Series运算 ===")
print(f"加法:\n{s5 + s6}")
print(f"乘法1:\n{s5 * 2}")
print(f"乘法2:\n{s5 * s6}")
print(f"广播运算:\n{s5 + 100}")
复制代码
=== Series运算 ===
加法:
a    11
b    22
c    33
d    44
dtype: int64
乘法1:
a    2
b    4
c    6
d    8
dtype: int64
乘法2:
a     10
b     40
c     90
d    160
dtype: int64
广播运算:
a    101
b    102
c    103
d    104
dtype: int64
python 复制代码
# 自动索引对齐
s7 = pd.Series([1, 2, 3], index=['a', 'b', 'c'])
s8 = pd.Series([4, 5, 6], index=['b', 'c', 'd'])
print(f"\n索引对齐加法:\n{s7 + s8}")
复制代码
索引对齐加法:
a    NaN
b    6.0
c    8.0
d    NaN
dtype: float64

1.2.2 DataFrame:二维表格数据结构

1.2.2.1 创建DataFrame
  1. 从字典创建(最常用)
python 复制代码
# 1. 从字典创建(最常用)
data = {
    '姓名': ['张三', '李四', '王五', '赵六'],
    '年龄': [25, 30, 35, 28],
    '城市': ['北京', '上海', '广州', '深圳'],
    '工资': [15000, 20000, 18000, 22000],
    '入职年份': [2019, 2018, 2020, 2017]
}
df = pd.DataFrame(data)
print("基本DataFrame:")
print(df)
复制代码
基本DataFrame:
   姓名  年龄  城市     工资  入职年份
0  张三  25  北京  15000  2019
1  李四  30  上海  20000  2018
2  王五  35  广州  18000  2020
3  赵六  28  深圳  22000  2017
  1. 指定行索引
python 复制代码
# 2. 指定行索引
df_with_index = pd.DataFrame(data, 
                            index=['E001', 'E002', 'E003', 'E004'])
print("带自定义索引的DataFrame:")
print(df_with_index)
复制代码
带自定义索引的DataFrame:
      姓名  年龄  城市     工资  入职年份
E001  张三  25  北京  15000  2019
E002  李四  30  上海  20000  2018
E003  王五  35  广州  18000  2020
E004  赵六  28  深圳  22000  2017
  1. 从列表创建
python 复制代码
# 3. 从列表创建
data_list = [
    ['张三', 25, '北京', 15000, 2019],
    ['李四', 30, '上海', 20000, 2018],
    ['王五', 35, '广州', 18000, 2020],
    ['赵六', 28, '深圳', 22000, 2017]
]
columns = ['姓名', '年龄', '城市', '工资', '入职年份']
df_from_list = pd.DataFrame(data_list, columns=columns)
print("从列表创建的DataFrame:")
print(df_from_list)
复制代码
从列表创建的DataFrame:
   姓名  年龄  城市     工资  入职年份
0  张三  25  北京  15000  2019
1  李四  30  上海  20000  2018
2  王五  35  广州  18000  2020
3  赵六  28  深圳  22000  2017
  1. 从NumPy数组创建
python 复制代码
np_array = np.random.randn(5, 4)
df_from_numpy = pd.DataFrame(np_array, 
                            columns=['A', 'B', 'C', 'D'])
print("从NumPy数组创建的DataFrame:")
print(df_from_numpy)
复制代码
从NumPy数组创建的DataFrame:
          A         B         C         D
0 -1.927079 -0.698070  1.029268  0.430813
1 -0.642815  1.747273  0.738184  0.492974
2 -1.392473 -0.219943  0.868221  0.715244
3 -0.208143  2.142948 -0.029559  0.806000
4 -2.601245 -0.076942 -1.085496  1.108939
  1. 从字典列表创建
python 复制代码
# 5. 从字典列表创建
dict_list = [
    {'姓名': '张三', '年龄': 25, '城市': '北京'},
    {'姓名': '李四', '年龄': 30, '城市': '上海'},
    {'姓名': '王五', '年龄': 35, '城市': '广州'}
]
df_from_dict_list = pd.DataFrame(dict_list)
print("从字典列表创建的DataFrame:")
print(df_from_dict_list)
复制代码
从字典列表创建的DataFrame:
   姓名  年龄  城市
0  张三  25  北京
1  李四  30  上海
2  王五  35  广州
1.2.2.2 DataFrame 基本属性和方法
python 复制代码
# DataFrame属性
print("=== DataFrame属性 ===")
print(f"形状: {df.shape}")
print(f"维度: {df.ndim}")
print(f"大小: {df.size}")
print(f"列名: {df.columns.tolist()}")
print(f"索引: {df.index}")
print(f"数据类型:\n{df.dtypes}")
print(f"内存使用:\n{df.memory_usage()}")
复制代码
=== DataFrame属性 ===
形状: (4, 5)
维度: 2
大小: 20
列名: ['姓名', '年龄', '城市', '工资', '入职年份']
索引: RangeIndex(start=0, stop=4, step=1)
数据类型:
姓名      object
年龄       int64
城市      object
工资       int64
入职年份     int64
dtype: object
内存使用:
Index    132
姓名        32
年龄        32
城市        32
工资        32
入职年份      32
dtype: int64
python 复制代码
# DataFrame信息概览
print("=== 数据概览 ===")
print("前3行:")
print(df.head(3))
print("\n后2行:")
print(df.tail(2))
print("\n基本信息:")
df.info()
print("\n描述性统计:")
print(df.describe())
print("\n数值列描述性统计:")
print(df.describe(include=[np.number]))
print("\n非数值列描述性统计:")
print(df.describe(exclude=[np.number]))
复制代码
=== 数据概览 ===
前3行:
   姓名  年龄  城市     工资  入职年份
0  张三  25  北京  15000  2019
1  李四  30  上海  20000  2018
2  王五  35  广州  18000  2020

后2行:
   姓名  年龄  城市     工资  入职年份
2  王五  35  广州  18000  2020
3  赵六  28  深圳  22000  2017

基本信息:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 5 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 
 4   入职年份    4 non-null      int64 
dtypes: int64(3), object(2)
memory usage: 292.0+ bytes

描述性统计:
              年龄            工资         入职年份
count   4.000000      4.000000     4.000000
mean   29.500000  18750.000000  2018.500000
std     4.203173   2986.078811     1.290994
min    25.000000  15000.000000  2017.000000
25%    27.250000  17250.000000  2017.750000
50%    29.000000  19000.000000  2018.500000
75%    31.250000  20500.000000  2019.250000
max    35.000000  22000.000000  2020.000000

数值列描述性统计:
              年龄            工资         入职年份
count   4.000000      4.000000     4.000000
mean   29.500000  18750.000000  2018.500000
std     4.203173   2986.078811     1.290994
min    25.000000  15000.000000  2017.000000
25%    27.250000  17250.000000  2017.750000
50%    29.000000  19000.000000  2018.500000
75%    31.250000  20500.000000  2019.250000
max    35.000000  22000.000000  2020.000000

非数值列描述性统计:
        姓名  城市
count    4   4
unique   4   4
top     张三  北京
freq     1   1

第二部分:数据查看与选择

2.1 数据查看方法

python 复制代码
# 创建示例DataFrame
np.random.seed(42)
data = {
    'ID': [f'E{100+i}' for i in range(10)],
    '姓名': ['张三', '李四', '王五', '赵六', '钱七', 
           '孙八', '周九', '吴十', '郑一', '王二'],
    '年龄': np.random.randint(20, 50, 10),
    '部门': ['技术部', '市场部', '技术部', '人事部', '市场部',
            '技术部', '人事部', '市场部', '技术部', '人事部'],
    '工资': np.random.randint(8000, 25000, 10),
    '奖金': np.random.randint(1000, 5000, 10),
    '入职日期': pd.date_range('2018-01-01', periods=10, freq='ME')
}
df = pd.DataFrame(data)
df['总薪资'] = df['工资'] + df['奖金']
df['绩效'] = np.random.choice(['A', 'B', 'C', 'D'], 10)

print("完整DataFrame:")
print(df)
复制代码
完整DataFrame:
     ID  姓名  年龄   部门     工资    奖金       入职日期    总薪资 绩效
0  E100  张三  26  技术部  24850  1955 2018-01-31  26805  C
1  E101  李四  39  市场部  12426  3324 2018-02-28  15750  C
2  E102  王五  48  技术部  22423  2184 2018-03-31  24607  C
3  E103  赵六  34  人事部  19363  1459 2018-04-30  20822  B
4  E104  钱七  30  市场部  24023  4385 2018-05-31  28408  D
5  E105  孙八  27  技术部  16322  1021 2018-06-30  17343  D
6  E106  周九  48  人事部   9685  3300 2018-07-31  12985  D
7  E107  吴十  40  市场部   8769  1747 2018-08-31  10516  D
8  E108  郑一  26  技术部  10433  3904 2018-09-30  14337  C
9  E109  王二  45  人事部  13311  4632 2018-10-31  17943  B
python 复制代码
# 查看数据
print("=== 数据查看方法 ===")
print("1. 查看前N行:")
print(df.head(3))

print("\n2. 查看后N行:")
print(df.tail(3))

print("\n3. 随机查看N行:")
print(df.sample(3))

print("\n4. 查看特定行:")
print(df.iloc[[0, 3, 5]])  # 查看第0,3,5行
复制代码
=== 数据查看方法 ===
1. 查看前N行:
     ID  姓名  年龄   部门     工资    奖金       入职日期    总薪资 绩效
0  E100  张三  26  技术部  24850  1955 2018-01-31  26805  C
1  E101  李四  39  市场部  12426  3324 2018-02-28  15750  C
2  E102  王五  48  技术部  22423  2184 2018-03-31  24607  C

2. 查看后N行:
     ID  姓名  年龄   部门     工资    奖金       入职日期    总薪资 绩效
7  E107  吴十  40  市场部   8769  1747 2018-08-31  10516  D
8  E108  郑一  26  技术部  10433  3904 2018-09-30  14337  C
9  E109  王二  45  人事部  13311  4632 2018-10-31  17943  B

3. 随机查看N行:
     ID  姓名  年龄   部门     工资    奖金       入职日期    总薪资 绩效
1  E101  李四  39  市场部  12426  3324 2018-02-28  15750  C
8  E108  郑一  26  技术部  10433  3904 2018-09-30  14337  C
7  E107  吴十  40  市场部   8769  1747 2018-08-31  10516  D

4. 查看特定行:
     ID  姓名  年龄   部门     工资    奖金       入职日期    总薪资 绩效
0  E100  张三  26  技术部  24850  1955 2018-01-31  26805  C
3  E103  赵六  34  人事部  19363  1459 2018-04-30  20822  B
5  E105  孙八  27  技术部  16322  1021 2018-06-30  17343  D
python 复制代码
print("\n5. 查看列:")
print("所有列:", df.columns.tolist())
print("特定几列:")
print(df[['姓名', '部门', '工资']])
复制代码
5. 查看列:
所有列: ['ID', '姓名', '年龄', '部门', '工资', '奖金', '入职日期', '总薪资', '绩效']
特定几列:
   姓名   部门     工资
0  张三  技术部  24850
1  李四  市场部  12426
2  王五  技术部  22423
3  赵六  人事部  19363
4  钱七  市场部  24023
5  孙八  技术部  16322
6  周九  人事部   9685
7  吴十  市场部   8769
8  郑一  技术部  10433
9  王二  人事部  13311
python 复制代码
print("\n6. 数据信息:")
df.info()
复制代码
6. 数据信息:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10 entries, 0 to 9
Data columns (total 9 columns):
 #   Column  Non-Null Count  Dtype         
---  ------  --------------  -----         
 0   ID      10 non-null     object        
 1   姓名      10 non-null     object        
 2   年龄      10 non-null     int32         
 3   部门      10 non-null     object        
 4   工资      10 non-null     int32         
 5   奖金      10 non-null     int32         
 6   入职日期    10 non-null     datetime64[ns]
 7   总薪资     10 non-null     int32         
 8   绩效      10 non-null     object        
dtypes: datetime64[ns](1), int32(4), object(4)
memory usage: 692.0+ bytes
python 复制代码
print("\n7. 统计摘要:")
df.describe(include='all')
复制代码
7. 统计摘要:

| | ID | 姓名 | 年龄 | 部门 | 工资 | 奖金 | 入职日期 | 总薪资 | 绩效 |
| count | 10 | 10 | 10.00000 | 10 | 10.000000 | 10.000000 | 10 | 10.000000 | 10 |
| unique | 10 | 10 | NaN | 3 | NaN | NaN | NaN | NaN | 3 |
| top | E100 | 张三 | NaN | 技术部 | NaN | NaN | NaN | NaN | C |
| freq | 1 | 1 | NaN | 4 | NaN | NaN | NaN | NaN | 4 |
| mean | NaN | NaN | 36.30000 | NaN | 16160.500000 | 2791.100000 | 2018-06-15 09:36:00 | 18951.600000 | NaN |
| min | NaN | NaN | 26.00000 | NaN | 8769.000000 | 1021.000000 | 2018-01-31 00:00:00 | 10516.000000 | NaN |
| 25% | NaN | NaN | 27.75000 | NaN | 10931.250000 | 1799.000000 | 2018-04-07 12:00:00 | 14690.250000 | NaN |
| 50% | NaN | NaN | 36.50000 | NaN | 14816.500000 | 2742.000000 | 2018-06-15 00:00:00 | 17643.000000 | NaN |
| 75% | NaN | NaN | 43.75000 | NaN | 21658.000000 | 3759.000000 | 2018-08-23 06:00:00 | 23660.750000 | NaN |
| max | NaN | NaN | 48.00000 | NaN | 24850.000000 | 4632.000000 | 2018-10-31 00:00:00 | 28408.000000 | NaN |

std NaN NaN 8.90755 NaN 6130.652317 1281.338749 NaN 6041.436956 NaN
python 复制代码
print("\n8. 唯一值统计:")
for col in ['部门', '绩效']:
    print(f"{col}的唯一值: {df[col].unique()}")
    print(f"{col}的值计数:\n{df[col].value_counts()}")
    print()
复制代码
8. 唯一值统计:
部门的唯一值: ['技术部' '市场部' '人事部']
部门的值计数:
部门
技术部    4
市场部    3
人事部    3
Name: count, dtype: int64

绩效的唯一值: ['C' 'B' 'D']
绩效的值计数:
绩效
C    4
D    4
B    2
Name: count, dtype: int64

2.2 数据选择与索引

2.2.1 列选择

python 复制代码
# 列选择
print("=== 列选择 ===")
print("1. 单列选择(返回Series):")
names = df['姓名']
print(type(names))
print(names)

print("\n2. 多列选择(返回DataFrame):")
subset = df[['姓名', '部门', '工资']]
print(type(subset))
print(subset)

print("\n3. 点号表示法(仅当列名是有效的Python标识符):")
ages = df.年龄
print(ages)
复制代码
=== 列选择 ===
1. 单列选择(返回Series):
<class 'pandas.core.series.Series'>
0    张三
1    李四
2    王五
3    赵六
4    钱七
5    孙八
6    周九
7    吴十
8    郑一
9    王二
Name: 姓名, dtype: object

2. 多列选择(返回DataFrame):
<class 'pandas.core.frame.DataFrame'>
   姓名   部门     工资
0  张三  技术部  24850
1  李四  市场部  12426
2  王五  技术部  22423
3  赵六  人事部  19363
4  钱七  市场部  24023
5  孙八  技术部  16322
6  周九  人事部   9685
7  吴十  市场部   8769
8  郑一  技术部  10433
9  王二  人事部  13311

3. 点号表示法(仅当列名是有效的Python标识符):
0    26
1    39
2    48
3    34
4    30
5    27
6    48
7    40
8    26
9    45
Name: 年龄, dtype: int32

2.2.2 行选择

python 复制代码
# 行选择
print("\n=== 行选择 ===")
print("1. 通过索引标签选择:")
print(df.loc[0])  # 选择第一行
print(df.loc[[0, 2, 4]])  # 选择多行

print("\n2. 通过位置选择:")
print(df.iloc[0])  # 选择第一行
print(df.iloc[0:3])  # 选择前3行
print(df.iloc[[0, 2, 4]])  # 选择第0,2,4行

print("\n3. 条件选择:")
# 单条件
tech_dept = df[df['部门'] == '技术部']
print("技术部员工:")
print(tech_dept)

# 多条件
high_salary_tech = df[(df['部门'] == '技术部') & (df['工资'] > 15000)]
print("\n技术部高薪员工:")
print(high_salary_tech)

# 复杂条件
condition = (df['年龄'] > 30) | (df['总薪资'] > 20000)
result = df[condition]
print("\n年龄>30或总薪资>20000的员工:")
print(result)

# 使用query方法
result_query = df.query('年龄 > 30 and 工资 > 15000')
print("\n使用query方法:")
print(result_query)
复制代码
=== 行选择 ===
1. 通过索引标签选择:
ID                     E100
姓名                       张三
年龄                       26
部门                      技术部
工资                    24850
奖金                     1955
入职日期    2018-01-31 00:00:00
总薪资                   26805
绩效                        C
Name: 0, dtype: object
     ID  姓名  年龄   部门     工资    奖金       入职日期    总薪资 绩效
0  E100  张三  26  技术部  24850  1955 2018-01-31  26805  C
2  E102  王五  48  技术部  22423  2184 2018-03-31  24607  C
4  E104  钱七  30  市场部  24023  4385 2018-05-31  28408  D

2. 通过位置选择:
ID                     E100
姓名                       张三
年龄                       26
部门                      技术部
工资                    24850
奖金                     1955
入职日期    2018-01-31 00:00:00
总薪资                   26805
绩效                        C
Name: 0, dtype: object
     ID  姓名  年龄   部门     工资    奖金       入职日期    总薪资 绩效
0  E100  张三  26  技术部  24850  1955 2018-01-31  26805  C
1  E101  李四  39  市场部  12426  3324 2018-02-28  15750  C
2  E102  王五  48  技术部  22423  2184 2018-03-31  24607  C
     ID  姓名  年龄   部门     工资    奖金       入职日期    总薪资 绩效
0  E100  张三  26  技术部  24850  1955 2018-01-31  26805  C
2  E102  王五  48  技术部  22423  2184 2018-03-31  24607  C
4  E104  钱七  30  市场部  24023  4385 2018-05-31  28408  D

3. 条件选择:
技术部员工:
     ID  姓名  年龄   部门     工资    奖金       入职日期    总薪资 绩效
0  E100  张三  26  技术部  24850  1955 2018-01-31  26805  C
2  E102  王五  48  技术部  22423  2184 2018-03-31  24607  C
5  E105  孙八  27  技术部  16322  1021 2018-06-30  17343  D
8  E108  郑一  26  技术部  10433  3904 2018-09-30  14337  C

技术部高薪员工:
     ID  姓名  年龄   部门     工资    奖金       入职日期    总薪资 绩效
0  E100  张三  26  技术部  24850  1955 2018-01-31  26805  C
2  E102  王五  48  技术部  22423  2184 2018-03-31  24607  C
5  E105  孙八  27  技术部  16322  1021 2018-06-30  17343  D

年龄>30或总薪资>20000的员工:
     ID  姓名  年龄   部门     工资    奖金       入职日期    总薪资 绩效
0  E100  张三  26  技术部  24850  1955 2018-01-31  26805  C
1  E101  李四  39  市场部  12426  3324 2018-02-28  15750  C
2  E102  王五  48  技术部  22423  2184 2018-03-31  24607  C
3  E103  赵六  34  人事部  19363  1459 2018-04-30  20822  B
4  E104  钱七  30  市场部  24023  4385 2018-05-31  28408  D
6  E106  周九  48  人事部   9685  3300 2018-07-31  12985  D
7  E107  吴十  40  市场部   8769  1747 2018-08-31  10516  D
9  E109  王二  45  人事部  13311  4632 2018-10-31  17943  B

使用query方法:
     ID  姓名  年龄   部门     工资    奖金       入职日期    总薪资 绩效
2  E102  王五  48  技术部  22423  2184 2018-03-31  24607  C
3  E103  赵六  34  人事部  19363  1459 2018-04-30  20822  B

2.3 高级索引技巧

2.3.1 使用loc进行高级选择

python 复制代码
# 使用loc进行高级选择
print("=== 使用loc进行高级选择 ===")
# 选择特定行和列
print("选择特定行和列:")
print(df.loc[[0, 2, 4], ['姓名', '部门', '工资']])

# 使用切片
print("\n使用行切片和列选择:")
print(df.loc[2:5, '姓名':'工资'])

# 使用条件
print("\n使用条件选择:")
print(df.loc[df['年龄'] > 30, ['姓名', '年龄', '部门']])
复制代码
=== 使用loc进行高级选择 ===
选择特定行和列:
   姓名   部门     工资
0  张三  技术部  24850
2  王五  技术部  22423
4  钱七  市场部  24023

使用行切片和列选择:
   姓名  年龄   部门     工资
2  王五  48  技术部  22423
3  赵六  34  人事部  19363
4  钱七  30  市场部  24023
5  孙八  27  技术部  16322

使用条件选择:
   姓名  年龄   部门
1  李四  39  市场部
2  王五  48  技术部
3  赵六  34  人事部
6  周九  48  人事部
7  吴十  40  市场部
9  王二  45  人事部

2.3.2 使用iloc进行位置选择

python 复制代码
# 使用iloc进行位置选择
print("\n=== 使用iloc进行位置选择 ===")
print("选择特定位置:")
print(df.iloc[0, 1])  # 第0行第1列(单个元素数据值)
print(df.iloc[0:3, 0:3])  # 前3行前3列
print(df.iloc[[0, 2, 4], [1, 3, 5]])  # 不连续行列
复制代码
=== 使用iloc进行位置选择 ===
选择特定位置:
张三
     ID  姓名  年龄
0  E100  张三  26
1  E101  李四  39
2  E102  王五  48
   姓名   部门    奖金
0  张三  技术部  1955
2  王五  技术部  2184
4  钱七  市场部  4385

2.3.3 使用at和iat快速访问

快速标量访问

python 复制代码
# 使用at和iat快速访问
print("\n=== 快速标量访问 ===")
print("使用at(标签访问):")
print(df.at[0, '姓名'])  # 比df.loc[0, '姓名']更快

print("\n使用iat(位置访问):")
print(df.iat[0, 1])  # 比df.iloc[0, 1]更快
复制代码
=== 快速标量访问 ===
使用at(标签访问):
张三

使用iat(位置访问):
张三

2.3.4 布尔索引

python 复制代码
# 布尔索引
print("\n=== 布尔索引 ===")
# 创建布尔序列
is_tech = df['部门'] == '技术部'
high_perf = df['绩效'].isin(['A', 'B'])
age_over_30 = df['年龄'] > 30

# 组合条件
combined = df[is_tech & high_perf & age_over_30]
print("技术部、高绩效、年龄>30的员工:")
print(combined)

# 使用between
print("\n使用between:")
age_range = df[df['年龄'].between(25, 35)]
print("年龄在25-35之间的员工:")
print(age_range)

# 使用str访问器
print("\n使用str访问器:")
name_start_wang = df[df['姓名'].str.startswith('王')]
print("姓王的员工:")
print(name_start_wang)
复制代码
=== 布尔索引 ===
技术部、高绩效、年龄>30的员工:
Empty DataFrame
Columns: [ID, 姓名, 年龄, 部门, 工资, 奖金, 入职日期, 总薪资, 绩效]
Index: []

使用between:
年龄在25-35之间的员工:
     ID  姓名  年龄   部门     工资    奖金       入职日期    总薪资 绩效
0  E100  张三  26  技术部  24850  1955 2018-01-31  26805  C
3  E103  赵六  34  人事部  19363  1459 2018-04-30  20822  B
4  E104  钱七  30  市场部  24023  4385 2018-05-31  28408  D
5  E105  孙八  27  技术部  16322  1021 2018-06-30  17343  D
8  E108  郑一  26  技术部  10433  3904 2018-09-30  14337  C

使用str访问器:
姓王的员工:
     ID  姓名  年龄   部门     工资    奖金       入职日期    总薪资 绩效
2  E102  王五  48  技术部  22423  2184 2018-03-31  24607  C
9  E109  王二  45  人事部  13311  4632 2018-10-31  17943  B

第三部分:数据处理与清洗

3.1 缺失值处理

python 复制代码
# 创建包含缺失值的数据
data_with_na = {
    '姓名': ['张三', '李四', '王五', '赵六', '钱七'],
    '年龄': [25, np.nan, 35, 28, np.nan],
    '工资': [15000, 20000, np.nan, 22000, 18000],
    '部门': ['技术部', '市场部', None, '人事部', '技术部'],
    '奖金': [3000, np.nan, 2000, np.nan, 2500]
}
df_na = pd.DataFrame(data_with_na)
print("包含缺失值的数据:")
print(df_na)
复制代码
包含缺失值的数据:
   姓名    年龄       工资    部门      奖金
0  张三  25.0  15000.0   技术部  3000.0
1  李四   NaN  20000.0   市场部     NaN
2  王五  35.0      NaN  None  2000.0
3  赵六  28.0  22000.0   人事部     NaN
4  钱七   NaN  18000.0   技术部  2500.0

3.1.1 检测缺失值

python 复制代码
# 检测缺失值
print("=== 缺失值检测 ===")
print("是否存在缺失值:")
print(df_na.isna().any())

print("\n每列缺失值数量:")
print(df_na.isna().sum())

print("\n每行缺失值数量:")
print(df_na.isna().sum(axis=1))

print("\n缺失值比例:")
print(df_na.isna().mean())
复制代码
=== 缺失值检测 ===
是否存在缺失值:
姓名    False
年龄     True
工资     True
部门     True
奖金     True
dtype: bool

每列缺失值数量:
姓名    0
年龄    2
工资    1
部门    1
奖金    2
dtype: int64

每行缺失值数量:
0    0
1    2
2    2
3    1
4    1
dtype: int64

缺失值比例:
姓名    0.0
年龄    0.4
工资    0.2
部门    0.2
奖金    0.4
dtype: float64

3.1.2 缺失值处理

3.1.2.1 删除缺失值
  1. 删除缺失行
python 复制代码
# 处理缺失值
print("\n=== 缺失值处理 ===")
# 1. 删除缺失值
print("1. 删除缺失行:")
df_dropna_rows = df_na.dropna()
print(df_dropna_rows)
复制代码
=== 缺失值处理 ===
1. 删除缺失行:
   姓名    年龄       工资   部门      奖金
0  张三  25.0  15000.0  技术部  3000.0
  1. 删除缺失列
python 复制代码
print("\n2. 删除缺失列:")
df_dropna_cols = df_na.dropna(axis=1)
print(df_dropna_cols)
复制代码
2. 删除缺失列:
   姓名
0  张三
1  李四
2  王五
3  赵六
4  钱七
  1. 删除全为缺失值的行
python 复制代码
print("\n3. 删除全为缺失值的行:")
df_dropna_all = df_na.dropna(how='all')
print(df_dropna_all)
复制代码
3. 删除全为缺失值的行:
   姓名    年龄       工资    部门      奖金
0  张三  25.0  15000.0   技术部  3000.0
1  李四   NaN  20000.0   市场部     NaN
2  王五  35.0      NaN  None  2000.0
3  赵六  28.0  22000.0   人事部     NaN
4  钱七   NaN  18000.0   技术部  2500.0
  1. 删除特定列有缺失值的行
python 复制代码
print("\n4. 删除特定列有缺失值的行:")
df_dropna_subset = df_na.dropna(subset=['年龄', '工资'])
print(df_dropna_subset)
复制代码
4. 删除特定列有缺失值的行:
   姓名    年龄       工资   部门      奖金
0  张三  25.0  15000.0  技术部  3000.0
3  赵六  28.0  22000.0  人事部     NaN
3.1.2.2 填充缺失值
  1. 用固定值填充
python 复制代码
# 用固定值填充
df_fill_value = df_na.fillna(0)
print("用0填充:")
print(df_fill_value)
复制代码
用0填充:
   姓名    年龄       工资   部门      奖金
0  张三  25.0  15000.0  技术部  3000.0
1  李四   0.0  20000.0  市场部     0.0
2  王五  35.0      0.0    0  2000.0
3  赵六  28.0  22000.0  人事部     0.0
4  钱七   0.0  18000.0  技术部  2500.0
  1. 用前值填充
python 复制代码
# 用前向填充
df_ffill = df_na.ffill()
print("\n前向填充:")
print(df_ffill)
复制代码
前向填充:
   姓名    年龄       工资   部门      奖金
0  张三  25.0  15000.0  技术部  3000.0
1  李四  25.0  20000.0  市场部  3000.0
2  王五  35.0  20000.0  市场部  2000.0
3  赵六  28.0  22000.0  人事部  2000.0
4  钱七  28.0  18000.0  技术部  2500.0
  1. 用后值填充
python 复制代码
# 用后向填充
df_bfill = df_na.bfill()
print("\n后向填充:")
print(df_bfill)
复制代码
后向填充:
   姓名    年龄       工资   部门      奖金
0  张三  25.0  15000.0  技术部  3000.0
1  李四  35.0  20000.0  市场部  2000.0
2  王五  35.0  22000.0  人事部  2000.0
3  赵六  28.0  22000.0  人事部  2500.0
4  钱七   NaN  18000.0  技术部  2500.0
  1. 用均值填充
python 复制代码
# 用均值填充
df_fill_mean = df_na.copy()
df_fill_mean['年龄'] = df_fill_mean['年龄'].fillna(df_fill_mean['年龄'].mean())
df_fill_mean['工资'] = df_fill_mean['工资'].fillna(df_fill_mean['工资'].mean())
print("\n用均值填充数值列:")
print(df_fill_mean)
复制代码
用均值填充数值列:
   姓名         年龄       工资    部门      奖金
0  张三  25.000000  15000.0   技术部  3000.0
1  李四  29.333333  20000.0   市场部     NaN
2  王五  35.000000  18750.0  None  2000.0
3  赵六  28.000000  22000.0   人事部     NaN
4  钱七  29.333333  18000.0   技术部  2500.0
  1. 用众数填充
python 复制代码
# 用众数填充
mode_dept = df_na['部门'].mode()[0]
df_fill_mode = df_na.copy()
df_fill_mode['部门'] = df_fill_mode['部门'].fillna(mode_dept)
print(f"\n用众数'{mode_dept}'填充部门列:")
print(df_fill_mode)
复制代码
用众数'技术部'填充部门列:
   姓名    年龄       工资   部门      奖金
0  张三  25.0  15000.0  技术部  3000.0
1  李四   NaN  20000.0  市场部     NaN
2  王五  35.0      NaN  技术部  2000.0
3  赵六  28.0  22000.0  人事部     NaN
4  钱七   NaN  18000.0  技术部  2500.0
3.1.2.3 插值
python 复制代码
print("\n插值法:")
df_interp = df_na.copy()
df_interp['年龄'] = df_interp['年龄'].interpolate()
print("线性插值:")
print(df_interp)
复制代码
插值法:
线性插值:
   姓名    年龄       工资    部门      奖金
0  张三  25.0  15000.0   技术部  3000.0
1  李四  30.0  20000.0   市场部     NaN
2  王五  35.0      NaN  None  2000.0
3  赵六  28.0  22000.0   人事部     NaN
4  钱七  28.0  18000.0   技术部  2500.0
3.1.2.4 使用KNN填充
python 复制代码
try:
    from sklearn.impute import KNNImputer
    imputer = KNNImputer(n_neighbors=2)
    df_knn = pd.DataFrame(imputer.fit_transform(df_na.select_dtypes(include=[np.number])),
                         columns=df_na.select_dtypes(include=[np.number]).columns)
    print("\nKNN填充:")
    print(df_knn)
except ImportError:
    print("\n需要scikit-learn进行KNN填充")
复制代码
KNN填充:
     年龄       工资      奖金
0  25.0  15000.0  3000.0
1  26.5  20000.0  2750.0
2  35.0  20000.0  2000.0
3  28.0  22000.0  2250.0
4  30.0  18000.0  2500.0

3.2 数据类型转换

python 复制代码
# 数据类型转换
print("=== 数据类型转换 ===")
print("原始数据类型:")
print(df_na.dtypes)

# 转换数据类型
df_convert = df_na.copy()
df_convert['年龄'] = df_convert['年龄'].astype('float32')
df_convert['工资'] = pd.to_numeric(df_convert['工资'], errors='coerce')

print("\n转换后数据类型:")
print(df_convert.dtypes)

# 使用分类数据类型
df_convert['部门'] = df_convert['部门'].astype('category')
print("\n部门列的分类信息:")
print(df_convert['部门'].cat.categories)
print("内存使用对比:")
print(f"原内存: {df_na['部门'].memory_usage(deep=True)} bytes")
print(f"分类内存: {df_convert['部门'].memory_usage(deep=True)} bytes")

# 日期时间转换
df_convert['入职日期'] = pd.to_datetime('2023-01-01')
print("\n添加日期列:")
print(df_convert.dtypes)
复制代码
=== 数据类型转换 ===
原始数据类型:
姓名     object
年龄    float64
工资    float64
部门     object
奖金    float64
dtype: object

转换后数据类型:
姓名     object
年龄    float32
工资    float64
部门     object
奖金    float64
dtype: object

部门列的分类信息:
Index(['人事部', '市场部', '技术部'], dtype='object')
内存使用对比:
原内存: 444 bytes
分类内存: 461 bytes

添加日期列:
姓名              object
年龄             float32
工资             float64
部门            category
奖金             float64
入职日期    datetime64[ns]
dtype: object

3.3 数据去重

python 复制代码
# 创建重复数据
duplicate_data = {
    '姓名': ['张三', '李四', '张三', '王五', '李四', '赵六'],
    '年龄': [25, 30, 25, 35, 30, 28],
    '城市': ['北京', '上海', '北京', '广州', '上海', '深圳']
}
df_dup = pd.DataFrame(duplicate_data)
print("包含重复值的数据:")
print(df_dup)
复制代码
包含重复值的数据:
   姓名  年龄  城市
0  张三  25  北京
1  李四  30  上海
2  张三  25  北京
3  王五  35  广州
4  李四  30  上海
5  赵六  28  深圳
python 复制代码
# 检测重复值
print("检测重复行:")
# 所有列都一样判定为重复行
print(df_dup.duplicated())

print("\n检测特定列重复:")
print(df_dup.duplicated(subset=['姓名']))
复制代码
检测重复行:
0    False
1    False
2     True
3    False
4     True
5    False
dtype: bool

检测特定列重复:
0    False
1    False
2     True
3    False
4     True
5    False
dtype: bool
python 复制代码
# 查看重复的数据
df_dup[df_dup.duplicated()]

| | 姓名 | 年龄 | 城市 |
| 2 | 张三 | 25 | 北京 |

4 李四 30 上海
python 复制代码
# 删除重复值
print("\n删除所有重复行:")
df_no_dup = df_dup.drop_duplicates()
print(df_no_dup)
复制代码
删除所有重复行:
   姓名  年龄  城市
0  张三  25  北京
1  李四  30  上海
3  王五  35  广州
5  赵六  28  深圳
python 复制代码
print("\n删除特定列重复(保留第一个):")
df_no_dup_name = df_dup.drop_duplicates(subset=['姓名'])
print(df_no_dup_name)
复制代码
删除特定列重复(保留第一个):
   姓名  年龄  城市
0  张三  25  北京
1  李四  30  上海
3  王五  35  广州
5  赵六  28  深圳
python 复制代码
print("\n删除特定列重复(保留最后一个):")
df_no_dup_name_last = df_dup.drop_duplicates(subset=['姓名'], keep='last')
print(df_no_dup_name_last)
复制代码
删除特定列重复(保留最后一个):
   姓名  年龄  城市
2  张三  25  北京
3  王五  35  广州
4  李四  30  上海
5  赵六  28  深圳
python 复制代码
print("\n删除所有重复(不保留任何重复):")
df_no_dup_all = df_dup.drop_duplicates(keep=False)
print(df_no_dup_all)
复制代码
删除所有重复(不保留任何重复):
   姓名  年龄  城市
3  王五  35  广州
5  赵六  28  深圳

3.4 数据转换

python 复制代码
# 创建示例数据
df_trans = pd.DataFrame({
    '订单号': ['ORD001', 'ORD002', 'ORD003', 'ORD004'],
    '金额': [1500.5, 2800.0, 3200.75, 980.25],
    '日期': ['2023-01-15', '2023-02-20', '2023-01-15', '2023-03-10'],
    '产品': ['A', 'B', 'A', 'C']
})

print("原始数据:")
print(df_trans)
复制代码
原始数据:
      订单号       金额          日期 产品
0  ORD001  1500.50  2023-01-15  A
1  ORD002  2800.00  2023-02-20  B
2  ORD003  3200.75  2023-01-15  A
3  ORD004   980.25  2023-03-10  C

3.4.1 重命名列

python 复制代码
# 重命名列
print("=== 重命名列 ===")
df_renamed = df_trans.rename(columns={
    '订单号': 'order_id',
    '金额': 'amount',
    '日期': 'date',
    '产品': 'product'
})
print("重命名后:")
print(df_renamed)
复制代码
=== 重命名列 ===
重命名后:
  order_id   amount        date product
0   ORD001  1500.50  2023-01-15       A
1   ORD002  2800.00  2023-02-20       B
2   ORD003  3200.75  2023-01-15       A
3   ORD004   980.25  2023-03-10       C

3.4.2 重命名索引

python 复制代码
# 重命名索引
df_renamed_idx = df_trans.rename(index=lambda x: f'row_{x}')
print("重命名索引后:")
print(df_renamed_idx)
复制代码
重命名索引后:
          订单号       金额          日期 产品
row_0  ORD001  1500.50  2023-01-15  A
row_1  ORD002  2800.00  2023-02-20  B
row_2  ORD003  3200.75  2023-01-15  A
row_3  ORD004   980.25  2023-03-10  C

3.4.3 重置索引

python 复制代码
# 重置索引
print("=== 重置索引 ===")
df_reset = df_trans.reset_index()
print("重置索引(保留原索引):")
print(df_reset)
复制代码
=== 重置索引 ===
重置索引(保留原索引):
   index     订单号       金额          日期 产品
0      0  ORD001  1500.50  2023-01-15  A
1      1  ORD002  2800.00  2023-02-20  B
2      2  ORD003  3200.75  2023-01-15  A
3      3  ORD004   980.25  2023-03-10  C
python 复制代码
df_reset_drop = df_trans.reset_index(drop=True)
print("\n重置索引(删除原索引):")
print(df_reset_drop)
复制代码
重置索引(删除原索引):
      订单号       金额          日期 产品
0  ORD001  1500.50  2023-01-15  A
1  ORD002  2800.00  2023-02-20  B
2  ORD003  3200.75  2023-01-15  A
3  ORD004   980.25  2023-03-10  C

3.4.4 设置索引

python 复制代码
# 设置索引
print("=== 设置索引 ===")
df_set_index = df_trans.set_index('订单号')
print("设置'订单号'为索引:")
print(df_set_index)
复制代码
=== 设置索引 ===
设置'订单号'为索引:
             金额          日期 产品
订单号                           
ORD001  1500.50  2023-01-15  A
ORD002  2800.00  2023-02-20  B
ORD003  3200.75  2023-01-15  A
ORD004   980.25  2023-03-10  C

3.4.5 添加列

python 复制代码
# 添加列
print("=== 添加列 ===")
df_trans['折扣'] = 0.1
df_trans['实际金额'] = df_trans['金额'] * (1 - df_trans['折扣'])
print("添加折扣和实际金额列:")
print(df_trans)
复制代码
=== 添加列 ===
添加折扣和实际金额列:
      订单号       金额          日期 产品   折扣      实际金额
0  ORD001  1500.50  2023-01-15  A  0.1  1350.450
1  ORD002  2800.00  2023-02-20  B  0.1  2520.000
2  ORD003  3200.75  2023-01-15  A  0.1  2880.675
3  ORD004   980.25  2023-03-10  C  0.1   882.225

3.4.6 删除列

python 复制代码
# 删除列
print("=== 删除列 ===")
df_dropped = df_trans.drop(columns=['折扣'])
print("删除折扣列:")
print(df_dropped)
复制代码
=== 删除列 ===
删除折扣列:
      订单号       金额          日期 产品      实际金额
0  ORD001  1500.50  2023-01-15  A  1350.450
1  ORD002  2800.00  2023-02-20  B  2520.000
2  ORD003  3200.75  2023-01-15  A  2880.675
3  ORD004   980.25  2023-03-10  C   882.225

3.4.7 修改值

python 复制代码
# 修改值
print("=== 修改值 ===")
df_modified = df_trans.copy()
df_modified.loc[df_modified['产品'] == 'A', '金额'] *= 1.1
print("产品A的金额增加10%:")
print(df_modified)
复制代码
=== 修改值 ===
产品A的金额增加10%:
      订单号        金额          日期 产品   折扣      实际金额
0  ORD001  1650.550  2023-01-15  A  0.1  1350.450
1  ORD002  2800.000  2023-02-20  B  0.1  2520.000
2  ORD003  3520.825  2023-01-15  A  0.1  2880.675
3  ORD004   980.250  2023-03-10  C  0.1   882.225

3.4.8 应用函数

python 复制代码
# 应用函数
print("=== 应用函数 ===")
# 对单列应用函数
df_trans['金额_千元'] = df_trans['金额'].apply(lambda x: f'{x/1000:.2f}K')
print("金额转换为千元:")
print(df_trans[['金额', '金额_千元']])
复制代码
=== 应用函数 ===
金额转换为千元:
        金额  金额_千元
0  1500.50  1.50K
1  2800.00  2.80K
2  3200.75  3.20K
3   980.25  0.98K
python 复制代码
# 对多列应用函数
df_trans['大额订单'] = df_trans.apply(
    lambda row: '是' if row['金额'] > 2000 else '否', axis=1
)
print("\n标记大额订单:")
print(df_trans[['订单号', '金额', '大额订单']])
复制代码
标记大额订单:
      订单号       金额 大额订单
0  ORD001  1500.50    否
1  ORD002  2800.00    是
2  ORD003  3200.75    是
3  ORD004   980.25    否

3.4.9 使用向量化操作

python 复制代码
# 使用向量化操作
df_trans['税率'] = 0.13
df_trans['税额'] = df_trans['金额'] * df_trans['税率']
df_trans['税后金额'] = df_trans['金额'] + df_trans['税额']
print("\n税后金额计算:")
print(df_trans[['订单号', '金额', '税额', '税后金额']])
复制代码
税后金额计算:
      订单号       金额        税额       税后金额
0  ORD001  1500.50  195.0650  1695.5650
1  ORD002  2800.00  364.0000  3164.0000
2  ORD003  3200.75  416.0975  3616.8475
3  ORD004   980.25  127.4325  1107.6825

第四部分:数据操作与计算

4.1 数据排序

python 复制代码
# 创建示例数据
sales_data = {
    '销售员': ['张三', '李四', '王五', '赵六', '钱七'],
    '销售额': [150000, 220000, 180000, 95000, 310000],
    '订单数': [45, 38, 52, 28, 61],
    '地区': ['北京', '上海', '北京', '广州', '上海'],
    '季度': ['Q1', 'Q2', 'Q1', 'Q3', 'Q2']
}
sales_df = pd.DataFrame(sales_data)
sales_df['客单价'] = sales_df['销售额'] / sales_df['订单数']

print("销售数据:")
print(sales_df)
复制代码
销售数据:
  销售员     销售额  订单数  地区  季度          客单价
0  张三  150000   45  北京  Q1  3333.333333
1  李四  220000   38  上海  Q2  5789.473684
2  王五  180000   52  北京  Q1  3461.538462
3  赵六   95000   28  广州  Q3  3392.857143
4  钱七  310000   61  上海  Q2  5081.967213

4.1.1 单列排序

python 复制代码
# 单列排序
print("=== 单列排序 ===")
df_sorted_sales = sales_df.sort_values('销售额')
print("按销售额升序排序:")
print(df_sorted_sales)

df_sorted_sales_desc = sales_df.sort_values('销售额', ascending=False)
print("\n按销售额降序排序:")
print(df_sorted_sales_desc)
复制代码
=== 单列排序 ===
按销售额升序排序:
  销售员     销售额  订单数  地区  季度          客单价
3  赵六   95000   28  广州  Q3  3392.857143
0  张三  150000   45  北京  Q1  3333.333333
2  王五  180000   52  北京  Q1  3461.538462
1  李四  220000   38  上海  Q2  5789.473684
4  钱七  310000   61  上海  Q2  5081.967213

按销售额降序排序:
  销售员     销售额  订单数  地区  季度          客单价
4  钱七  310000   61  上海  Q2  5081.967213
1  李四  220000   38  上海  Q2  5789.473684
2  王五  180000   52  北京  Q1  3461.538462
0  张三  150000   45  北京  Q1  3333.333333
3  赵六   95000   28  广州  Q3  3392.857143

4.1.2 多列排序

python 复制代码
# 多列排序
print("=== 多列排序 ===")
df_sorted_multi = sales_df.sort_values(['地区', '销售额'], ascending=[True, False])
print("先按地区升序,再按销售额降序:")
print(df_sorted_multi)
复制代码
=== 多列排序 ===
先按地区升序,再按销售额降序:
  销售员     销售额  订单数  地区  季度          客单价
4  钱七  310000   61  上海  Q2  5081.967213
1  李四  220000   38  上海  Q2  5789.473684
2  王五  180000   52  北京  Q1  3461.538462
0  张三  150000   45  北京  Q1  3333.333333
3  赵六   95000   28  广州  Q3  3392.857143

4.1.3 按索引排序

python 复制代码
# 按索引排序
print("=== 索引排序 ===")
df_sorted_index = sales_df.sort_index(ascending=False)
print("按索引降序排序:")
print(df_sorted_index)
复制代码
=== 索引排序 ===
按索引降序排序:
  销售员     销售额  订单数  地区  季度          客单价
4  钱七  310000   61  上海  Q2  5081.967213
3  赵六   95000   28  广州  Q3  3392.857143
2  王五  180000   52  北京  Q1  3461.538462
1  李四  220000   38  上海  Q2  5789.473684
0  张三  150000   45  北京  Q1  3333.333333

4.1.4 自定义排序

python 复制代码
# 自定义排序
print("=== 自定义排序 ===")
quarter_order = ['Q1', 'Q2', 'Q3', 'Q4']
sales_df['季度'] = pd.Categorical(sales_df['季度'], categories=quarter_order, ordered=True)
df_sorted_custom = sales_df.sort_values('季度')
print("按季度自定义顺序排序:")
print(df_sorted_custom)
复制代码
=== 自定义排序 ===
按季度自定义顺序排序:
  销售员     销售额  订单数  地区  季度          客单价
0  张三  150000   45  北京  Q1  3333.333333
2  王五  180000   52  北京  Q1  3461.538462
1  李四  220000   38  上海  Q2  5789.473684
4  钱七  310000   61  上海  Q2  5081.967213
3  赵六   95000   28  广州  Q3  3392.857143
python 复制代码
sales_df['季度'] = pd.Categorical(sales_df['季度'], categories=quarter_order, ordered=True)

作用 :将'季度'列从普通文本转换为有序分类数据

参数说明:

  • pd.Categorical(): Pandas的分类数据类型
  • categories=quarter_order: 指定所有可能的类别及其逻辑顺序
  • ordered=True: 表示这是一个有顺序的分类变量

为什么要这样做?

如果不转换,Pandas默认按字母顺序排序(Q1、Q2、Q3的顺序是正确的,但如果有Q10,字母排序就会出错)。转换为有序分类后,Pandas就会按照我们指定的quarter_order顺序来理解季度的大小关系。

4.2 数据分组与聚合

4.2.1 分组操作

python 复制代码
# 单列分组
grouped_region = sales_df.groupby('地区')
print("按地区分组:")
for region, group in grouped_region:
    print(f"\n地区: {region}")
    print(group)
复制代码
按地区分组:

地区: 上海
  销售员     销售额  订单数  地区  季度          客单价
1  李四  220000   38  上海  Q2  5789.473684
4  钱七  310000   61  上海  Q2  5081.967213

地区: 北京
  销售员     销售额  订单数  地区  季度          客单价
0  张三  150000   45  北京  Q1  3333.333333
2  王五  180000   52  北京  Q1  3461.538462

地区: 广州
  销售员    销售额  订单数  地区  季度          客单价
3  赵六  95000   28  广州  Q3  3392.857143
python 复制代码
# 多列分组
# 当分类列中有 分类 数据时,需提供 observed 参数
grouped_multi = sales_df.groupby(['地区', '季度'], 
                                 observed=True)
print("\n\n按地区和季度分组:")
for (region, quarter), group in grouped_multi:
    print(f"\n地区: {region}, 季度: {quarter}")
    print(group)
复制代码
按地区和季度分组:

地区: 上海, 季度: Q2
  销售员     销售额  订单数  地区  季度          客单价
1  李四  220000   38  上海  Q2  5789.473684
4  钱七  310000   61  上海  Q2  5081.967213

地区: 北京, 季度: Q1
  销售员     销售额  订单数  地区  季度          客单价
0  张三  150000   45  北京  Q1  3333.333333
2  王五  180000   52  北京  Q1  3461.538462

地区: 广州, 季度: Q3
  销售员    销售额  订单数  地区  季度          客单价
3  赵六  95000   28  广州  Q3  3392.857143

4.2.2 聚合操作

python 复制代码
# 单聚合函数
region_sales = grouped_region['销售额'].sum()
print("各地区总销售额:")
print(region_sales)
复制代码
各地区总销售额:
地区
上海    530000
北京    330000
广州     95000
Name: 销售额, dtype: int64
python 复制代码
# 多聚合函数
region_stats = grouped_region['销售额'].agg(['sum', 'mean', 'count', 'std', 'min', 'max'])
print("各地区销售额统计:")
print(region_stats)
复制代码
各地区销售额统计:
       sum      mean  count           std     min     max
地区                                                       
上海  530000  265000.0      2  63639.610307  220000  310000
北京  330000  165000.0      2  21213.203436  150000  180000
广州   95000   95000.0      1           NaN   95000   95000
python 复制代码
# 不同列使用不同聚合函数
detailed_stats = grouped_region.agg({
    '销售额': ['sum', 'mean'],
    '订单数': 'sum',
    '客单价': 'mean'
})
print("详细统计:")
print(detailed_stats)
复制代码
详细统计:
       销售额           订单数          客单价
       sum      mean sum         mean
地区                                   
上海  530000  265000.0  99  5435.720449
北京  330000  165000.0  97  3397.435897
广州   95000   95000.0  28  3392.857143
python 复制代码
# 重命名聚合结果
renamed_stats = grouped_region.agg(
    总销售额=('销售额', 'sum'),
    平均销售额=('销售额', 'mean'),
    总订单数=('订单数', 'sum'),
    平均客单价=('客单价', 'mean')
)
print("重命名聚合结果:")
print(renamed_stats)
复制代码
重命名聚合结果:
      总销售额     平均销售额  总订单数        平均客单价
地区                                     
上海  530000  265000.0    99  5435.720449
北京  330000  165000.0    97  3397.435897
广州   95000   95000.0    28  3392.857143

4.2.3 分组后应用函数

python 复制代码
# 分组后应用函数
def normalize(x):
    """标准化函数"""
    return (x - x.mean()) / x.std()

normalized_sales = sales_df.groupby('地区')['销售额'].transform(normalize)
sales_df['销售额标准化'] = normalized_sales
print("标准化后的销售额:")
print(sales_df[['销售员', '地区', '销售额', '销售额标准化']])
复制代码
标准化后的销售额:
  销售员  地区     销售额    销售额标准化
0  张三  北京  150000 -0.707107
1  李四  上海  220000 -0.707107
2  王五  北京  180000  0.707107
3  赵六  广州   95000       NaN
4  钱七  上海  310000  0.707107

4.2.4 分组过滤

python 复制代码
# 过滤
# 筛选订单数大于40的组
high_order_groups = sales_df.groupby('地区').filter(lambda x: x['订单数'].sum() > 40)
print("订单总数大于40的地区:")
print(high_order_groups)
复制代码
订单总数大于40的地区:
  销售员     销售额  订单数  地区  季度          客单价    销售额标准化
0  张三  150000   45  北京  Q1  3333.333333 -0.707107
1  李四  220000   38  上海  Q2  5789.473684 -0.707107
2  王五  180000   52  北京  Q1  3461.538462  0.707107
4  钱七  310000   61  上海  Q2  5081.967213  0.707107

4.2.5 透视表

python 复制代码
# 透视表
pivot_table = sales_df.pivot_table(
    values='销售额',
    index='地区',
    columns='季度',
    aggfunc='sum',
    fill_value=0,
    margins=True,
    margins_name='总计',
    observed=True
)
print("销售额透视表:")
print(pivot_table)
复制代码
销售额透视表:
季度      Q1      Q2     Q3      总计
地区                               
上海       0  530000      0  530000
北京  330000       0      0  330000
广州       0       0  95000   95000
总计  330000  530000  95000  955000

4.2.6 交叉表

python 复制代码
# 交叉表
cross_tab = pd.crosstab(
    index=sales_df['地区'],
    columns=sales_df['季度'],
    values=sales_df['销售额'],
    aggfunc='sum',
    margins=True,
    margins_name='总计'
)
print("交叉表:")
print(cross_tab)
复制代码
交叉表:
季度      Q1      Q2     Q3   Q4      总计
地区                                    
上海       0  530000      0  0.0  530000
北京  330000       0      0  0.0  330000
广州       0       0  95000  0.0   95000
总计  330000  530000  95000  NaN  955000

4.3 数据合并与连接

python 复制代码
# 创建多个DataFrame
df1 = pd.DataFrame({
    '员工号': ['E001', 'E002', 'E003', 'E004'],
    '姓名': ['张三', '李四', '王五', '赵六'],
    '部门': ['技术部', '市场部', '技术部', '人事部']
})

df2 = pd.DataFrame({
    '员工号': ['E001', 'E002', 'E005'],
    '工资': [15000, 18000, 22000],
    '奖金': [3000, 4000, 5000]
})

df3 = pd.DataFrame({
    '员工号': ['E003', 'E004', 'E006'],
    '入职日期': ['2020-01-15', '2019-03-20', '2021-05-10'],
    '城市': ['北京', '上海', '广州']
})

print("DataFrame 1:")
print(df1)
print("\nDataFrame 2:")
print(df2)
print("\nDataFrame 3:")
print(df3)
复制代码
DataFrame 1:
    员工号  姓名   部门
0  E001  张三  技术部
1  E002  李四  市场部
2  E003  王五  技术部
3  E004  赵六  人事部

DataFrame 2:
    员工号     工资    奖金
0  E001  15000  3000
1  E002  18000  4000
2  E005  22000  5000

DataFrame 3:
    员工号        入职日期  城市
0  E003  2020-01-15  北京
1  E004  2019-03-20  上海
2  E006  2021-05-10  广州

4.3.1 合并操作

merge - 类似SQL JOIN

python 复制代码
print("1. 内连接 (INNER JOIN):")
inner_join = pd.merge(df1, df2, on='员工号', how='inner')
print(inner_join)
复制代码
1. 内连接 (INNER JOIN):
    员工号  姓名   部门     工资    奖金
0  E001  张三  技术部  15000  3000
1  E002  李四  市场部  18000  4000
python 复制代码
print("\n2. 左连接 (LEFT JOIN):")
left_join = pd.merge(df1, df2, on='员工号', how='left')
print(left_join)
复制代码
2. 左连接 (LEFT JOIN):
    员工号  姓名   部门       工资      奖金
0  E001  张三  技术部  15000.0  3000.0
1  E002  李四  市场部  18000.0  4000.0
2  E003  王五  技术部      NaN     NaN
3  E004  赵六  人事部      NaN     NaN
python 复制代码
print("\n3. 右连接 (RIGHT JOIN):")
right_join = pd.merge(df1, df2, on='员工号', how='right')
print(right_join)
复制代码
3. 右连接 (RIGHT JOIN):
    员工号   姓名   部门     工资    奖金
0  E001   张三  技术部  15000  3000
1  E002   李四  市场部  18000  4000
2  E005  NaN  NaN  22000  5000
python 复制代码
print("\n4. 外连接 (OUTER JOIN):")
outer_join = pd.merge(df1, df2, on='员工号', how='outer')
print(outer_join)
复制代码
4. 外连接 (OUTER JOIN):
    员工号   姓名   部门       工资      奖金
0  E001   张三  技术部  15000.0  3000.0
1  E002   李四  市场部  18000.0  4000.0
2  E003   王五  技术部      NaN     NaN
3  E004   赵六  人事部      NaN     NaN
4  E005  NaN  NaN  22000.0  5000.0
python 复制代码
print("\n5. 多DataFrame合并:")
multi_merge = pd.merge(pd.merge(df1, df2, on='员工号', how='left'), 
                      df3, on='员工号', how='left')
print(multi_merge)
复制代码
5. 多DataFrame合并:
    员工号  姓名   部门       工资      奖金        入职日期   城市
0  E001  张三  技术部  15000.0  3000.0         NaN  NaN
1  E002  李四  市场部  18000.0  4000.0         NaN  NaN
2  E003  王五  技术部      NaN     NaN  2020-01-15   北京
3  E004  赵六  人事部      NaN     NaN  2019-03-20   上海
python 复制代码
print("\n6. 按不同列名合并:")
df2_renamed = df2.rename(columns={'员工号': '编号'})
merge_different_cols = pd.merge(df1, df2_renamed, 
                                 left_on='员工号', 
                                 right_on='编号', 
                                 how='left')
print(merge_different_cols)
复制代码
6. 按不同列名合并:
    员工号  姓名   部门    编号       工资      奖金
0  E001  张三  技术部  E001  15000.0  3000.0
1  E002  李四  市场部  E002  18000.0  4000.0
2  E003  王五  技术部   NaN      NaN     NaN
3  E004  赵六  人事部   NaN      NaN     NaN

4.3.2 连接操作

concat - 沿轴连接

python 复制代码
df4 = pd.DataFrame({
    '员工号': ['E007', 'E008'],
    '姓名': ['钱七', '孙八'],
    '部门': ['技术部', '市场部']
})

print("7. 垂直连接 (追加行):")
vertical_concat = pd.concat([df1, df4], ignore_index=True)
print(vertical_concat)
复制代码
7. 垂直连接 (追加行):
    员工号  姓名   部门
0  E001  张三  技术部
1  E002  李四  市场部
2  E003  王五  技术部
3  E004  赵六  人事部
4  E007  钱七  技术部
5  E008  孙八  市场部
python 复制代码
print("\n8. 水平连接 (追加列):")
df1_subset = df1[['员工号', '姓名']]
df2_subset = df2[['员工号', '工资']]
horizontal_concat = pd.concat([df1_subset.set_index('员工号'), 
                               df2_subset.set_index('员工号')], 
                              axis=1)
print(horizontal_concat)
复制代码
8. 水平连接 (追加列):
       姓名       工资
员工号               
E001   张三  15000.0
E002   李四  18000.0
E003   王五      NaN
E004   赵六      NaN
E005  NaN  22000.0

4.3.3 基于索引合并

join - 基于索引合并

python 复制代码
df1_indexed = df1.set_index('员工号')
df2_indexed = df2.set_index('员工号')
df3_indexed = df3.set_index('员工号')

join_result = df1_indexed.join([df2_indexed, df3_indexed], how='outer')
print("基于索引合并:")
print(join_result)
复制代码
基于索引合并:
       姓名   部门       工资      奖金        入职日期   城市
员工号                                             
E001   张三  技术部  15000.0  3000.0         NaN  NaN
E002   李四  市场部  18000.0  4000.0         NaN  NaN
E003   王五  技术部      NaN     NaN  2020-01-15   北京
E004   赵六  人事部      NaN     NaN  2019-03-20   上海
E005  NaN  NaN  22000.0  5000.0         NaN  NaN
E006  NaN  NaN      NaN     NaN  2021-05-10   广州

4.4 窗口函数与滚动计算

python 复制代码
# 创建时间序列数据
np.random.seed(42)
dates = pd.date_range('2023-01-01', periods=30, freq='D')
stock_data = pd.DataFrame({
    '日期': dates,
    '股票代码': 'AAPL',
    '开盘价': np.random.uniform(150, 180, 30).round(2),
    '收盘价': np.random.uniform(155, 185, 30).round(2),
    '成交量': np.random.randint(1000000, 5000000, 30)
})

# 添加涨跌幅
stock_data['涨跌幅'] = (stock_data['收盘价'] - stock_data['开盘价']) / stock_data['开盘价']
stock_data.set_index('日期', inplace=True)

print("股票数据:")
print(stock_data.head(10))
复制代码
股票数据:
            股票代码     开盘价     收盘价      成交量       涨跌幅
日期                                                 
2023-01-01  AAPL  161.24  173.23  1023247  0.074361
2023-01-02  AAPL  178.52  160.12  2072876 -0.103070
2023-01-03  AAPL  171.96  156.95  4613009 -0.087288
2023-01-04  AAPL  167.96  183.47  3704238  0.092343
2023-01-05  AAPL  154.68  183.97  3630708  0.189359
2023-01-06  AAPL  154.68  179.25  4494679  0.158844
2023-01-07  AAPL  151.74  164.14  2322905  0.081719
2023-01-08  AAPL  175.99  157.93  2767640 -0.102619
2023-01-09  AAPL  168.03  175.53  3839291  0.044635
2023-01-10  AAPL  171.24  168.20  3529467 -0.017753

4.4.1 滚动窗口计算

python 复制代码
# 5日滚动平均
stock_data['5日平均收盘价'] = stock_data['收盘价'].rolling(window=5).mean()
stock_data['5日成交量平均'] = stock_data['成交量'].rolling(window=5).mean()

# 滚动最大值/最小值
stock_data['5日最高价'] = stock_data['收盘价'].rolling(window=5).max()
stock_data['5日最低价'] = stock_data['收盘价'].rolling(window=5).min()

# 滚动标准差
stock_data['5日价格波动'] = stock_data['收盘价'].rolling(window=5).std()

# 滚动求和
stock_data['5日成交量总和'] = stock_data['成交量'].rolling(window=5).sum()

print("滚动计算后的数据:")
print(stock_data[['收盘价', '5日平均收盘价', '5日最高价', '5日最低价', '5日价格波动']].head(10))
复制代码
滚动计算后的数据:
               收盘价  5日平均收盘价   5日最高价   5日最低价     5日价格波动
日期                                                    
2023-01-01  173.23      NaN     NaN     NaN        NaN
2023-01-02  160.12      NaN     NaN     NaN        NaN
2023-01-03  156.95      NaN     NaN     NaN        NaN
2023-01-04  183.47      NaN     NaN     NaN        NaN
2023-01-05  183.97  171.548  183.97  156.95  12.678427
2023-01-06  179.25  172.752  183.97  156.95  13.154977
2023-01-07  164.14  173.556  183.97  156.95  12.283940
2023-01-08  157.93  173.752  183.97  157.93  11.956183
2023-01-09  175.53  172.164  183.97  157.93  10.815664
2023-01-10  168.20  169.010  179.25  157.93   8.580609

4.4.2 扩展窗口

python 复制代码
stock_data['累计成交量'] = stock_data['成交量'].expanding().sum()
stock_data['累计平均收盘价'] = stock_data['收盘价'].expanding().mean()
print("扩展窗口计算:")
print(stock_data[['成交量', '累计成交量', '收盘价', '累计平均收盘价']].head(10))
复制代码
扩展窗口计算:
                成交量       累计成交量     收盘价     累计平均收盘价
日期                                                 
2023-01-01  1023247   1023247.0  173.23  173.230000
2023-01-02  2072876   3096123.0  160.12  166.675000
2023-01-03  4613009   7709132.0  156.95  163.433333
2023-01-04  3704238  11413370.0  183.47  168.442500
2023-01-05  3630708  15044078.0  183.97  171.548000
2023-01-06  4494679  19538757.0  179.25  172.831667
2023-01-07  2322905  21861662.0  164.14  171.590000
2023-01-08  2767640  24629302.0  157.93  169.882500
2023-01-09  3839291  28468593.0  175.53  170.510000
2023-01-10  3529467  31998060.0  168.20  170.279000

4.4.3 指数加权移动平均

python 复制代码
stock_data['EWM_收盘价'] = stock_data['收盘价'].ewm(span=5).mean()
stock_data['EWM_成交量'] = stock_data['成交量'].ewm(span=5).mean()
print("指数加权移动平均:")
print(stock_data[['收盘价', 'EWM_收盘价', '成交量', 'EWM_成交量']].head(10))
复制代码
指数加权移动平均:
               收盘价     EWM_收盘价      成交量       EWM_成交量
日期                                                   
2023-01-01  173.23  173.230000  1023247  1.023247e+06
2023-01-02  160.12  165.364000  2072876  1.653024e+06
2023-01-03  156.95  161.378421  4613009  3.055122e+06
2023-01-04  183.47  170.554923  3704238  3.324755e+06
2023-01-05  183.97  175.704787  3630708  3.442206e+06
2023-01-06  179.25  177.000256  4494679  3.826794e+06
2023-01-07  164.14  172.447013  2322905  3.294334e+06
2023-01-08  157.93  167.411532  2767640  3.111641e+06
2023-01-09  175.53  170.189961  3839291  3.360669e+06
2023-01-10  168.20  169.514935  3529467  3.417928e+06

4.4.4 滚动应用自定义函数

python 复制代码
def price_range(series):
    """计算价格范围"""
    return series.max() - series.min()

stock_data['5日价格范围'] = stock_data['收盘价'].rolling(window=5).apply(price_range)
stock_data['5日涨跌幅波动'] = stock_data['涨跌幅'].rolling(window=5).std()

print("滚动应用自定义函数:")
print(stock_data[['收盘价', '5日价格范围', '涨跌幅', '5日涨跌幅波动']].head(10))
复制代码
滚动应用自定义函数:
               收盘价  5日价格范围       涨跌幅   5日涨跌幅波动
日期                                            
2023-01-01  173.23     NaN  0.074361       NaN
2023-01-02  160.12     NaN -0.103070       NaN
2023-01-03  156.95     NaN -0.087288       NaN
2023-01-04  183.47     NaN  0.092343       NaN
2023-01-05  183.97   27.02  0.189359  0.125164
2023-01-06  179.25   27.02  0.158844  0.137240
2023-01-07  164.14   27.02  0.081719  0.107321
2023-01-08  157.93   26.04 -0.102619  0.113582
2023-01-09  175.53   26.04  0.044635  0.114697
2023-01-10  168.20   21.32 -0.017753  0.099139
相关推荐
marsh02062 小时前
2 为什么选择OpenClaw?深入分析其技术优势与商业价值
人工智能·ai·数据挖掘·编程·技术
江畔柳前堤3 小时前
XZ07_解决WORD中间单词间隔过大的问题
数据库·人工智能·线性代数·oracle·数据挖掘·word
城数派11 小时前
2005-2025年我国乡镇级的逐日最低气温数据(Shp/Excel格式)
数据分析·excel
YangYang9YangYan11 小时前
2026大专国际经济与贸易学数据分析的技术应用价值
数据挖掘·数据分析
L***一11 小时前
2026高职财税大数据应用,如何成功转向数据分析?
大数据·数据挖掘·数据分析
2501_9336707911 小时前
2026大专商务数据分析与应用考什么证书比较有用?
数据挖掘·数据分析
CC数学建模12 小时前
2026年(第14届)“泰迪杯”数据挖掘挑战赛C题:事件驱动型股市投资策略构建 多维度完整金融市场数据分享
人工智能·数据挖掘
努力变大白12 小时前
智能制造供应链优化系统:从数据挖掘到运筹优化的完整算法解析
人工智能·数据挖掘
YangYang9YangYan12 小时前
2026大专大数据科学专业学数据分析的技术价值分析
大数据·数据挖掘·数据分析