📚 Pandas数据分析完整学习指南

💡 核心定位:Pandas是Python中最强大的数据分析库,专门用于处理结构化数据,基于NumPy构建


📑 目录结构

  1. Pandas核心数据结构
  2. Series详解
  3. Series字符串操作
  4. Series其他常用方法
  5. DataFrame详解
  6. DataFrame高级操作
  7. 数据读取与存储
  8. 数据库连接
  9. 知识点速查表

1. Pandas核心数据结构

1.1 Pandas简介

📌 核心概念
Pandas提供两种核心数据结构用于数据分析:

  • Series:一维数组 + 标签(类似带索引的列表)
  • DataFrame:二维数组 + 行标签 + 列名称(类似Excel表格)

💡 知识点:Pandas的四大功能

  1. 读取数据
  2. 数据处理
  3. 数据分析
  4. 数据可视化

📝 代码示例:导入Pandas

import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings('ignore')  # 忽略警告信息

⚠️ 注意事项

  • Pandas基于NumPy构建,因此继承了NumPy的许多特性
  • 通常使用pd作为Pandas的别名(行业标准)
  • 建议同时导入NumPy,因为很多操作需要配合使用

2. Series详解

2.1 Series基础概念

📌 核心概念
Series是一维的数组加标签,可以理解为Excel表格中的一列数据,每个数据都有对应的行索引。

🔧 函数:pd.Series()

📊 参数说明

参数类型说明默认值
datalist/tuple/dict/ndarray数据源必填
indexlist/array行索引标签0开始的整数
dtypedtype数据类型自动推断
namestrSeries名称None

📝 代码示例:创建Series

# 方法1:从列表创建
data = [1, 2, 3, 4]
s1 = pd.Series(data=data, index=list('abcd'))
print(s1)
# 输出:
# a    1
# b    2
# c    3
# d    4
# dtype: int64

# 方法2:从字典创建(推荐)
dic = {'lisa': 80, 'cc': 90, 'john': 100}
s2 = pd.Series(data=dic)
print(s2)
# 输出:
# lisa     80
# cc       90
# john    100
# dtype: int64

# 方法3:从NumPy数组创建
arr = np.array([1, 2, 3, 4])
s3 = pd.Series(data=arr, index=list('abcd'))

💎 最佳实践

✅ 推荐:使用字典创建Series,键自动成为索引
s = pd.Series({'name': 'Lisa', 'age': 18})

❌ 避免:索引长度与数据长度不匹配
s = pd.Series([1, 2, 3], index=['a', 'b'])  # 会报错

2.2 Series数据访问

💡 知识点:Series的两种索引方式

  1. 位置索引:使用整数位置(从0开始)
  2. 标签索引:使用自定义的索引标签

📝 代码示例:数据访问

s2 = pd.Series({'lisa': 80, 'cc': 90, 'john': 100})

# 位置索引访问
print(s2[0])        # 输出:80(第一个元素)

# 标签索引访问
print(s2['lisa'])   # 输出:80(通过标签访问)

# 多个元素访问
print(s2[['cc', 'john']])
# 输出:
# cc      90
# john    100
# dtype: int64

2.3 Series属性

📊 常用属性列表

属性说明示例
ndim维度(Series固定为1)s.ndim
shape形状(元素个数,)s.shape
size元素总数s.size
dtype数据类型s.dtype
index行索引对象s.index
values值(返回NumPy数组)s.values

📝 代码示例:属性使用

s2 = pd.Series({'lisa': 80, 'cc': 90, 'john': 100})

print('维度:', s2.ndim)           # 输出:1
print('形状:', s2.shape)          # 输出:(3,)
print('元素个数:', s2.size)       # 输出:3
print('数据类型:', s2.dtype)      # 输出:int64
print('行索引:', s2.index)        # 输出:Index(['lisa', 'cc', 'john'], dtype='object')
print('值:', s2.values)           # 输出:[ 80  90 100]

2.4 Series继承NumPy的特性

💡 知识点:Series支持NumPy操作

📝 代码示例:NumPy风格操作

s2 = pd.Series({'lisa': 80, 'cc': 90, 'john': 100})

# 1. 掩码操作(布尔索引)
print('取出>=80的数据:\n', s2[s2 >= 80])
# 输出:
# lisa     80
# cc       90
# john    100

# 2. 切片操作
print('取出cc和john的成绩:\n', s2[['cc', 'john']])

# 3. 统计函数
print('计算成绩均值:', s2.mean())      # 输出:90.0
print('最大值:', s2.max())             # 输出:100
print('最小值:', s2.min())             # 输出:80
print('标准差:', s2.std())             # 输出:10.0
print('求和:', s2.sum())               # 输出:270

🔗 关联知识
→ 3. Series字符串操作
→ 4. Series其他常用方法


3. Series字符串操作

3.1 字符串操作基础

📌 核心概念
所有Series字符串操作都通过series.str.函数名()的形式调用,这是Pandas提供的向量化字符串操作接口。

⚠️ 注意事项

  • 必须使用.str访问器才能调用字符串方法
  • 字符串操作返回新的Series,不修改原数据(除非赋值)
  • 只能用于字符串类型的Series

3.2 常用字符串方法

📊 字符串方法速查表

方法功能返回值示例
str.strip()去除首尾指定字符Seriess.str.strip('()+ ')
str.split()按分隔符分割Series/DataFrames.str.split('-')
str.replace()替换子串Seriess.str.replace('old', 'new')
str.contains()检查是否包含布尔Seriess.str.contains('关键词')
str.count()统计子串出现次数Seriess.str.count('a')
str.len()计算字符串长度Seriess.str.len()
str.find()查找子串位置Seriess.str.find('x')

3.3 strip() - 去除首尾字符

🔧 函数:series.str.strip()

📝 代码示例

data = ['Tom', ' Jerry)', '(Tyke+', 'Spark']
s1 = pd.Series(data)

# 去除首尾的括号、加号和空格
s1 = s1.str.strip('()+ ')
print(s1)
# 输出:
# 0      Tom
# 1    Jerry
# 2     Tyke
# 3    Spark

# 去除首尾等号
data2 = ['Tom-Zhang', '====Jerry-Li', '===Tyke-Xiong===', 'Spark-Zhao====']
s2 = pd.Series(data2)
s2 = s2.str.strip('=')
print(s2)
# 输出:
# 0       Tom-Zhang
# 1       Jerry-Li
# 2    Tyke-Xiong
# 3    Spark-Zhao

💎 最佳实践

✅ 推荐:链式调用多个字符串方法
s = s.str.strip().str.lower().str.replace(' ', '_')

❌ 避免:忘记使用.str访问器
s = s.strip()  # 错误!会报错

3.4 split() - 字符串分割

🔧 函数:series.str.split()

📊 参数说明

参数类型说明默认值
patstr分隔符空格
expandbool是否展开为DataFrameFalse
nint最大分割次数-1(全部)

📝 代码示例

s2 = pd.Series(['Tom-Zhang', 'Jerry-Li', 'Tyke-Xiong', 'Spark-Zhao'])

# 基础分割(返回列表)
result1 = s2.str.split('-')
print(result1)
# 输出:
# 0     [Tom, Zhang]
# 1     [Jerry, Li]
# 2     [Tyke, Xiong]
# 3    [Spark, Zhao]

# 展开为DataFrame(推荐)
result2 = s2.str.split('-', expand=True)
print(result2)
# 输出:
#        0      1
# 0    Tom  Zhang
# 1  Jerry     Li
# 2   Tyke  Xiong
# 3  Spark   Zhao

