什么是Pandas
在Python的江湖中,如果说NumPy是内功心法,那Pandas就是降龙十八掌——简单粗暴,一招制敌。
不管你是做数据分析的表哥表姐,还是搞深度学习的炼丹师,Pandas都是你绑定的新手装备。它底层用C实现(所以别问为什么快,问就是C的功劳),提供了一堆让你"少掉头发"的数据处理API。
简单来说:没有Pandas,你的数据处理代码会像意大利面一样——又长又乱还容易断。
Pandas的两大数据结构
Pandas的核心就两个数据结构,记住它们,你就掌握了Pandas的半壁江山:
| 数据结构 | 一句话解释 | 类比 |
|---|---|---|
| Series | 带标签的一维数组 | Excel的一列 |
| DataFrame | 带标签的二维表格 | Excel的整张表 |
import pandas as pd
from pandas import Series, DataFrame
# Series: 就是一列数据
s = Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])
print(s)
# a 1
# b 2
# c 3
# d 4
# DataFrame: 就是一张表
df = DataFrame({
'name': ['张三', '李四', '王五'],
'age': [25, 30, 35],
'salary': [10000, 20000, 30000]
})
print(df)
# name age salary
# 0 张三 25 10000
# 1 李四 30 20000
# 2 王五 35 30000💡 记忆技巧:Series是"系列",DataFrame是"数据框"。一个是一维的,一个是二维的。就这么简单,别想复杂了。
Pandas的奇技淫巧
这部分是重点,建议反复观看,考试要考。
1. 删除异常数据
现实世界的数据就像你的代码——总有bug。空值、重复值、异常值,三座大山压在每个数据工程师头上。
# 删除包含空值的行(简单粗暴)
df.dropna()
# 只删除某些列为空的行(精准打击)
df.dropna(subset=['name', 'age'])
# 删除重复行
df.drop_duplicates()
# 按某些列去重(保留最后一条)
df.drop_duplicates(['card_bin', 'card_len'], keep='last')
# 条件删除:删除年龄小于0的异常数据(除非你在统计穿越者)
df = df[df['age'] >= 0]
# 组合条件删除:删除国家为AE且银行名为空的数据
df = df[~((df['cc'] == 'AE') & (df['bank_name'].isna()))]
# 或者用query,更优雅
df = df.query("not (cc == 'AE' and bank_name != bank_name)")2. 补全缺失数据
有时候删除太暴力,我们需要温柔地填补空白。
# 用固定值填充
df['currency'].fillna('16', inplace=True)
# 用均值填充(适合数值型)
df['age'].fillna(df['age'].mean(), inplace=True)
# 用前一个值填充(适合时间序列)
df['price'].fillna(method='ffill', inplace=True)
# 用后一个值填充
df['price'].fillna(method='bfill', inplace=True)
# 不同列用不同策略填充(骚操作)
df.fillna({
'name': '佚名',
'age': df['age'].median(),
'salary': 0
}, inplace=True)3. 数据类型转换
Pandas读进来的数据类型经常不是你想要的,需要手动调教。
# 转换单列
df['age'] = df['age'].astype(int)
# 转换多列
df = df.astype({'age': int, 'salary': float})
# 字符串转日期(常用!)
df['date'] = pd.to_datetime(df['date'])
# 处理转换失败的情况(errors='coerce'会把失败的转成NaN)
df['amount'] = pd.to_numeric(df['amount'], errors='coerce')4. 数据筛选的N种姿势
# 基础筛选
df[df['age'] > 25]
# 多条件筛选(注意括号!)
df[(df['age'] > 25) & (df['salary'] > 15000)]
# isin筛选(适合枚举值)
df[df['country'].isin(['CN', 'US', 'UK'])]
# query方法(写起来更像SQL)
df.query("age > 25 and salary > 15000")
# loc和iloc的区别
df.loc[0:5, ['name', 'age']] # 按标签,包含结束位置
df.iloc[0:5, [0, 1]] # 按位置,不包含结束位置Pandas的相关库
Pandas不是一个人在战斗,它有一群好基友:
NumPy —— 矩阵计算扛把子
Pandas的底层就是NumPy数组。如果你要做矩阵运算、线性代数,NumPy是你的不二之选。
import numpy as np
# Pandas和NumPy无缝衔接
df['age'].values # 返回NumPy数组
np.mean(df['age']) # NumPy函数直接用Matplotlib / Seaborn —— 可视化双雄
数据分析不画图,等于没分析。
import matplotlib.pyplot as plt
# Pandas内置绑定了Matplotlib
df['salary'].plot(kind='hist')
df.plot(x='age', y='salary', kind='scatter')
plt.show()Scikit-learn —— 机器学习老大哥
当你用Pandas处理完数据,下一步就是喂给模型。Scikit-learn和Pandas配合得天衣无缝。
Pandas实战:卡BIN数据分析
理论说一万遍,不如实战来一遍。
背景
卡BIN是支付行业的重要数据,通过卡号前6-8位可以识别发卡行、卡组织、国家等信息。这类数据动辄几十万条,手写循环分析?等你跑完黄花菜都凉了。
样例数据(分号分隔):
457186;VISA/DANKORT;NETS;DEBIT;CLASSIC;DENMARK;DK;DNK;208;HTTP://WWW.TELLER.COM/;915 08 989;16;PERSONAL;N字段说明:
| 序号 | 字段名 | 说明 | 特殊规则 |
|---|---|---|---|
| 1 | card_bin | 卡BIN | - |
| 2 | card_brand | 卡组织 | - |
| 3 | bank_name | 银行名 | 若国家为AE,银行名为空则舍弃;其他国家银行名为空保留 |
| 4 | drcr | 借记/贷记 | - |
| 5 | class | 卡级别 | - |
| 6 | country_name | 国家名 | - |
| 7 | cc | 国家二字码 | - |
| 8 | cc3 | 国家三字码 | - |
| 9 | currency | 币种 | 若为空,默认值16 |
| 10 | website | 网站 | - |
| 11 | phone_no | 银行电话 | - |
| 12 | card_len | 卡号长度 | - |
| 13 | person | 个人/公司 | - |
| 14 | unknown | 未知 | - |
实战代码
Step 1: 读取数据并抽样
import pandas as pd
file_path = "/opt/file/dataset/bins_all.csv"
# 读取CSV数据
# sep=';' 指定分隔符
# header=None 原文件没有表头
# dtype=str 所有字段按字符串读取(避免卡BIN被当成数字丢失前导零)
df = pd.read_csv(
file_path,
sep=';',
header=None,
index_col=False,
names=['card_bin', 'card_brand', 'bank_name', 'drcr', 'class',
'country_name', 'cc', 'cc3', 'currency', 'website',
'phone_no', 'card_len', 'person', 'unknown'],
dtype=str
)
# 看看数据长啥样
print(f"总数据量: {len(df)}")
df.head()
# 随机抽样5000条用于分析(大数据集先抽样是好习惯)
df_sample = df.sample(5000)
df_sample.to_csv("/opt/file/dataset/bins_analysis.csv", index=False)Step 2: 数据清洗
# 1. 删除重复数据(card_bin + card_len 确定唯一记录)
df_clean = df.drop_duplicates(['card_bin', 'card_len'], keep='last')
print(f"去重后: {len(df_clean)} 条")
# 2. 处理AE国家的特殊规则:cc为AE时,bank_name不能为空
# 翻译成人话:删除 (cc == 'AE') & (bank_name为空) 的行
df_clean = df_clean[~((df_clean['cc'] == 'AE') & (df_clean['bank_name'].isna()))]
# 或者用这种写法,更直观
# df_clean = df_clean.query("not (cc == 'AE' and bank_name != bank_name)")
print(f"处理AE规则后: {len(df_clean)} 条")
# 3. 填充currency的默认值
df_clean['currency'] = df_clean['currency'].fillna('16')
# 4. 查看清洗结果
print(df_clean.info())
print(df_clean.describe())Step 3: 数据分析
# 按卡组织统计
print("=== 卡组织分布 ===")
print(df_clean['card_brand'].value_counts().head(10))
# 按国家统计
print("\n=== 国家分布 TOP 10 ===")
print(df_clean['cc'].value_counts().head(10))
# 交叉统计:各国家的卡组织分布
print("\n=== 各国卡组织分布 ===")
cross_tab = pd.crosstab(df_clean['cc'], df_clean['card_brand'])
print(cross_tab.head(10))
# 分组聚合:各卡组织的借记/贷记比例
print("\n=== 各卡组织借贷比例 ===")
print(df_clean.groupby(['card_brand', 'drcr']).size().unstack(fill_value=0))Pandas在Java中的替代品
Python不是万能的,有时候你不得不用Java(比如你的老板要求,比如你的项目是Java栈)。
Java中模仿Pandas的库主要有两个:
| 库名 | 特点 | 成熟度 |
|---|---|---|
| Joinery | 主要实现DataFrame,API风格接近Pandas | ⭐⭐ |
| Tablesaw | 侧重数据可视化,图表功能强 | ⭐⭐⭐ |
⚠️ 忠告:这两个库的知名度和成熟度都远逊于Pandas。如果可以,请坚定地选择Python。
Joinery vs Pandas 性能对比
测试环境:110MB CSV文件
| 测试场景 | Joinery (秒) | Pandas (秒) | 结论 |
|---|---|---|---|
| 删除无效和重复数据 | 411 | 586 | Joinery略胜 |
| 100次全量读取并describe | 603 | 270 | Pandas快一倍 |
| 50次读取并value_counts | 411 | 174 | Pandas快一倍 |
结论:
- Joinery在简单的数据清洗场景下还行
- 但涉及统计分析(describe、value_counts),Pandas完胜
- Joinery的describe还缺少25%/50%/75%分位数,功能不全
建议:除非万不得已,否则别用Java做数据分析。真的,相信我。
常见坑点 & 避坑指南
坑1:链式赋值警告
# ❌ 错误写法(会有SettingWithCopyWarning)
df[df['age'] > 25]['salary'] = 0
# ✅ 正确写法
df.loc[df['age'] > 25, 'salary'] = 0坑2:inplace参数的迷惑行为
# inplace=True 不返回值,直接修改原DataFrame
df.drop_duplicates(inplace=True) # df被修改,返回None
# inplace=False(默认)返回新DataFrame,原DataFrame不变
df_new = df.drop_duplicates() # df不变,df_new是新的坑3:读取大文件内存爆炸
# 分块读取大文件
chunks = pd.read_csv('huge_file.csv', chunksize=100000)
for chunk in chunks:
process(chunk) # 分块处理
# 或者只读取需要的列
df = pd.read_csv('huge_file.csv', usecols=['col1', 'col2'])坑4:日期解析的玄学
# 让Pandas自动解析日期
df = pd.read_csv('data.csv', parse_dates=['date_column'])
# 指定日期格式(更快更准)
df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d')总结
Pandas就像一把瑞士军刀:
- 功能强大,但你可能只用到10%
- 入门简单,精通需要时间
- 遇到问题,先Google/Stack Overflow
从入门到放弃?不,是从入门到真香!
参考资料
- 📖 《深入浅出Pandas:利用Python进行数据处理与分析》
- 📖 《利用Python进行数据分析》(Wes McKinney著,Pandas作者亲笔)
- 🔗 Pandas官方文档
- 🔗 Pandas教程 - 盖若
- 🔗 Table转换工具
如果这篇文章对你有帮助,请给作者点个赞。如果没有帮助……那一定是你打开的方式不对。 😏