从零开始的数据分析之旅
Pandas是Python数据分析的核心库,提供了两种主要数据结构:Series(一维)和DataFrame(二维)。DataFrame就像Excel表格或SQL表,但强大得多——支持复杂的数据操作、分析和可视化。
import pandas as pd
import numpy as np
# 从字典创建
df = pd.DataFrame({
'姓名': ['张三', '李四', '王五', '赵六', '孙七'],
'年龄': [22, 25, 28, 22, 30],
'成绩': [85, 92, 78, 95, 88],
'城市': ['北京', '上海', '广州', '北京', '深圳']
})
# 从NumPy创建
df2 = pd.DataFrame(np.random.randn(5, 3), columns=list('ABC'))
# 从列表创建
df3 = pd.DataFrame([
{'姓名': '张三', '成绩': 85},
{'姓名': '李四', '成绩': 92}
])
| 方法 | 索引类型 | 语法 | 特点 |
|---|---|---|---|
loc | 标签索引 | df.loc[行标签, 列标签] | 包含末端 |
iloc | 位置索引 | df.iloc[行号, 列号] | 不包含末端 |
[] | 列选择 | df['列名'] | 返回Series |
[[]] | 多列选择 | df[['列1','列2']] | 返回DataFrame |
# loc: 按标签选择(包含末端!)
df.loc[0:2, ['姓名', '成绩']] # 行0到2,姓名和成绩列
# iloc: 按位置选择(不包含末端!)
df.iloc[1:3, 0:2] # 行1到2,前两列
# 条件过滤
df[df['成绩'] >= 90] # 成绩>=90的行
df[(df['城市'] == '北京') & (df['年龄'] == 22)] # 多条件
# isin过滤
df[df['城市'].isin(['北京', '上海'])]
loc切片包含末端,iloc切片不包含末端!这是Pandas最常见的陷阱之一。# 按值排序
df.sort_values('成绩', ascending=False) # 降序
# 按索引排序
df.sort_index()
# 多列排序
df.sort_values(['城市', '成绩'], ascending=[True, False])
# 快速统计摘要
df.describe()
# 单列统计
df['成绩'].mean() # 均值
df['成绩'].median() # 中位数
df['成绩'].std() # 标准差
# 值计数
df['城市'].value_counts()
# 唯一值
df['城市'].unique() # 返回数组
df['城市'].nunique() # 唯一值数量
# 自定义函数应用
df['等级'] = df['成绩'].apply(
lambda x: 'A' if x >= 90 else 'B' if x >= 80 else 'C'
)
# 多列操作
df['评级'] = df.apply(
lambda row: '优秀' if row['成绩'] >= 90 and row['年龄'] < 25 else '良好',
axis=1
)
import pandas as pd
# Series运算(对齐索引)
s_a = pd.Series([1, 2, 3], index=['a', 'b', 'c'])
s_b = pd.Series([10, 20, 30], index=['b', 'c', 'd'])
result = s_a + s_b # 索引对齐,不匹配为NaN
# 常用方法
print(s_a.values) # numpy数组
print(s_a.index) # 索引对象
print(s_a.describe()) # 统计摘要
# CSV
df = pd.read_csv('data.csv')
df.to_csv('output.csv', index=False)
# Excel
df = pd.read_excel('data.xlsx', sheet_name='Sheet1')
df.to_excel('output.xlsx')
# JSON
df = pd.read_json('data.json')
df.to_json('output.json', orient='records', force_ascii=False)
# SQL
from sqlalchemy import create_engine
engine = create_engine('sqlite:///db.db')
df = pd.read_sql('SELECT * FROM table', engine)
# 读取选项
df = pd.read_csv('data.csv',
encoding='utf-8',
usecols=['A', 'B'], # 只读指定列
nrows=1000, # 只读前N行
dtype={'age': int}, # 指定类型
parse_dates=['date'], # 解析日期
chunksize=10000) # 分块读取
chunksize分块,或dtype指定类型减少内存。用df.info(memory_usage='deep')查看实际内存。#!/usr/bin/env python3
# Pandas基础 — 完整实战
import pandas as pd
import numpy as np
# ============ DataFrame创建 ============
df = pd.DataFrame({
'姓名': ['张三', '李四', '王五', '赵六', '孙七'],
'年龄': [22, 25, 28, 22, 30],
'成绩': [85, 92, 78, 95, 88],
'城市': ['北京', '上海', '广州', '北京', '深圳']
})
print(f"DataFrame:\n{df}")
print(f"形状: {df.shape}")
print(f"数据类型:\n{df.dtypes}")
# ============ 数据选择 ============
print(f"\nloc选择:\n{df.loc[0:2, ['姓名', '成绩']]}")
print(f"\niloc选择:\n{df.iloc[1:3, 0:2]}")
# ============ 过滤 ============
print(f"\n北京学生:\n{df[df['城市'] == '北京']}")
print(f"\n高分学生:\n{df[df['成绩'] >= 90]}")
# ============ 排序 ============
print(f"\n按成绩排序:\n{df.sort_values('成绩', ascending=False)}")
# ============ 统计 ============
print(f"\n描述统计:\n{df.describe()}")
print(f"\n城市分布:\n{df['城市'].value_counts()}")
# ============ apply ============
df['等级'] = df['成绩'].apply(lambda x: 'A' if x >= 90 else 'B' if x >= 80 else 'C')
print(f"\n添加等级列:\n{df}")
print("\n✅ Python验证通过 — DataFrame创建/选择/过滤")
| 操作 | Pandas | SQL |
|---|---|---|
| 选择列 | df[['A','B']] | SELECT A, B |
| 过滤 | df[df.A > 0] | WHERE A > 0 |
| 排序 | df.sort_values('A') | ORDER BY A |
| 分组 | df.groupby('A').mean() | GROUP BY A |
| 连接 | pd.merge(df1, df2) | JOIN |
| 去重 | df.drop_duplicates() | DISTINCT |
| 限制行数 | df.head(10) | LIMIT 10 |
| 聚合 | df.agg({'A':'mean'}) | AVG(A) |
df[df['列'] > 值],多条件用&和|describe()是你对数据的第一次"体检"apply()是最灵活的列操作——但能不用就不用(向量化更快)
# 常见操作速查
df['新列'] = df['旧列'] * 2 # 新增列
df = df.rename(columns={'旧':'新'}) # 重命名
df = df.drop(columns=['列名']) # 删除列
df = df.drop(index=[0,1]) # 删除行
df['列'] = df['列'].astype(float) # 类型转换
df = df.set_index('列名') # 设置索引
df = df.reset_index() # 重置索引
df = df.replace({旧值: 新值}) # 值替换
chunksize分块读取 ②用dtype指定类型节省内存 ③用usecols只读需要的列 ④用parse_dates直接解析日期。对于GB级数据,考虑Dask或Vaex。df[df>0]['A']=1会触发SettingWithCopyWarning ②inplace=True在新版Pandas中可能不生效 ③df.ix已废弃,用loc或iloc ④df['A']返回Series,df[['A']]返回DataFrame。