# 设置列名
df = s2.str.split('-', expand=True)
df.columns = ['姓', '名']

🎯 应用场景:地理位置分割

s3 = pd.Series(['北京市-昌平区', '北京市-海淀区', '北京市-东城区'])
df1 = s3.str.split('-', expand=True)
df1.columns = ['城市', '片区']
print(df1)
# 输出:
#     城市   片区
# 0  北京市  昌平区
# 1  北京市  海淀区
# 2  北京市  东城区

3.5 replace() - 字符串替换

🔧 函数:series.str.replace()

📝 代码示例

s4 = pd.Series(['cc', 'lisa', 'john'])

# 替换字符串
s4 = s4.str.replace('cc', 'ch')
print(s4)
# 输出:
# 0      ch
# 1    lisa
# 2    john

# 实际应用:清理地铁站名称
s5 = pd.Series(['望京地铁站', '平安里地铁站', '西直门地铁站', '望京'])
s5 = s5.str.replace('地铁站', '')
print(s5)
# 输出:
# 0     望京
# 1    平安里
# 2    西直门
# 3     望京

3.6 contains() - 包含检查

🔧 函数:series.str.contains()

📊 参数说明

参数类型说明默认值
patstr搜索模式(支持正则)必填
casebool是否区分大小写True
regexbool是否使用正则表达式True

📝 代码示例

s4 = pd.Series(['ch', 'lisa', 'john'])

# 基础包含检查
result = s4[s4.str.contains('lisa')]
print(result)
# 输出:
# 1    lisa

# 不区分大小写
emails = pd.Series(['user@example.com', 'admin@test.org', 'Support@ai.com'])
result = emails[emails.str.contains('admin|support', case=False)]
print(result)
# 输出:
# 1    admin@test.org
# 2    Support@ai.com

# 实际应用:筛选地点
s6 = s5[s5.str.contains('望京')]
print(s6)
# 输出:
# 0    望京
# 3    望京

3.7 count() - 统计子串出现次数

🔧 函数:series.str.count()

📝 代码示例

s4 = pd.Series(['ch', 'lisa', 'john'])

# 统计字符'c'出现的次数
result = s4.str.count('c')
print(result)
# 输出:
# 0    1
# 1    0
# 2    0

# 实际应用:统计DNA序列
dna = pd.Series(['AGCTAG', 'TTAGAC', 'GGGAGG'])
ag_count = dna.str.count('AG')
print(ag_count)
# 输出:
# 0    2
# 1    1
# 2    1

3.8 len() - 计算字符串长度

🔧 函数:series.str.len()

📝 代码示例

s4 = pd.Series(['ch', 'lisa', 'john'])

# 计算每个字符串的长度
lengths = s4.str.len()
print(lengths)
# 输出:
# 0    2
# 1    4
# 2    4

# 实际应用:验证学号长度
s2 = pd.Series(['20130101', '201301', '20130104', '20130106'])
invalid = s2[s2.str.len() != 8]
print('不合规的学号:\n', invalid)
# 输出:
# 1    201301

3.9 find() - 查找子串位置

🔧 函数:series.str.find()

💡 知识点:返回值规则

  • 找到:返回第一次出现的索引位置(从0开始)
  • 未找到:返回-1

📝 代码示例

s4 = pd.Series(['ch', 'lisa', 'john'])

# 查找字符'c'的位置
positions = s4.str.find('c')
print(positions)
# 输出:
# 0    0  ('ch'中'c'在位置0)
# 1   -1  ('lisa'中没有'c')
# 2   -1  ('john'中没有'c')

# 实际应用:筛选以'A'开头的数据
codes = pd.Series(['A100', 'B000', 'C300', 'A250'])
a_codes = codes[codes.str.find('A') == 0]
print(a_codes)
# 输出:
# 0    A100
# 3    A250

3.10 字符串索引

💡 知识点:直接索引字符

📝 代码示例

s1 = pd.Series(['Tom', 'Jerry', 'Tyke', 'Spark'])

# 截取首字母
first_letters = s1.str[0]
print(first_letters)
# 输出:
# 0    T
# 1    J
# 2    T
# 3    S

# 截取前三个字符
first_three = s1.str[0:3]
print(first_three)
# 输出:
# 0    Tom
# 1    Jer
# 2    Tyk
# 3    Spa

3.11 综合案例

🎯 案例1:公司福利统计

# 统计每家公司福利的个数
s1 = pd.Series(
    data=['五险一金,餐补,年终奖',
          '五险一金,下午茶,全勤奖,带薪休假',
          '五险一金,下午茶,全勤奖,带薪休假,定期体检,团建'],
    index=list('ABC')
)

# 方法:统计逗号数量+1
welfare_count = s1.str.count(',') + 1
print(welfare_count)
# 输出:
# A    3
# B    4
# C    6

🎯 案例2:学号验证

# 找到学号不合规的数据
s2 = pd.Series(['20130101', '201301', '20130104', '20130106'])
invalid_ids = s2[s2.str.len() != 8]
print('不合规学号:\n', invalid_ids)
# 输出:
# 1    201301

🎯 案例3:邮箱筛选

# 检查是否包含"admin"或"support"(不区分大小写)
emails = pd.Series(['user@example.com', 'admin@test.org', 'Support@ai.com'])
admin_emails = emails[emails.str.contains('admin|support', case=False)]
print(admin_emails)
# 输出:
# 1    admin@test.org
# 2    Support@ai.com

🔗 关联知识
→ 4. Series其他常用方法
→ 5. DataFrame详解


4. Series其他常用方法

4.1 isin() - 成员检查

🔧 函数:series.isin()

📌 核心概念
检查Series中的每个元素是否在给定的列表中,返回布尔Series,常用于按条件筛选数据。

📝 代码示例

s1 = pd.Series(['北京', '上海', '北京', '天津', '北京', '重庆', '上海', '重庆'])

# 筛选开设产品线的城市
target_cities = ['北京', '上海', '重庆']
result = s1[s1.isin(target_cities)]
print(result)
# 输出:
# 0    北京
# 1    上海
# 2    北京
# 4    北京
# 5    重庆
# 6    上海
# 7    重庆

# 实际应用:筛选已知性别
gender = pd.Series(['男', '女', '未统计', '男', '男', '女', '未统计'])
known_gender = gender[gender.isin(['男', '女'])]
print(known_gender)
# 输出:
# 0    男
# 1    女
# 3    男
# 4    男
# 5    女

💎 最佳实践

✅ 推荐:使用isin()进行多值筛选
df = df[df['city'].isin(['北京', '上海', '深圳'])]

❌ 避免:使用多个or条件
df = df[(df['city']=='北京') | (df['city']=='上海') | (df['city']=='深圳')]  # 冗长

4.2 unique() - 去重

🔧 函数:series.unique()

📌 核心概念
返回Series中所有唯一值组成的NumPy数组,用于查看数据中有哪些不同的类别。

📝 代码示例

gender = pd.Series(['男', '女', '未统计', '男', '男', '女', '未统计'])

# 查看有哪些类别
categories = gender.unique()
print('有哪些类别:', categories)
# 输出:['男' '女' '未统计']

# 数据清洗后再去重
data_info = pd.Series(
    ['经理', '本科', '经理 ', '初中', '博士', '专科',
     '专科', '博士', '博士', '本科', '专科', '本科', '专科', '本科'],
    name='学历'
)

