Python 数据分析详解(第一期):环境搭建与核心库基础
数据分析的核心是 “从数据中提取价值”,而 Python 凭借其丰富的库生态、简洁的语法,成为数据分析领域的主流工具。第一期我们聚焦 “基础准备”—— 从环境搭建到核心库(NumPy、Pandas)的核心用法,为后续分析打下坚实基础。
一、数据分析环境搭建:Anaconda + Jupyter Notebook
新手最容易踩的坑是 “库版本冲突”,而Anaconda(开源 Python 发行版)能一次性解决环境管理和库安装问题,建议优先使用。
1.1 Anaconda 安装步骤(跨平台通用)
步骤 1:下载 Anaconda
- 官网地址:https://www.anaconda.com/products/distribution(建议选择 “Anaconda Individual Edition”,免费且足够用)
- 版本选择:根据系统(Windows/macOS/Linux)选择对应安装包,Python 版本优先选 3.9~3.11(兼容性最好,避免过新版本的库适配问题)。
步骤 2:安装 Anaconda
- Windows:双击安装包,注意两个关键选项(必选!):
- “Add Anaconda3 to my PATH environment variable”(添加环境变量,否则命令行无法调用 conda)
- “Register Anaconda3 as my default Python 3.x”(设为默认 Python)
- macOS:拖入 “应用程序” 文件夹即可,安装后需打开 “终端” 执行
conda init zsh
(若用默认终端)初始化环境。
步骤 3:验证安装
- 打开 “Anaconda Prompt”(Windows)或 “终端”(macOS/Linux),输入以下命令,若显示版本号则安装成功:
conda --version # 查看conda版本,如conda 23.10.0 python --version # 查看Python版本,如Python 3.10.12
1.2 启动 Jupyter Notebook(数据分析首选工具)
Jupyter Notebook 是交互式开发工具,支持 “代码块 + 文本注释 + 结果展示” 一体化,非常适合数据分析的 “边写边调试” 场景。
启动步骤:
- 打开 “Anaconda Prompt”/“终端”,输入命令:
jupyter notebook
- 自动打开浏览器,进入 Jupyter 界面(默认地址:http://localhost:8888),左侧是电脑文件目录。
- 新建 Notebook:点击右上角 “New”→选择 “Python 3”,会生成一个名为 “Untitled.ipynb” 的文件(可重命名,如 “第一期数据分析基础.ipynb”)。
Notebook 基础操作:
- 单元格类型:默认 “Code”(代码),可通过上方菜单栏 “Cell”→“Cell Type” 切换为 “Markdown”(文本注释,支持 Markdown 语法)。
- 运行代码:选中代码单元格,按
Shift+Enter
(运行并新建下一个单元格)或Ctrl+Enter
(仅运行当前单元格)。 - 保存文件:点击左上角 “保存” 图标,或按
Ctrl+S
。
二、核心库 1:NumPy—— 数值计算的基石
NumPy(Numerical Python)是 Python 数据分析的 “底层引擎”,提供了高效的多维数组(ndarray) 和数学运算函数,解决了 Python 原生列表运算效率低的问题。
2.1 NumPy 安装(Anaconda 用户可跳过)
若未用 Anaconda,需手动安装:
pip install numpy # 终端/命令行执行,建议指定版本:pip install numpy==1.26.4
在 Notebook 中验证安装:
import numpy as np # 导入NumPy,约定别名np(行业通用)
print(np.__version__) # 查看版本,如1.26.4
2.2 核心概念:ndarray(多维数组)
ndarray 是 NumPy 的核心数据结构,可理解为 “统一数据类型的多维容器”,比 Python 列表快 10~100 倍(底层用 C 实现,避免 Python 循环的开销)。
2.2.1 创建 ndarray(5 种常用方式)
方式 1:从 Python 列表 / 元组转换(最基础)
# 1维数组(列表→ndarray)
list1 = [1, 2, 3, 4, 5]
arr1 = np.array(list1)
print("1维数组:", arr1) # 输出:[1 2 3 4 5](注意元素间无逗号,是ndarray特征)
print("维度:", arr1.ndim) # 输出:1(ndim属性:数组维度)# 2维数组(列表嵌套列表→ndarray,需保证子列表长度一致)
list2 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
arr2 = np.array(list2)
print("2维数组:\n", arr2) # 输出2行3列的矩阵
print("形状:", arr2.shape) # 输出:(3, 3)(shape属性:(行数, 列数),n维数组则为(n1, n2, ..., nk))
方式 2:创建特殊数组(zeros/ones/eye/arange/linspace)
# 1. 全0数组(指定形状,默认数据类型float)
zeros_arr = np.zeros((2, 3)) # 形状(2行3列)
print("全0数组:\n", zeros_arr)
# 若需整数类型,指定dtype参数:np.zeros((2,3), dtype=int)# 2. 全1数组
ones_arr = np.ones((3, 2), dtype=int) # 3行2列整数数组
print("全1数组:\n", ones_arr)# 3. 单位矩阵(n阶方阵,对角线为1,其余为0)
eye_arr = np.eye(3) # 3阶单位矩阵
print("单位矩阵:\n", eye_arr)# 4. 等差数组(类似range,但返回ndarray)
arange_arr = np.arange(1, 10, 2) # 起始=1,终止=10(不包含),步长=2
print("等差数组:", arange_arr) # 输出:[1 3 5 7 9]# 5. 等间隔数组(指定元素个数,而非步长)
linspace_arr = np.linspace(0, 10, 5) # 起始=0,终止=10(包含),元素个数=5
print("等间隔数组:", linspace_arr) # 输出:[ 0. 2.5 5. 7.5 10. ]
2.2.2 ndarray 的核心属性(4 个必记)
属性名 | 含义 | 示例(arr2 是 2 维数组 (3,3)) |
---|---|---|
ndim | 数组维度(秩) | arr2.ndim → 2 |
shape | 数组形状(n1,n2,...nk) | arr2.shape → (3,3) |
size | 数组总元素个数 | arr2.size → 9 |
dtype | 数组数据类型 | arr2.dtype → int64(默认根据输入推断) |
修改形状示例(reshape,需保证总元素个数不变):
arr = np.arange(12) # 1维数组,size=12
arr_reshape1 = arr.reshape(3, 4) # 改为3行4列(3*4=12)
arr_reshape2 = arr.reshape(2, 2, 3) # 改为3维数组(2*2*3=12)
print("3维数组形状:", arr_reshape2.shape) # 输出:(2,2,3)
2.2.3 ndarray 的基本运算(无需循环,直接广播)
NumPy 的核心优势是 “向量化运算”—— 对数组整体操作,无需写 for 循环,效率极高。
1. 数组与标量的运算(广播到所有元素)
arr = np.array([1, 2, 3, 4])
print("加2:", arr + 2) # 输出:[3 4 5 6]
print("乘3:", arr * 3) # 输出:[3 6 9 12]
print("平方:", arr ** 2) # 输出:[ 1 4 9 16]
print("开方:", np.sqrt(arr)) # 输出:[1. 1.4142 1.732 2. ](需用np.sqrt函数)
2. 数组与数组的运算(对应元素运算,需形状一致)
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
print("加法:", arr1 + arr2) # 输出:[5 7 9]
print("乘法(对应元素乘,非矩阵乘法):", arr1 * arr2) # 输出:[4 10 18]
3. 矩阵乘法(需用@
或np.dot()
)
# 矩阵A:2行3列,矩阵B:3行2列(A的列数=B的行数,才可相乘)
A = np.array([[1, 2, 3], [4, 5, 6]])
B = np.array([[7, 8], [9, 10], [11, 12]])
print("矩阵乘法(@):\n", A @ B) # 结果为2行2列
# 等价于:np.dot(A, B)
2.2.4 ndarray 的索引与切片(取数据的核心)
索引:取单个元素;切片:取连续 / 指定范围的元素(类似 Python 列表,但支持多维)。
1. 1 维数组(与 Python 列表完全一致)
arr = np.arange(10) # [0 1 2 3 4 5 6 7 8 9]
print("索引取第3个元素(从0开始):", arr[2]) # 输出:2
print("切片取第2到第5个元素(左闭右开):", arr[1:5]) # 输出:[1 2 3 4]
print("切片步长2:", arr[0:10:2]) # 输出:[0 2 4 6 8]
print("反向取数:", arr[-3:]) # 输出:[7 8 9](最后3个元素)
2. 2 维数组(行索引在前,列索引在后,用逗号分隔)
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) # 3行3列数组
# 1. 取单个元素:第2行第3列(行索引1,列索引2)
print("单个元素:", arr[1, 2]) # 输出:6# 2. 取整行:第1行(索引0)
print("第1行:", arr[0]) # 输出:[1 2 3]
# 取第2-3行(索引1到2)
print("第2-3行:\n", arr[1:3])# 3. 取整列:第2列(索引1)
print("第2列:", arr[:, 1]) # 输出:[2 5 8](:表示“所有行”)
# 取第1-2列(索引0到1)
print("第1-2列:\n", arr[:, 0:2])# 4. 取子矩阵:第2-3行,第2-3列
print("子矩阵:\n", arr[1:3, 1:3]) # 输出:[[5 6],[8 9]]# 5. 布尔索引(按条件筛选,非常常用!)
# 筛选出所有大于5的元素
mask = arr > 5 # 生成布尔数组:True表示满足条件
print("布尔掩码:\n", mask)
print("筛选结果:", arr[mask]) # 输出:[6 7 8 9](自动转为1维数组)
三、核心库 2:Pandas—— 表格数据处理神器
Pandas 基于 NumPy 开发,专门用于结构化数据(表格型数据,如 Excel、CSV) 的处理,核心数据结构是Series
(1 维表格)和DataFrame
(2 维表格,类似 Excel 工作表)。
3.1 Pandas 安装(Anaconda 用户可跳过)
pip install pandas # 手动安装,建议版本:pandas==2.1.4
在 Notebook 中验证安装:
python
import pandas as pd # 导入Pandas,约定别名pd(行业通用)
print(pd.__version__) # 查看版本,如2.1.4
3.2 核心结构 1:Series(1 维表格)
Series 是 “带标签的 1 维数组”—— 相比 NumPy 的 1 维 ndarray,多了 “索引(index)”,可理解为 “一列数据 + 一列行标签”。
3.2.1 创建 Series(3 种常用方式)
方式 1:从列表创建(默认索引为 0,1,2,...)
data = [10, 20, 30, 40]
s1 = pd.Series(data)
print("Series 1:\n", s1)
# 输出:
# 0 10
# 1 20
# 2 30
# 3 40
# dtype: int64(数据类型)
方式 2:指定自定义索引
data = [10, 20, 30, 40]
index = ["a", "b", "c", "d"] # 自定义索引(标签)
s2 = pd.Series(data, index=index)
print("Series 2:\n", s2)
# 输出:
# a 10
# b 20
# c 30
# d 40
# dtype: int64
方式 3:从字典创建(字典的 key 为索引,value 为数据)
data_dict = {"a": 10, "b": 20, "c": 30, "d": 40}
s3 = pd.Series(data_dict)
print("Series 3:\n", s3) # 结果与s2一致
3.2.2 Series 的核心属性与方法
属性 / 方法 | 含义 | 示例(s2 是带索引 [a,b,c,d] 的 Series) |
---|---|---|
values | 提取数据(返回 ndarray) | s2.values → array([10,20,30,40]) |
index | 提取索引(返回 Index 对象) | s2.index → Index(['a','b','c','d'], dtype='object') |
dtype | 数据类型 | s2.dtype → int64 |
head(n) | 查看前 n 个元素(默认 n=5) | s2.head (2) → 显示 a 和 b 的元素 |
tail(n) | 查看后 n 个元素(默认 n=5) | s2.tail (1) → 显示 d 的元素 |
describe() | 描述性统计(计数、均值、标准差等) | s2.describe () → 输出 count=4, mean=25, std=12.91 等 |
示例代码:
print("Series数据:", s2.values)
print("前2个元素:\n", s2.head(2))
print("描述性统计:\n", s2.describe())
3.2.3 Series 的索引与切片(比 NumPy 更灵活)
s = pd.Series([10,20,30,40], index=["a","b","c","d"])
# 1. 按索引标签取元素(推荐,更直观)
print("按标签'a'取:", s["a"]) # 输出:10
print("按标签'b'和'd'取(列表传入):\n", s[["b", "d"]])# 2. 按位置取元素(用iloc[],类似NumPy的索引)
print("按位置0取:", s.iloc[0]) # 输出:10(位置从0开始)
print("按位置1-2取:", s.iloc[1:3]) # 输出:b=20, c=30# 3. 条件筛选(类似NumPy的布尔索引)
print("大于20的元素:\n", s[s > 20]) # 输出:c=30, d=40
3.3 核心结构 2:DataFrame(2 维表格,重点!)
DataFrame 是 “带标签的 2 维表格”—— 可理解为 “多个 Series 共享同一个索引(行标签)”,对应 Excel 中的 “工作表” 或 SQL 中的 “表”,是 Pandas 最核心、最常用的结构。
3.3.1 创建 DataFrame(4 种常用方式)
方式 1:从字典创建(最常用,字典 key 为列名,value 为列数据)
# 字典的每个key是列名,value是该列的列表数据
data_dict = {"姓名": ["张三", "李四", "王五", "赵六"],"年龄": [22, 25, 23, 24],"性别": ["男", "男", "女", "男"],"成绩": [85, 92, 78, 90]
}
df1 = pd.DataFrame(data_dict)
print("DataFrame 1:\n", df1)
# 输出:
# 姓名 年龄 性别 成绩
# 0 张三 22 男 85
# 1 李四 25 男 92
# 2 王五 23 女 78
# 3 赵六 24 男 90
方式 2:从列表嵌套列表创建(需指定列名)
data_list = [["张三", 22, "男", 85],["李四", 25, "男", 92],["王五", 23, "女", 78],["赵六", 24, "男", 90]
]
columns = ["姓名", "年龄", "性别", "成绩"] # 指定列名
df2 = pd.DataFrame(data_list, columns=columns)
print("DataFrame 2:\n", df2) # 结果与df1一致
方式 3:从外部文件读取(实战最常用,以 CSV 为例)
CSV(逗号分隔值)是数据分析中最常见的文件格式,Pandas 用read_csv()
读取:
# 读取本地CSV文件(需指定文件路径,相对路径/绝对路径均可)
# 示例:若CSV文件与Notebook在同一文件夹,直接写文件名
df = pd.read_csv("student_scores.csv") # 替换为你的CSV文件名# 若需读取Excel文件,需先安装openpyxl:pip install openpyxl
# df_excel = pd.read_excel("student_scores.xlsx", sheet_name="Sheet1")
方式 4:从 NumPy 数组创建(需指定列名)
arr = np.array([["张三", 22, "男", 85],["李四", 25, "男", 92]
])
df3 = pd.DataFrame(arr, columns=["姓名", "年龄", "性别", "成绩"])
print("DataFrame 3:\n", df3)
3.3.2 DataFrame 的核心属性与方法(必记)
属性 / 方法 | 含义 | 示例(df1 是学生成绩表) |
---|---|---|
shape | 表格形状(行数,列数) | df1.shape → (4,4) |
columns | 列名(返回 Index 对象) | df1.columns → Index ([' 姓名 ',' 年龄 ',' 性别 ',' 成绩 '], dtype='object') |
index | 行索引(默认 0,1,2,...) | df1.index → RangeIndex(start=0, stop=4, step=1) |
info() | 数据基本信息(列类型、非空值数量) | df1.info() → 显示 4 列,每列非空值 4 个,年龄 / 成绩是 int64 |
describe() | 数值型列的描述性统计(计数、均值、最值等) | df1.describe () → 仅显示年龄、成绩的统计信息(姓名、性别是字符串,不参与) |
head(n) | 查看前 n 行(默认 5 行) | df1.head (2) → 显示前 2 行数据 |
tail(n) | 查看后 n 行(默认 5 行) | df1.tail (1) → 显示最后 1 行数据 |
示例代码:
print("表格形状:", df1.shape)
print("数据基本信息:\n", df1.info())
print("数值列统计:\n", df1.describe())
3.3.3 DataFrame 的列操作(取列、增列、删列)
1. 取列(两种方式,推荐第一种)
# 方式1:按列名取(df["列名"],返回Series)
age_col = df1["年龄"]
print("年龄列(Series):\n", age_col)# 方式2:按属性取(df.列名,仅当列名无空格时可用)
score_col = df1.成绩
print("成绩列(Series):\n", score_col)# 取多列(传入列名列表,返回DataFrame)
name_age_col = df1[["姓名", "年龄"]]
print("姓名+年龄列(DataFrame):\n", name_age_col)
2. 增列(直接赋值新列名)
# 新增“等级”列:根据成绩判断(>=90为A,>=80为B,否则为C)
df1["等级"] = df1["成绩"].apply(lambda x: "A" if x >= 90 else ("B" if x >= 80 else "C")
)
print("新增等级列后:\n", df1)# 新增“年龄+5”列(基于已有列计算)
df1["年龄+5"] = df1["年龄"] + 5
print("新增年龄+5列后:\n", df1)
3. 删列(用 drop (),指定 axis=1 表示删列)
# 方式1:修改原DataFrame(inplace=True表示在原数据上删除)
df1.drop("年龄+5", axis=1, inplace=True)
print("删除年龄+5列后:\n", df1)# 方式2:不修改原DataFrame,返回新DataFrame(不写inplace=True)
df_new = df1.drop("等级", axis=1)
print("新DataFrame(删除等级列):\n", df_new)
3.3.4 DataFrame 的行操作(取行、筛选行、排序行)
1. 按索引取行(用 loc [] 按行标签,iloc [] 按位置)
# loc[]:按行标签取行(默认标签是0,1,2,...)
row0 = df1.loc[0] # 取第1行(标签0),返回Series
print("第1行(loc):\n", row0)# 取多行(传入标签列表)
row0_2 = df1.loc[[0, 2]] # 取标签0和2的行
print("第1、3行(loc):\n", row0_2)# iloc[]:按位置取行(与标签无关,位置从0开始)
row1 = df1.iloc[1] # 取第2行(位置1)
print("第2行(iloc):\n", row1)# 取连续行(切片)
row1_3 = df1.iloc[1:3] # 取位置1到2的行(左闭右开)
print("第2、3行(iloc):\n", row1_3)
2. 按条件筛选行(核心操作,类似 SQL 的 WHERE)
# 条件1:筛选成绩>=90的行
high_score = df1[df1["成绩"] >= 90]
print("成绩>=90的行:\n", high_score)# 条件2:筛选性别为“男”且年龄<25的行(多条件用&,且每个条件加括号)
male_young = df1[(df1["性别"] == "男") & (df1["年龄"] < 25)]
print("男且年龄<25的行:\n", male_young)# 条件3:筛选姓名为“张三”或“王五”的行(多条件用|)
name_filter = df1[(df1["姓名"] == "张三") | (df1["姓名"] == "王五")]
print("姓名是张三或王五的行:\n", name_filter)
3. 按列排序(用 sort_values ())
# 按“成绩”降序排序(ascending=False表示降序,默认True升序)
df_sorted = df1.sort_values("成绩", ascending=False)
print("按成绩降序排序:\n", df_sorted)# 按“年龄”升序+“成绩”降序排序(多列排序,传入列名列表)
df_sorted2 = df1.sort_values(["年龄", "成绩"], ascending=[True, False])
print("按年龄升序、成绩降序排序:\n", df_sorted2)