本系列是对Python for Data Analysis第三版的整理,个人目的仅是进一步熟悉Python以及学习NumPy、pandas等库。

    忽略了原书的大部分API介绍,仅保留了部分基础API。

    作者提供了在线电子版https://wesmckinney.com/book,以及相关代码https://github.com/wesm/pydata-book。不适应英文原文的可以选择有中文翻译的第二版https://www.jianshu.com/p/04d180d90a3f,或者纸质书《利用Python进行数据分析》。


第1章 准备工作    

1.1 基本的Python库

    NumPy一直以来是Python中数值计算的基石,提供了该领域大部分的数据结构、算法和胶水库。pandas提供高级数据结构与功能,针对结构化或表格数据。matplotlib是用于数据可视化的最流行的 Python 库。

    IPython是交互式Python解释器;Jupyter基于前者,是一个针对交互式与探索性计算的高效环境。本书提供的示例代码全部使用Jupyter。

    SciPy 是解决科学计算中许多基本问题的软件包集合。scikit-learn是通用机器学习工具包。statsmodels是一个统计分析包,包含经典统计和计量经济学的算法。


1.2 安装与设置

    Python、conda的安装不再赘述。

    Jupyter的安装与自动格式化,需要首先(创建并进入conda环境)在命令行下输入以下命令,然后在弹出的网页中找到Setting-Advanced Setting Editor-Jupyterlab Code Formatter,选中Auto format config。

pip install black jupyterlab jupyterlab-code-formatter jupyterlab-spellchecker
jupyter lab

    第2章与第3章主要介绍Python基础语法、内置数据结构等,这里直接跳过。如果对Python基础语法不太熟悉的可以看网上各类教程,例如https://www.liaoxuefeng.com/wiki/1016959663602400,以及本公众号之前的Effective Python系列。


第4章 NumPy基础:数组和矢量化计算

    之所以不用Python内置数据结构,而用NumPy这样的数值计算包,很大程度是因为:NumPy基于C,计算速度比纯Python代码更快;NumPy的数组操作是在连续的内存块中进行的,而内置数据结构有额外的开销。

    NumPy的核心特性之一是多维数组ndarray。

import numpy as np
# 创建ndarray
data = np.array([[1.5, -0.1, 3], [0, -3, 6.5]])
assert data.ndim == 2
assert data.shape == (2, 3)
# 常用工厂函数
data = np.arange(10)
data = np.zeros((2, 3, 2))
# 数据类型dtype
arr = np.array([1, 2, 3, 4, 5])
assert arr.dtype == np.int32
float_arr = arr.astype(np.float64)

    元素级操作:

arr * arr
1 / arr
arr**2
z = np.sqrt(xs ** 2 + ys ** 2)
arr = np.exp(arr)
arr = np.maximum(x, y)
arr = np.where(arr > 0, arr * 2, -2)

    保存与读取:

arr = np.arange(10)
np.save("some_array", arr)
np.load("some_array.npy")
np.savez("array_archive.npz", a=arr, b=arr)

    线性代数:

# 转置
arr.T
# 点乘
x.dot(y)
np.dot(x, y)
x @ np.ones(3)
# 逆矩阵
from numpy.linalg import inv, qr
inv(arr)

    最后,以模拟随机运动为例:

# 随机数生成器
rng = np.random.default_rng(seed=12345) 
# 生成1000个1、-1
draws = rng.integers(0, 2, size=1000)
steps = np.where(draws == 0, 1, -1)
# 模拟结果
walk = steps.cumsum()
walk.min()
walk.max()

第5章 pandas入门

    Series是一维数组对象,包含一系列索引与数据。

import numpy as np
import pandas as pd
from pandas import Series
obj = pd.Series([4, 7, -5, 3], index=["d", "b", "a", "c"])
print(obj.array)
print(obj.index)
print(obj.to_dict())
assert obj["d"] == 4

    DataFrame代表一个矩形数据表,可以看作存储着索引相同的Series的字典。

python read_csv chunksize 预加载_python

from pandas import DataFrame
data = {
    "state": ["Ohio", "Ohio", "Ohio", "Nevada", "Nevada", "Nevada"],
    "year": [2000, 2001, 2002, 2001, 2002, 2003],
    "pop": [1.5, 1.7, 3.6, 2.4, 2.9, 3.2],
}
frame = pd.DataFrame(data)
assert "state" in frame.columns
assert 0 in frame.index
# 查询列
frame["state"]
frame.year
# 查询行
frame2.loc[1]
frame2.iloc[2]
# 删除列
del frame["frame"]

    与ndarray类似,Series与DataFrame同样支持各种基础操作以及数学与统计方法。这里不再一一介绍了,后文实际例子中遇到时再逐个讲解;有兴趣的可以自己读pandas文档。


第6章 数据加载、存储和文件格式

    pandas中有许多旨在将文本转化为DataFrame对象的函数,例如read_csv、read_excel等等。它们的可选参数包括:索引,类型推断和数据转换,日期和时间解析,迭代,脏数据问题,

    首先,以csv文件为例:

# 没有标题行
pd.read_csv("examples/ex2.csv", header=None)
# 自定义标题行
pd.read_csv("examples/ex2.csv", names=["a", "b","message"])
# 自定义分隔符,取代默认的逗号
result = pd.read_csv("examples/ex3.txt", sep="\s+")
# 迭代处理大文件
chunker = pd.read_csv("examples/ex6.csv", chunksize=1000)
for piece in chunker:
    ...
# 写入文件
data.to_csv("examples/out.csv")

    有时read_csv不足以满足需求,需要手动处理。以下是处理流程的简单示例:

import csv
with open("examples/ex7.csv") as f:
    lines = list(csv.reader(f))
header, values = lines[0], lines[1:]
# zip函数同时迭代两个迭代器
data_dict = {h: v for h, v in zip(header, zip(*values))}

    接下来考虑JSON文件:

import json
result = json.loads(obj)
asjson = json.dumps(result)
data = pd.read_json("examples/example.json")
data.to_json(sys.stdout)

    其余的二进制文件、xml、html、excel、web api、database基本上全都换汤不换药。这里不再赘述,有需要时再查即可。


第7章 数据清理与准备

    在进行数据分析和建模的过程中,大量时间都花在数据准备上。有时,数据存储在文件或数据库中的方式不适合特定任务。pandas提供了一组高级、灵活且快速的工具,能够将数据操作成正确的形式。

    首先考虑缺失值的情况:

float_data = pd.Series([1.2, -3.5, np.nan, 0])
# 返回一个布尔Series,代表每一项是否是NA
float_data.isna()
float_data.notna()
# 去除所有NA
float_data.dropna()
# 将NA替换为其他值
float_data.fillna(0)

    接下来考虑数据转换:

# 重复
data.duplicated()
data.drop_duplicates()
# 映射
def get_animal(x):
    return ...
data["animal"] = data["food"].map(get_animal)
# 替换
data.replace(-999, np.nan)
# 过滤
col[col.abs() > 3]

    此外,还有一些字符串操作:

val = "a,b,  guido"
# 以逗号分隔,去除首尾空格
pieces = [x.strip() for x in val.split(",")]
# 以::连接
"::".join(pieces)
val.index(",") == 1
val.find(":") == -1
val.count(",")
val.replace(",", "::")
# 正则表达式操作这里不再介绍
# pandas也有字符串处理
data.str[:5]
data.str.contains("gmail")
pattern = r"([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\.([A-Z]{2,4})"
data.str.findall(pattern, flags=re.IGNORECASE)
data.str.extract(pattern, flags=re.IGNORECASE)

    扩展数据类型、分类数据部分略过。