# 去掉首尾空格
data_info = data_info.str.strip()
# 去掉非学历数据
data_info = data_info[data_info != '经理']
# 查看学历类别
print('学历类别:', data_info.unique())
# 输出:['本科' '初中' '博士' '专科']

4.3 nunique() - 唯一值计数

🔧 函数:series.nunique()

📌 核心概念
返回Series中唯一值的数量(去重后的计数),常用于统计类别数量。

📝 代码示例

gender = pd.Series(['男', '女', '男', '男', '女'])

# 统计类别数量
n_categories = gender.nunique()
print('一共有几个类别:', n_categories)
# 输出:2

4.4 value_counts() - 分类计数

🔧 函数:series.value_counts()

📊 参数说明

参数类型说明默认值
normalizebool是否返回占比False
sortbool是否排序True
ascendingbool升序还是降序False
dropnabool是否排除缺失值True

📝 代码示例

gender = pd.Series(['男', '女', '男', '男', '女'])

# 统计每个类别的数量
counts = gender.value_counts()
print('每个类别多少人:\n', counts)
# 输出:
# 男    3
# 女    2

# 计算占比
proportions = gender.value_counts(normalize=True)
print('男女占比:\n', proportions)
# 输出:
# 男    0.6
# 女    0.4

# 或者手动计算占比
proportions2 = gender.value_counts() / gender.size
print(proportions2)
# 输出:
# 男    0.6
# 女    0.4

🎯 应用场景:学历统计

data_info = pd.Series(
    ['本科', '初中', '博士', '专科', '专科', '博士', '博士', '本科', '专科', '本科', '专科', '本科'],
    name='学历'
)

# 查看各学历人数
print('各学历人数:\n', data_info.value_counts())
# 输出:
# 本科    4
# 专科    4
# 博士    3
# 初中    1

# 查看各学历占比
print('各学历占比:\n', data_info.value_counts(normalize=True))
# 输出:
# 本科    0.333333
# 专科    0.333333
# 博士    0.250000
# 初中    0.083333

4.5 map() - 映射转换

🔧 函数:series.map()

📌 核心概念
根据字典或函数对Series中的每个值进行一对一映射转换,常用于数据编码和分类转换。

📊 参数说明

参数类型说明
argdict/function映射规则(字典或函数)

📝 代码示例:城市等级映射

s1 = pd.Series(['北京', '上海', '北京', '天津', '北京', '重庆', '上海', '重庆'])

# 定义映射关系
city_map = {
    '北京': '一线城市',
    '上海': '一线城市',
    '天津': '二线城市',
    '重庆': '二线城市',
}

# 应用映射
s1 = s1.map(city_map)
print(s1)
# 输出:
# 0    一线城市
# 1    一线城市
# 2    一线城市
# 3    二线城市
# 4    一线城市
# 5    二线城市
# 6    一线城市
# 7    二线城市

🎯 应用场景:用户行为编码

# 用户行为数据:1-浏览 2-加购 3-收藏 4-购买
user_actions = pd.Series([1, 1, 2, 3, 4, 2, 1])

# 定义映射关系
actions_map = {
    1: 'pv',       # page view 浏览
    2: 'cart',     # 加购物车
    3: 'collect',  # 收藏
    4: 'buy'       # 购买
}

# 应用映射
user_actions = user_actions.map(actions_map)
print(user_actions)
# 输出:
# 0        pv
# 1        pv
# 2      cart
# 3   collect
# 4       buy
# 5      cart
# 6        pv

💎 最佳实践

✅ 推荐:使用map()进行分类编码
df['level'] = df['score'].map({1: '低', 2: '中', 3: '高'})

❌ 避免:使用多个if-else
# 不推荐的写法
def classify(x):
    if x == 1: return '低'
    elif x == 2: return '中'
    else: return '高'

4.6 shift() - 数据偏移

🔧 函数:series.shift()

📊 参数说明

参数类型说明默认值
periodsint偏移量(正数向下,负数向上)1
fill_valuescalar填充值NaN

📌 核心概念
将Series中的数据向上或向下移动指定位置,常用于计算环比、同比等时间序列分析。

📝 代码示例:基础偏移

s2 = pd.Series(
    [11, 22, 33, 44, 55], 
    index=['一月', '二月', '三月', '四月', '五月']
)

# 向下偏移1位(正数)
shifted_down = s2.shift(1)
print(shifted_down)
# 输出:
# 一月    NaN
# 二月   11.0
# 三月   22.0
# 四月   33.0
# 五月   44.0

# 向上偏移1位(负数)
shifted_up = s2.shift(-1)
print(shifted_up)
# 输出:
# 一月   22.0
# 二月   33.0
# 三月   44.0
# 四月   55.0
# 五月    NaN

🎯 应用场景:计算月环比

s2 = pd.Series(
    [11, 22, 33, 44, 55], 
    index=['一月', '二月', '三月', '四月', '五月']
)

# 月环比 = (本月 - 上月) / 上月
# 例如:二月环比 = (22 - 11) / 11 = 1.0 = 100%增长
mom_growth = (s2 - s2.shift(1)) / s2.shift(1)
print('月环比:\n', mom_growth)
# 输出:
# 一月         NaN
# 二月    1.000000  (增长100%)
# 三月    0.500000  (增长50%)
# 四月    0.333333  (增长33.3%)
# 五月    0.250000  (增长25%)

💡 知识点:环比计算公式

  • 月环比 = (本月 - 上月) / 上月
  • 正数表示增长,负数表示下降
  • 例如:0.25 表示增长25%,-0.1 表示下降10%

🔗 关联知识
→ 5. DataFrame详解
→ 7. 数据读取与存储


5. DataFrame详解

5.1 DataFrame基础概念

📌 核心概念
DataFrame是二维的数组加行标签和列名称,可以理解为Excel表格或SQL数据表,是Pandas中最常用的数据结构。

💡 知识点:DataFrame的组成

  • 行索引(index):每一行的标签
  • 列名(columns):每一列的名称
  • 数据(values):实际的数据内容(NumPy数组)

🔧 函数:pd.DataFrame()

📊 参数说明

参数类型说明默认值
datadict/list/ndarray数据源必填
indexlist/array行索引0开始的整数
columnslist列名自动生成
dtypedtype数据类型自动推断

5.2 创建DataFrame的三种方式

📝 方法1:从NumPy数组创建

import numpy as np
import pandas as pd

# 创建随机数据
np.random.seed(123)
data = np.random.randint(1, 100, 24).reshape(6, 4)

# 定义行索引和列名
row_index = np.arange(2001, 2007, 1).astype(str)
col_index = ['语文', '数学', '英语', '物理']

# 创建DataFrame
df1 = pd.DataFrame(
    data=data,
    index=row_index,
    columns=col_index
)
print(df1)
# 输出:
#       语文  数学  英语  物理
# 2001  67  93  99  18
# 2002  84  58  87  98
# 2003  97  48  13  93
# 2004  89  84  28  10
# 2005  94  72  84  45
# 2006  39  60  75  39

📝 方法2:从字典创建(推荐)

# 字典的key是列名,value是列数据
dic = {
    '姓名': ['lisa', 'cc', 'john', 'lili'],
    '年龄': [18, 21, 20, 19],
    '语文成绩': [98, 95, 59, 75]
}

df2 = pd.DataFrame(data=dic, index=[5, 6, 7, 8])
print(df2)
# 输出:
#     姓名  年龄  语文成绩
# 5  lisa  18    98
# 6    cc  21    95
# 7  john  20    59
# 8  lili  19    75

📝 方法3:从嵌套列表创建

# 每个子列表代表一行数据
data1 = [
    ['lisa', 18, 98],
    ['cc', 21, 95],
    ['john', 20, 59],
    ['lili', 19, 75]
]

df3 = pd.DataFrame(data=data1, columns=['姓名', '年龄', '语文成绩'])
print(df3)
# 输出:
#     姓名  年龄  语文成绩
# 0  lisa  18    98
# 1    cc  21    95
# 2  john  20    59
# 3  lili  19    75

💎 最佳实践

✅ 推荐:使用字典创建DataFrame(列名清晰)
df = pd.DataFrame({'name': ['A', 'B'], 'age': [20, 21]})

❌ 避免:使用嵌套列表但不指定列名
df = pd.DataFrame([['A', 20], ['B', 21]])  # 列名不清晰

5.3 DataFrame属性

📊 常用属性列表

属性说明示例
shape形状(行数, 列数)df.shape
ndim维度(固定为2)df.ndim
size元素总数df.size
dtypes每列的数据类型df.dtypes
index行索引对象df.index
columns列名对象df.columns
values值(NumPy数组)df.values

📝 代码示例

df1 = pd.DataFrame({
    '语文': [67, 84, 97],
    '数学': [93, 58, 48],
    '英语': [99, 87, 13]
}, index=['2001', '2002', '2003'])

print('df1的形状:', df1.shape)          # 输出:(3, 3)
print('df1的维度:', df1.ndim)           # 输出:2
print('df1的元素个数:', df1.size)       # 输出:9
print('df1的数据类型:\n', df1.dtypes)   
# 输出:
# 语文    int64
# 数学    int64
# 英语    int64

print('df1的行索引:', df1.index)        # 输出:Index(['2001', '2002', '2003'])
print('df1的列名:', df1.columns)        # 输出:Index(['语文', '数学', '英语'])
print('df1的值:\n', df1.values)
# 输出:
# [[67 93 99]
#  [84 58 87]
#  [97 48 13]]

5.4 DataFrame数据查询

5.4.1 查询列数据

💡 知识点:两种列访问方式

  1. 方括号访问df['列名']df[['列1', '列2']]
  2. 属性访问df.列名(仅适用于列名是合法Python标识符的情况)

📝 代码示例

df1 = pd.DataFrame({
    '语文': [67, 84, 97],
    '数学': [93, 58, 48],
    '英语': [99, 87, 13],
    '物理': [18, 98, 93]
}, index=['2001', '2002', '2003'])

# 查询单列(返回Series)
print(df1['语文'])
# 或
print(df1.语文)
# 输出:
# 2001    67
# 2002    84
# 2003    97

# 查询多列(返回DataFrame)
print(df1[['语文', '英语']])
# 输出:
#       语文  英语
# 2001  67  99
# 2002  84  87
# 2003  97  13

⚠️ 注意事项

  • 单列查询返回Series,多列查询返回DataFrame
  • 属性访问方式不能用于列名包含空格或特殊字符的情况
  • 多列查询必须使用双层方括号[[]]
5.4.2 查询行数据

💡 知识点:行切片
使用切片语法df[start:end:step]可以按行索引位置查询数据。

📝 代码示例

# 查询前两行
print(df1[0:2])
# 输出:
#       语文  数学  英语  物理
# 2001  67  93  99  18
# 2002  84  58  87  98

# 查询奇数行(0, 2, 4...)
print(df1[0:5:2])
# 输出:
#       语文  数学  英语  物理
# 2001  67  93  99  18
# 2003  97  48  13  93
5.4.3 iloc和loc定位

📌 核心概念

  • iloc:基于整数位置的索引(integer location),前闭后开
  • loc:基于标签的索引(label location),前闭后闭

🔍 对比说明

方法索引方式区间规则使用场景
iloc整数位置前闭后开[)按位置查询
loc标签名称前闭后闭[]按名称查询

📝 代码示例

df1 = pd.DataFrame({
    '语文': [67, 84, 97, 89, 94, 39],
    '数学': [93, 58, 48, 84, 72, 60],
    '英语': [99, 87, 13, 28, 84, 75],
    '物理': [18, 98, 93, 10, 45, 39]
}, index=['2001', '2002', '2003', '2004', '2005', '2006'])

# iloc:前两行,前两列
print(df1.iloc[0:2, 0:2])
# 输出:
#       语文  数学
# 2001  67  93
# 2002  84  58

# loc:前两行,前两列(都能取到)
print(df1.loc['2001':'2002', '语文':'英语'])
# 输出:
#       语文  数学  英语
# 2001  67  93  99
# 2002  84  58  87

# loc:使用列表指定具体的行和列
print(df1.loc[['2001', '2002'], ['语文', '英语']])
# 输出:
#       语文  英语
# 2001  67  99
# 2002  84  87
5.4.4 条件查询

💡 知识点:布尔索引
使用条件表达式创建布尔Series,然后用于筛选数据。

📝 代码示例

# 查询语文成绩大于60分的数据
print(df1[df1['语文'] > 60])
# 或
print(df1.loc[df1['语文'] > 60])
# 输出:
#       语文  数学  英语  物理
# 2001  67  93  99  18
# 2002  84  58  87  98
# 2003  97  48  13  93
# 2004  89  84  28  10
# 2005  94  72  84  45

# 查询Lisa的语文成绩
df2 = pd.DataFrame({
    '姓名': ['lisa', 'cc', 'john', 'lili'],
    '年龄': [18, 21, 20, 19],
    '语文成绩': [98, 95, 59, 75]
}, index=[5, 6, 7, 8])

result = df2.loc[df2['姓名'] == 'lisa', '语文成绩']
print(result)
# 输出:
# 5    98

💎 最佳实践

✅ 推荐:使用loc进行条件查询
df.loc[df['age'] > 18, ['name', 'score']]

❌ 避免:链式索引(可能产生警告)
df[df['age'] > 18]['name']  # 不推荐

5.5 DataFrame数据修改

5.5.1 新增列

📝 代码示例

df1 = pd.DataFrame({
    '语文': [67, 84, 97],
    '数学': [93, 58, 48],
    '英语': [99, 87, 13]
}, index=['2001', '2002', '2003'])

# 新增化学成绩列
np.random.seed(123)
df1['化学'] = np.random.randint(20, 100, 3)
print(df1)
# 输出:
#       语文  数学  英语  化学
# 2001  67  93  99  86
# 2002  84  58  87  98
# 2003  97  48  13  97

# 新增行总分列
df1['row_sum'] = df1.sum(axis=1)
print(df1)
# 输出:
#       语文  数学  英语  化学  row_sum
# 2001  67  93  99  86     345
# 2002  84  58  87  98     327
# 2003  97  48  13  97     255
5.5.2 新增行

📝 代码示例

# 新增一行数据
df1.loc['2004'] = [90, 60, 100, 50, 300]
print(df1)
# 输出:
#       语文  数学  英语  化学  row_sum
# 2001  67  93  99  86     345
# 2002  84  58  87  98     327
# 2003  97  48  13  97     255
# 2004  90  60 100  50     300

# 新增列总和行
df1.loc['col_sum'] = df1.sum(axis=0)
print(df1)
# 输出:
#          语文   数学   英语   化学  row_sum
# 2001      67   93   99   86      345
# 2002      84   58   87   98      327
# 2003      97   48   13   97      255
# 2004      90   60  100   50      300
# col_sum  338  259  299  331     1227
5.5.3 修改数据

📝 代码示例

df2 = pd.DataFrame({
    '姓名': ['lisa', 'cc', 'john', 'lili'],
    '年龄': [18, 21, 20, 19],
    '语文成绩': [98, 95, 59, 75]
}, index=[5, 6, 7, 8])

# 修改单个值
df2.loc[df2['姓名'] == 'lisa', '年龄'] = 20
print(df2)

# 修改整列数据
df2['年龄'] = df2['年龄'] + 1
print(df2)

# 修改特定条件的数据
df2.loc[df2['姓名'] == 'cc', '年龄'] += 1
print(df2)

5.6 综合案例

🎯 案例:学生信息管理

df2 = pd.DataFrame({
    '姓名': ['lisa', 'cc', 'john', 'lili'],
    '年龄': [18, 21, 20, 19],
    '语文成绩': [98, 95, 59, 75]
}, index=[5, 6, 7, 8])

# 1. 新增一行:id为9,lulu,20,98
df2.loc[9] = ['lulu', 20, 98]

# 2. 新增一列:性别
df2['性别'] = ['女', '男', '男', '女', '女']

# 3. 将年龄数据整体+1
df2['年龄'] = df2['年龄'] + 1

# 4. 打印列名
print('列名:', df2.columns)

# 5. 打印形状
print('形状:', df2.shape)

# 6. 找到cc的性别
cc_gender = df2.loc[df2['姓名'] == 'cc', '性别'].values
print('cc的性别:', cc_gender)

# 7. 找到所有女生的数据
female_students = df2[df2['性别'] == '女']
print('女生数据:\n', female_students)

# 8. 找到成绩大于80的学生姓名
high_score = df2.loc[df2['语文成绩'] > 80, '姓名'].values
print('成绩>80的学生:', high_score)

# 9. 找到第三行和第四行,以及第一列第三列数据
result = df2.iloc[2:4, 0:3:2]
# 或
result = df2.loc[[7, 8], ['姓名', '语文成绩']]
print(result)

# 10. 把cc的年龄加1
df2.loc[df2['姓名'] == 'cc', '年龄'] += 1

🔗 关联知识
→ 6. DataFrame高级操作
→ 7. 数据读取与存储


6. DataFrame高级操作

6.1 head()和tail() - 快速查看数据

🔧 函数:df.head() / df.tail()

📊 参数说明

参数类型说明默认值
nint返回的行数5

📝 代码示例

df2 = pd.DataFrame({
    '姓名': ['lisa', 'cc', 'john', 'lili'],
    '年龄': [18, 21, 20, 19],
    '语文成绩': [98, 95, 59, 75]
}, index=[5, 6, 7, 8])

# 查看前2行
print(df2.head(2))
# 输出:
#     姓名  年龄  语文成绩
# 5  lisa  18    98
# 6    cc  21    95

# 查看后2行
print(df2.tail(2))
# 输出:
#     姓名  年龄  语文成绩
# 7  john  20    59
# 8  lili  19    75

💎 最佳实践

✅ 推荐:读取大文件后先用head()查看数据结构
df = pd.read_csv('large_file.csv')
print(df.head())  # 快速了解数据格式

❌ 避免:直接打印整个DataFrame
print(df)  # 数据量大时会很慢

6.2 drop() - 删除数据

🔧 函数:df.drop()

📊 参数说明

参数类型说明默认值
labelsstr/list要删除的行/列标签必填
axisint0删除行,1删除列0
inplacebool是否在原数据上修改False

📝 代码示例

df2 = pd.DataFrame({
    '姓名': ['lisa', 'cc', 'john', 'lili'],
    '年龄': [18, 21, 20, 19],
    '语文成绩': [98, 95, 59, 75]
}, index=[5, 6, 7, 8])

# 删除列(不修改原数据)
result = df2.drop(labels='姓名', axis=1)
print(result)
# 输出:
#    年龄  语文成绩
# 5  18    98
# 6  21    95
# 7  20    59
# 8  19    75

# 删除行(直接修改原数据)
df2.drop(labels=[7, 8], axis=0, inplace=True)
print(df2)
# 输出:
#     姓名  年龄  语文成绩
# 5  lisa  18    98
# 6    cc  21    95

⚠️ 注意事项

  • inplace=False(默认):返回新DataFrame,不修改原数据
  • inplace=True:直接修改原数据,返回None
  • 删除多个行/列时,labels参数传入列表

6.3 sort_values() - 按值排序

🔧 函数:df.sort_values()

📊 参数说明

参数类型说明默认值
bystr/list排序依据的列名必填
ascendingboolTrue升序,False降序True
inplacebool是否在原数据上修改False

📝 代码示例

df2 = pd.DataFrame({
    '姓名': ['lisa', 'cc', 'john', 'lili'],
    '年龄': [18, 21, 20, 19],
    '语文成绩': [98, 95, 59, 75]
}, index=[5, 6, 7, 8])

# 按语文成绩降序排序
sorted_df = df2.sort_values(by='语文成绩', ascending=False)
print(sorted_df)
# 输出:
#     姓名  年龄  语文成绩
# 5  lisa  18    98
# 6    cc  21    95
# 8  lili  19    75
# 7  john  20    59

# 按多列排序
sorted_df = df2.sort_values(by=['年龄', '语文成绩'], ascending=[True, False])

6.4 sort_index() - 按索引排序

🔧 函数:df.sort_index()

📊 参数说明

参数类型说明默认值
axisint0按行索引,1按列名0
ascendingboolTrue升序,False降序True
inplacebool是否在原数据上修改False

📝 代码示例

df2 = pd.DataFrame({
    '姓名': ['lisa', 'cc', 'john', 'lili'],
    '年龄': [18, 21, 20, 19],
    '语文成绩': [98, 95, 59, 75]
}, index=[5, 6, 7, 8])

# 按行索引降序排序
sorted_df = df2.sort_index(axis=0, ascending=False)
print(sorted_df)
# 输出:
#     姓名  年龄  语文成绩
# 8  lili  19    75
# 7  john  20    59
# 6    cc  21    95
# 5  lisa  18    98

# 按列名排序
sorted_df = df2.sort_index(axis=1, ascending=True)

6.5 综合案例:学生成绩管理系统

🎯 案例背景

np.random.seed(123)
Score = pd.DataFrame({
    "Name": ["Nancy", "Jack", "Jim", "Lili", "Simon", "Tom", "Lilei", "Jerry"],
    "Python": np.random.randint(40, 100, 8),
    "Java": np.random.randint(40, 100, 8),
    "UI": np.random.randint(40, 100, 8),
    "Class": np.random.randint(1, 3, 8)
})

📝 任务1:班级映射

# 1. Class班级:1-A,2-B
dic_class = {1: 'A', 2: 'B'}
Score['Class'] = Score['Class'].map(dic_class)
print(Score)

📝 任务2:数据修改

# 2. Jack修改为John
Score.loc[Score['Name'] == 'Jack', 'Name'] = 'John'

# 3. Simon的Java分数修改为75
Score.loc[Score['Name'] == 'Simon', 'Java'] = 75

📝 任务3:数据分析

# 4. A班Python成绩均值
a_class_avg = Score.loc[Score['Class'] == 'A', 'Python'].mean()
print('A班Python均分:', a_class_avg)

# 5. 一共有几个班,每个班多少人
class_counts = Score['Class'].value_counts()
print('班级人数:\n', class_counts)

# 6. 得到UI大于80分的学生姓名
high_ui = Score.loc[Score['UI'] > 80, 'Name'].values
print('UI>80的学生:', high_ui)

📝 任务4:成绩处理

# 1. UI成绩全部加10分
Score['UI'] = Score['UI'] + 10

# 2. 新增四列:总分、均分、最大、最小
Score['总分'] = Score[['Python', 'Java', 'UI']].sum(axis=1)
Score['均分'] = Score[['Python', 'Java', 'UI']].mean(axis=1)
Score['最大'] = Score[['Python', 'Java', 'UI']].max(axis=1)
Score['最小'] = Score[['Python', 'Java', 'UI']].min(axis=1)

# 3. 得到3科都及格的学生信息
# 方法1:使用多个条件
passed = Score[(Score['Python'] >= 60) & (Score['Java'] >= 60) & (Score['UI'] >= 60)]

# 方法2:使用最小值
passed = Score[Score['最小'] >= 60]

# 方法3:使用all()函数(推荐)
mask = (Score.iloc[:, 1:4] > 60).all(axis=1)
passed = Score[mask]
print('三科都及格的学生:\n', passed)

# 4. Tom的Class改为A
Score.loc[Score['Name'] == 'Tom', 'Class'] = 'A'

# 5. 按照总分从大到小排序
Score = Score.sort_values(by='总分', ascending=False)
print(Score)

💡 知识点:all()函数

  • all(axis=1):对每一行进行逻辑与运算
  • 所有值都为True时,结果才为True
  • 常用于检查多个条件是否同时满足

🔗 关联知识
→ 7. 数据读取与存储
→ 4. Series其他常用方法


7. 数据读取与存储

7.1 读取CSV文件

🔧 函数:pd.read_csv()

📊 常用参数说明

参数类型说明默认值
filepath_or_bufferstr文件路径必填
encodingstr文件编码(UTF-8/GBK/GB2312)None
sepstr分隔符‘,’
headerint哪一行作为列名0
nameslist自定义列名None
usecolslist只读取指定列None
index_colint/str指定某列为行索引None
nrowsint读取前n行None
skiprowsint/list跳过前n行None

📝 代码示例:基础读取

import pandas as pd

# 基础读取
df = pd.read_csv(
    filepath_or_buffer='data/HR.csv',
    encoding='GB2312'
)
print(df.head())

💡 知识点:CSV vs Excel

特性CSVExcel
文件类型纯文本二进制
分隔符逗号-
数据表单个多个sheet
体积
功能仅数据图表/公式/格式
加载速度
适用场景日志/原始数据/备份财务报表/商业分析

7.2 检测文件编码

🔧 工具:chardet库

📝 代码示例

import chardet

# 检测文件编码
with open('data/HR.csv', 'rb') as f:
    result = chardet.detect(f.read(1000))  # 读取前1000字节判断

print('文件编码:', result['encoding'])
# 输出:GB2312

⚠️ 常见编码问题

  • UTF-8:国际通用,支持所有字符
  • GBK/GB2312:中文编码,Windows中文系统常用
  • ISO-8859-1:西欧字符编码

💎 最佳实践

✅ 推荐:先检测编码再读取
import chardet
with open('file.csv', 'rb') as f:
    encoding = chardet.detect(f.read(1000))['encoding']
df = pd.read_csv('file.csv', encoding=encoding)

❌ 避免:盲目尝试不同编码
df = pd.read_csv('file.csv', encoding='utf-8')  # 可能报错

7.3 高级读取参数

📝 代码示例:指定列和行

# 只读取指定列
df = pd.read_csv(
    'data/HR.csv',
    encoding='GB2312',
    usecols=['员工满意度', '项目数量', '部门']
)

# 指定某列为行索引
df = pd.read_csv(
    'data/HR.csv',
    encoding='GB2312',
    index_col=0  # 第一列作为行索引
)

# 读取前100行
df = pd.read_csv(
    'data/HR.csv',
    encoding='GB2312',
    nrows=100
)

# 跳过前5行
df = pd.read_csv(
    'data/HR.csv',
    encoding='GB2312',
    skiprows=5
)

# 自定义列名
df = pd.read_csv(
    'data/HR.csv',
    encoding='GB2312',
    header=None,  # 不使用第一行作为列名
    names=['col1', 'col2', 'col3']  # 自定义列名
)

7.4 HR数据分析案例

🎯 数据字段说明

  1. 员工满意度:员工打的分数
  2. 考核评分:领导给的分数
  3. 项目数量:负责几个项目
  4. 每月在公司工作时间:平均值
  5. 司龄:在公司第几年
  6. 工作事故:0没有,1有
  7. 是否离职:0没有,1离职
  8. 五年内是否升职:0没有,1有
  9. 部门:所在部门
  10. 薪水:低/中/高

📝 分析任务

df = pd.read_csv('data/HR.csv', encoding='GB2312')

# 1. 打印数据列名
print('列名:', df.columns)

# 2. 求公司员工满意度的均值
avg_satisfaction = df['员工满意度'].mean()
print('员工满意度均值:', avg_satisfaction)

# 3. 求公司的员工离职率
turnover_rate = df['是否离职'].value_counts() / df.shape[0]
print('离职率:\n', turnover_rate)
# 或
turnover_rate = df.loc[df['是否离职'] == 1, '是否离职'].count() / df['是否离职'].count()

# 4. 都有哪些部门,每个部门多少人
dept_counts = df['部门'].value_counts()
print('各部门人数:\n', dept_counts)

# 5. 工作时长的最大值、最小值、均值
print('工作时长最大值:', df['每月在公司工作时间'].max())
print('工作时长最小值:', df['每月在公司工作时间'].min())
print('工作时长均值:', df['每月在公司工作时间'].mean())

# 6. 薪水的占比情况
salary_ratio = df['薪水'].value_counts(normalize=True)
print('薪水占比:\n', salary_ratio)

# 7. 销售部门员工项目数量的均值
sales_avg = df.loc[df['部门'] == 'sales', '项目数量'].mean()
print('销售部门项目数量均值:', sales_avg)

# 8. 每月在公司工作时间>250,得到部门和项目数量两列数据
result = df.loc[df['每月在公司工作时间'] > 250, ['部门', '项目数量']]
print(result)

7.5 保存CSV文件

🔧 函数:df.to_csv()

📊 常用参数说明

参数类型说明默认值
path_or_bufstr保存路径必填
sepstr分隔符‘,’
indexbool是否保存行索引True
headerbool是否保存列名True
columnslist保存指定列None
encodingstr文件编码‘utf-8’

📝 代码示例

stu = pd.DataFrame({
    '姓名': ['张三', '李四', '王五'],
    '年龄': [18, 19, 17],
    '成绩': [80, 70, 99]
}, index=['No1', 'No3', 'No2'])

# 保存到CSV(包含行索引)
stu.to_csv(path_or_buf='data/stu.csv')

# 保存到CSV(不包含行索引)
stu.to_csv(path_or_buf='data/stu.csv', index=False)

# 保存指定列
stu.to_csv(
    path_or_buf='data/stu.csv',
    columns=['姓名', '成绩'],
    index=False
)

7.6 读取Excel文件

🔧 函数:pd.read_excel()

⚠️ 注意事项
需要先安装openpyxl库:

pip install openpyxl -i https://repo.huaweicloud.com/repository/pypi/simple/

📝 代码示例

# 读取Excel文件
df2 = pd.read_excel('data/students.xlsx')
print(df2)

# 读取指定sheet
df2 = pd.read_excel('data/students.xlsx', sheet_name='Sheet1')

# 读取多个sheet
dfs = pd.read_excel('data/students.xlsx', sheet_name=None)  # 返回字典

7.7 保存Excel文件

🔧 函数:df.to_excel()

📝 代码示例

df2 = pd.DataFrame({
    '姓名': ['张三', '李四', '王五', '赵六'],
    '年龄': [18, 19, 17, 20],
    '成绩': [80, 70, 99, 85],
    '性别': ['男', '女', '男', '男']
})

# 修改数据
df2.loc[df2['姓名'] == '张三', '年龄'] = 20
df2.loc[df2['姓名'] == '赵六', '成绩'] = 98
df2.loc[df2['姓名'] == '李四', '性别'] = '男'

# 保存到Excel
df2.to_excel(excel_writer='data/new_stu.xlsx', index=False)

# 保存到指定sheet
df2.to_excel(
    excel_writer='data/new_stu.xlsx',
    sheet_name='学生信息',
    index=False
)

🔗 关联知识
→ 8. 数据库连接
→ 5. DataFrame详解


8. 数据库连接

8.1 连接MySQL数据库

🔧 工具:pymysql库

⚠️ 注意事项
需要先安装pymysql库:

pip install pymysql

📝 代码示例:建立连接

import pymysql
import pandas as pd
import warnings
warnings.filterwarnings('ignore')

# 建立数据库连接
conn = pymysql.connect(
    host='localhost',      # 数据库IP地址
    port=3306,             # 端口号
    user='root',           # 用户名
    password='123456',     # 密码
    charset='utf8',        # 字符编码
    database='games_db'    # 数据库名
)

print('连接成功:', conn)

📊 连接参数说明

参数说明示例
host数据库服务器地址‘localhost’ / ‘192.168.1.100’
port端口号3306(MySQL默认)
user用户名‘root’
password密码‘123456’
charset字符编码‘utf8’ / ‘utf8mb4’
database数据库名‘test_db’

8.2 读取数据库数据

🔧 函数:pd.read_sql()

📊 参数说明

参数类型说明
sqlstrSQL查询语句
conconnection数据库连接对象
index_colstr指定某列为行索引
parse_dateslist解析为日期的列

📝 代码示例

# 读取整张表
df = pd.read_sql('SELECT * FROM sanguo', conn)
print(df)

# 条件查询
df = pd.read_sql('SELECT name, country FROM sanguo WHERE country="蜀国"', conn)
print(df)

# 聚合查询
df = pd.read_sql('SELECT country, COUNT(*) as count FROM sanguo GROUP BY country', conn)
print(df)

# 关闭连接
conn.close()

💡 知识点:SQL基础语句

-- 查询所有数据
SELECT * FROM table_name;

-- 条件查询
SELECT column1, column2 FROM table_name WHERE condition;

-- 排序
SELECT * FROM table_name ORDER BY column_name DESC;

-- 分组统计
SELECT column_name, COUNT(*) FROM table_name GROUP BY column_name;

-- 限制返回行数
SELECT * FROM table_name LIMIT 10;

8.3 完整工作流程

📝 代码示例:完整流程

import pymysql
import pandas as pd

# 1. 建立连接
conn = pymysql.connect(
    host='localhost',
    port=3306,
    user='root',
    password='123456',
    charset='utf8',
    database='games_db'
)

# 2. 读取数据
df = pd.read_sql('SELECT * FROM sanguo', conn)

# 3. 数据分析
print('数据形状:', df.shape)
print('前5行:\n', df.head())
print('数据类型:\n', df.dtypes)

# 4. 数据处理
# ... 进行各种数据分析和处理 ...

# 5. 关闭连接
conn.close()

⚠️ 注意事项

  • 使用完数据库后要记得关闭连接
  • 敏感信息(密码)不要硬编码在代码中
  • 大数据量查询时注意内存占用
  • 使用参数化查询防止SQL注入

💎 最佳实践

✅ 推荐:使用上下文管理器自动关闭连接
with pymysql.connect(...) as conn:
    df = pd.read_sql('SELECT * FROM table', conn)
# 连接自动关闭

❌ 避免:忘记关闭连接
conn = pymysql.connect(...)
df = pd.read_sql('SELECT * FROM table', conn)
# 忘记conn.close(),可能导致连接泄漏

📚 知识点速查表

📊 核心知识点思维导图

Pandas数据分析
├── 1. 核心数据结构 ⭐
│   ├── Series(一维)
│   │   ├── 创建:pd.Series(data, index, dtype, name)
│   │   ├── 属性:index, values, dtype, shape, size, ndim
│   │   ├── 访问:位置索引[0]、标签索引['label']
│   │   └── 统计:mean(), sum(), max(), min(), std()
│   │
│   └── DataFrame(二维)
│       ├── 创建:pd.DataFrame(data, index, columns)
│       ├── 属性:index, columns, values, shape, dtypes, ndim, size
│       ├── 查询:df['col'], df.loc[], df.iloc[], df[condition]
│       └── 修改:df['col']=value, df.loc[]=value
│
├── 2. Series字符串操作 ⭐⭐
│   ├── 基础方法
│   │   ├── str.strip() - 去除首尾字符
│   │   ├── str.split() - 字符串分割
│   │   ├── str.replace() - 字符串替换
│   │   └── str[0:3] - 字符串切片
│   │
│   └── 高级方法
│       ├── str.contains() - 包含检查(支持正则)
│       ├── str.count() - 统计出现次数
│       ├── str.len() - 计算字符串长度
│       └── str.find() - 查找子串位置
│
├── 3. Series数据处理 ⭐⭐
│   ├── 成员检查
│   │   ├── isin() - 检查是否在列表中
│   │   └── 布尔索引 - series[condition]
│   │
│   ├── 去重统计
│   │   ├── unique() - 返回唯一值数组
│   │   ├── nunique() - 返回唯一值数量
│   │   └── value_counts() - 分类计数(支持normalize)
│   │
│   └── 数据转换
│       ├── map() - 映射转换(字典/函数)
│       └── shift() - 数据偏移(计算环比)
│
├── 4. DataFrame查询 ⭐⭐⭐
│   ├── 列查询
│   │   ├── df['col'] - 单列(返回Series)
│   │   ├── df[['col1','col2']] - 多列(返回DataFrame)
│   │   └── df.col - 属性访问(仅合法标识符)
│   │
│   ├── 行查询
│   │   ├── df[0:2] - 切片查询
│   │   ├── df.iloc[0:2, 0:2] - 位置索引(前闭后开)
│   │   └── df.loc['a':'b', 'col1':'col2'] - 标签索引(前闭后闭)
│   │
│   └── 条件查询
│       ├── df[df['col'] > 60] - 单条件
│       ├── df[(df['col1']>60) & (df['col2']<90)] - 多条件
│       └── df.loc[condition, ['col1','col2']] - 指定列
│
├── 5. DataFrame修改 ⭐⭐⭐
│   ├── 新增数据
│   │   ├── df['new_col'] = values - 新增列
│   │   ├── df.loc['new_row'] = values - 新增行
│   │   └── df['sum'] = df.sum(axis=1) - 计算列
│   │
│   ├── 修改数据
│   │   ├── df['col'] = df['col'] + 1 - 整列修改
│   │   ├── df.loc[condition, 'col'] = value - 条件修改
│   │   └── df.loc[index, 'col'] = value - 单值修改
│   │
│   └── 删除数据
│       ├── df.drop(labels, axis=0) - 删除行
│       ├── df.drop(labels, axis=1) - 删除列
│       └── inplace=True - 直接修改原数据
│
├── 6. DataFrame高级操作 ⭐⭐
│   ├── 查看数据
│   │   ├── df.head(n) - 查看前n行
│   │   ├── df.tail(n) - 查看后n行
│   │   └── df.info() - 查看数据信息
│   │
│   ├── 排序操作
│   │   ├── df.sort_values(by='col') - 按值排序
│   │   ├── df.sort_index() - 按索引排序
│   │   └── ascending=False - 降序排列
│   │
│   └── 统计分析
│       ├── df.describe() - 描述性统计
│       ├── df.sum(axis=0/1) - 求和(按列/行)
│       ├── df.mean(axis=0/1) - 平均值
│       └── df.max()/min() - 最大/最小值
│
├── 7. 数据读取与存储 ⭐⭐⭐
│   ├── CSV文件
│   │   ├── pd.read_csv(path, encoding, sep, header)
│   │   ├── df.to_csv(path, index, encoding)
│   │   └── 编码检测:chardet.detect()
│   │
│   ├── Excel文件
│   │   ├── pd.read_excel(path, sheet_name)
│   │   ├── df.to_excel(path, sheet_name, index)
│   │   └── 需要:pip install openpyxl
│   │
│   └── 高级参数
│       ├── usecols - 指定读取列
│       ├── nrows - 读取前n行
│       ├── skiprows - 跳过前n行
│       └── index_col - 指定索引列
│
└── 8. 数据库连接 ⭐⭐
    ├── MySQL连接
    │   ├── pymysql.connect() - 建立连接
    │   ├── pd.read_sql(sql, conn) - 读取数据
    │   └── conn.close() - 关闭连接
    │
    └── SQL查询
        ├── SELECT * FROM table - 查询所有
        ├── WHERE condition - 条件筛选
        ├── ORDER BY col DESC - 排序
        └── GROUP BY col - 分组统计

📋 函数速查表

Series创建与属性
函数/属性语法说明优先级
pd.Series()pd.Series(data, index, dtype, name)创建Series
ndims.ndim维度(固定为1)
shapes.shape形状(元素个数,)
sizes.size元素总数
dtypes.dtype数据类型
indexs.index行索引对象
valuess.values值(NumPy数组)
Series字符串方法
方法语法说明优先级
str.strip()s.str.strip('chars')去除首尾指定字符⭐⭐
str.split()s.str.split('-', expand=True)字符串分割(expand展开为DataFrame)⭐⭐⭐
str.replace()s.str.replace('old', 'new')字符串替换⭐⭐⭐
str.contains()s.str.contains('pattern', case=False)包含检查(支持正则)⭐⭐⭐
str.count()s.str.count('substring')统计子串出现次数⭐⭐
str.len()s.str.len()计算字符串长度⭐⭐
str.find()s.str.find('substring')查找子串位置(-1表示未找到)
str[start:end]s.str[0:3]字符串切片⭐⭐
Series数据处理方法
方法语法说明优先级
isin()s.isin(['value1', 'value2'])成员检查⭐⭐⭐
unique()s.unique()返回唯一值数组⭐⭐⭐
nunique()s.nunique()返回唯一值数量⭐⭐
value_counts()s.value_counts(normalize=True)分类计数(normalize返回占比)⭐⭐⭐
map()s.map({1:'A', 2:'B'})映射转换(字典或函数)⭐⭐⭐
shift()s.shift(1)数据偏移(正数向下,负数向上)⭐⭐
Series统计方法
方法语法说明优先级
sum()s.sum()求和
mean()s.mean()平均值
std()s.std(ddof=1)标准差(ddof=1为样本标准差)
min()s.min()最小值
max()s.max()最大值
DataFrame创建与属性
函数/属性语法说明优先级
pd.DataFrame()pd.DataFrame(data, index, columns)创建DataFrame
shapedf.shape形状(行数, 列数)
ndimdf.ndim维度(固定为2)
sizedf.size元素总数
dtypesdf.dtypes每列的数据类型
indexdf.index行索引对象
columnsdf.columns列名对象
valuesdf.values值(NumPy数组)
DataFrame查询方法
方法语法说明优先级
列查询df['col']df[['col1','col2']]单列返回Series,多列返回DataFrame⭐⭐⭐
行切片df[0:2]按位置切片查询行⭐⭐
ilocdf.iloc[0:2, 0:2]位置索引(前闭后开)⭐⭐⭐
locdf.loc['a':'b', 'col1':'col2']标签索引(前闭后闭)⭐⭐⭐
条件查询df[df['col'] > 60]布尔索引筛选⭐⭐⭐
head()df.head(n)查看前n行(默认5)⭐⭐⭐
tail()df.tail(n)查看后n行(默认5)⭐⭐⭐
DataFrame修改方法
方法语法说明优先级
新增列df['new_col'] = values添加新列⭐⭐⭐
新增行df.loc['new_row'] = values添加新行⭐⭐⭐
修改数据df.loc[condition, 'col'] = value条件修改⭐⭐⭐
drop()df.drop(labels, axis=0/1, inplace=True)删除行/列⭐⭐
DataFrame排序方法
方法语法说明优先级
sort_values()df.sort_values(by='col', ascending=False)按值排序⭐⭐⭐
sort_index()df.sort_index(axis=0, ascending=True)按索引排序⭐⭐
DataFrame统计方法
方法语法说明支持axis优先级
sum()df.sum(axis=0/1)求和
mean()df.mean(axis=0/1)平均值
std()df.std(axis=0/1)标准差⭐⭐
min()df.min(axis=0/1)最小值
max()df.max(axis=0/1)最大值
describe()df.describe()描述性统计⭐⭐
数据读取函数
函数语法常用参数优先级
pd.read_csv()pd.read_csv(path, encoding, sep, header, usecols, nrows)encoding, usecols, nrows⭐⭐⭐
pd.read_excel()pd.read_excel(path, sheet_name)sheet_name⭐⭐⭐
pd.read_sql()pd.read_sql(sql, conn)sql, conn⭐⭐
数据存储函数
函数语法常用参数优先级
df.to_csv()df.to_csv(path, index=False, encoding='utf-8')index, encoding⭐⭐⭐
df.to_excel()df.to_excel(path, sheet_name, index=False)sheet_name, index⭐⭐⭐
df.to_sql()df.to_sql(table_name, conn)table_name, conn⭐⭐

⚠️ 常见错误与解决方案

错误类型错误示例正确写法说明
字符串方法s.strip()s.str.strip()必须使用.str访问器
多列查询df['col1', 'col2']df[['col1', 'col2']]多列需要双层方括号
逻辑运算df[df['a']>60 and df['b']<90]df[(df['a']>60) & (df['b']<90)]使用&且加括号
loc vs ilocdf.loc[0:2, 0:2]df.iloc[0:2, 0:2]loc用标签,iloc用位置
链式索引df[df['a']>60]['b']df.loc[df['a']>60, 'b']避免链式索引警告
inplace参数df = df.drop('col', axis=1)df.drop('col', axis=1, inplace=True)理解inplace含义

📖 参考资源

  • 官方文档:https://pandas.pydata.org/docs/
  • 中文教程:https://www.pypandas.cn/
  • 在线练习:https://www.kaggle.com/learn/pandas
  • 视频教程:https://www.bilibili.com/(搜索Pandas教程)

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