pandas
库不仅提供了强大的数据结构,还内置了丰富的数学和统计方法,以及灵活的数据处理和分析工具。这些功能使得数据汇总、探索、清洗和特征工程变得高效且直观。
pandas
对象(Series 和 DataFrame)拥有一组常用的数学和统计方法,它们属于汇总统计(summary statistics)。这些方法可以对 Series 进行汇总计算(如求均值、最大值),或者对 DataFrame 的行或列进行汇总计算,并返回一个 Series 或 DataFrame。
1.简单统计指标
这些方法用于计算数据集中最基本的统计量,帮助我们快速了解数据的中心趋势、离散程度和范围。
df.count(axis=0, level=None, numeric_only=False)
:- 计算非
NA
(非缺失)值的数量。 axis
: 默认为0
(按列计算),也可以设置为1
(按行计算)。numeric_only
: 仅计算数值列。
- 计算非
df.max(axis=0, skipna=True, level=None)
:- 计算最大值。
skipna
: 默认为True
,表示在计算时跳过NA
值。
df.min(axis=0, skipna=True, level=None)
:- 计算最小值。
df.median(axis=0, skipna=True, level=None)
:- 计算中位数(数据的中间值)。
df.sum(axis=0, skipna=True, level=None)
:- 计算总和。
df.mean(axis=0, skipna=True, level=None)
:- 计算算术平均值。
df.quantile(q=0.5, axis=0, numeric_only=True)
:- 计算分位数。
q
可以是单个浮点数(0到1之间)或浮点数列表。例如,q=0.5
是中位数,q=[0.25, 0.75]
是四分位数。
- 计算分位数。
df.describe(percentiles=None, include=None, exclude=None)
:- 生成数值型列的汇总统计信息,包括非
NA
计数、平均值、标准差、最小值、四分位数(25%、50%、75%)和最大值。 - 对于非数值型(如对象或分类)列,它会显示计数、唯一值数量和出现频率最高的项。
- 生成数值型列的汇总统计信息,包括非
pandas
的这些统计方法在底层依赖于NumPy
的高度优化实现。它们通过矢量化操作,直接在 C 语言层面执行计算,从而避免了 Python 循环的开销,确保了在大数据集上的高性能。
axis
参数: 决定了计算是沿着行进行(axis=1
,对每行求统计量)还是沿着列进行(axis=0
,对每列求统计量)。skipna
参数: 这些函数默认会跳过NaN
值。这意味着在计算均值、总和等时,NaN
值不会被包含在计算中,也不会导致结果为NaN
(除非所有值都是NaN
)。describe()
的原理:describe()
方法会根据列的数据类型,自动选择合适的统计量进行计算。对于数值列,它会调用count()
,mean()
,std()
,min()
,quantile()
,max()
等内部方法。
level
参数与多层索引
当 DataFrame 具有多层索引(MultiIndex)时,这些统计方法还可以使用 level
参数,对指定索引级别的数据进行分组聚合。例如,df.mean(level='Student_ID')
可以计算每个学生的平均分,即使数据是按学生和科目分层的。
【1】非NaN的数量:
1
2
3
4
5
6
data = np.random.randint(0, 101, (10, 3))
df = pd.DataFrame(data=data, index=list("ABCDEFGHIJ"), columns=["python", "java", "golang"])
df.iloc[5, 0] = np.nan
df.iloc[9, 1] = np.nan
display(df)
df.count()
【2】轴0 的最大值:
1
df.max(axis=0)
不加axis=0也可以,因为是默认的:
1
df.max()
【3】中位数:
1
df.median()
【4】求和:
1
df.sum()
【5】每行的均值:(轴1的均值)
1
df.mean(axis=1)
【6】分位数:
1
df.quantile(q=[0.2, 0.4, 0.8])
【7】查看数值型列的汇总统计:
1
df.describe()
【8】有MultiIndex时使用level参数:
1
2
3
4
5
data = np.random.randint(0, 100, (6, 2))
index = pd.MultiIndex.from_product([["A", "B", "C"], ["Q1", "Q2"]])
df_multi = pd.DataFrame(data=data, index=index, columns=["Sales", "Profit"])
display(df_multi)
df_multi["Sales"].groupby(level=-1).mean()
1
df_multi["Sales"].groupby(level=0).mean()
选择题
-
给定
s = pd.Series([1, 2, np.nan, 4])
,执行s.count()
的结果是什么?A. 4
B. 3
C. 2
D. 1
答案:B
-
以下哪个方法会返回 DataFrame 中所有数值型列的均值、标准差、最小值、四分位数和最大值?
A.
df.mean()
B.
df.describe()
C.
df.info()
D.
df.sum()
答案:B,
df.info()
: 返回 DataFrame 的结构信息(如列名、数据类型、非空计数),不包含统计信息。
2.索引标签、位置获取
除了获取统计值本身,我们还经常需要找出这些统计值在数组中的位置(索引或标签)。
Series.argmin(axis=None, skipna=True)
:- 计算 Series 中最小值的整数位置(索引)。
- 如果 Series 中有多个最小值,返回第一个出现的最小值的位置。
Series.argmax(axis=None, skipna=True)
:- 计算 Series 中最大值的整数位置(索引)。
df.idxmax(axis=0, skipna=True)
:- 计算 DataFrame 中每个列(或行)的最大值对应的索引标签。
- 返回一个 Series,其索引是原始 DataFrame 的列名(或行索引),值是最大值所在的索引标签。
df.idxmin(axis=0, skipna=True)
:- 计算 DataFrame 中每个列(或行)的最小值对应的索引标签。
这些方法在底层会遍历 Series 或 DataFrame 的指定轴,比较元素值,并记录最大/最小值及其位置。
argmin()
/argmax()
返回的是基于 0 的整数位置,这与 NumPy 的argmin()
/argmax()
行为一致。idxmax()
/idxmin()
则更进一步,它们返回的是pandas
索引对象中对应的标签。这在 DataFrame 具有非整数索引时特别有用,因为它直接提供了有意义的标签,而不是仅仅一个数字位置。
应用场景:
- 找出最佳/最差表现: 在销售数据中找出销售额最高的月份,或利润最低的产品。
- 时间序列分析: 找出历史数据中最高或最低点发生的时间戳。
- 数据清洗: 结合这些方法找出异常值所在的具体位置。
【1】某一列最小值的整数位置:
1
df["python"].argmin()
【2】每列最大值的索引标签:
1
df.idxmax()
【3】行方向上查找最大值/最小值的标签
1
df.idxmax(axis=1)
选择题
-
给定
s = pd.Series([10, 5, 20], index=['a', 'b', 'c'])
,执行s.argmax()
的结果是什么?A.
'c'
B.2
C.20
D. 报错答案:B
-
以下哪个方法会返回 DataFrame 中每列最大值对应的索引标签?
A.
df.max()
B.df.argmax()
C.df.idxmax()
D.df.loc[df.max()]
答案:C
编程题
- 创建一个 DataFrame
product_ratings
,包含'Product_ID'
作为行索引,以及'Design_Score'
,'Performance_Score'
两列,填充随机整数评分(1到10)。 - 找出
'Design_Score'
列中最高评分对应的产品 ID。 - 找出
'Performance_Score'
列中最低评分对应的产品 ID。 - 找出每个产品(行)的最高评分是在哪个指标(列)上。
- 打印每一步操作后的结果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
pro_id = np.arange(1, 11)
des_s = np.random.randint(1, 11, (10, ))
per_s = np.random.randint(1, 11, (10, ))
data = {"Product_ID": pro_id, "Design_Score": des_s, "Performance_Score": per_s}
product_ratings = pd.DataFrame(data=data)
display(product_ratings)
# 找出 'Design_Score' 列中最高评分对应的产品 ID
des_max = product_ratings.Product_ID[product_ratings["Design_Score"].argmax()]
print(des_max)
# 找出 'Performance_Score' 列中最低评分对应的产品 ID
per_min = product_ratings.Product_ID[product_ratings["Performance_Score"].argmin()]
print(per_min)
# 找出每个产品(行)的最高评分是在哪个指标(列)上。
max_ = product_ratings.loc[:, ["Design_Score", "Performance_Score"]].idxmax(axis=1)
print(max_)
3.更多统计指标
除了简单的聚合统计,pandas
还提供了一些用于数据分布、变化和唯一性分析的统计方法。
Series.value_counts(normalize=False, sort=True, ascending=False, bins=None, dropna=True)
:- 统计 Series 中每个唯一值出现的次数。
normalize
: 布尔值,如果为True
,则返回相对频率(百分比)。sort
: 布尔值,是否按频率降序排序。dropna
: 布尔值,是否包含NaN
值的计数。
Series.unique()
:- 返回 Series 中所有唯一值的 NumPy 数组(顺序与第一次出现时的顺序一致)。
df.cumsum(axis=0, skipna=True)
:- 计算累积和。
df.cumprod(axis=0, skipna=True)
:- 计算累积乘积。
df.std(axis=0, skipna=True, ddof=1)
:- 计算标准差。
ddof
是自由度,默认为1
(样本标准差)。
- 计算标准差。
df.var(axis=0, skipna=True, ddof=1)
:- 计算方差。
df.cummin(axis=0, skipna=True)
:- 计算累积最小值。
df.cummax(axis=0, skipna=True)
:- 计算累积最大值。
df.diff(periods=1, axis=0)
:- 计算当前元素与前一个(或后一个)元素之间的差分。常用于时间序列分析。
periods
: 整数,指定要计算的滞后(lag)期数。
df.pct_change(periods=1, axis=0)
:- 计算当前元素与前一个(或后一个)元素之间的百分比变化。常用于金融数据分析
value_counts()
和unique()
: 这些方法在底层使用哈希表来高效地识别和计数唯一元素。value_counts()
会构建一个频率分布表。累积函数 (
cumsum
,cumprod
,cummin
,cummax
): 这些函数通过迭代 Series 或 DataFrame 的元素,并维护一个累积状态来实现。它们在底层是高度优化的,避免了显式循环。
std()
和var()
: 这些是标准统计公式的实现,涉及到均值、平方差等计算。ddof
参数允许用户选择样本方差/标准差(ddof=1
)或总体方差/标准差(ddof=0
)。
diff()
和pct_change()
: 这些函数通过比较当前行/列与滞后periods
的行/列来实现。它们在处理时间序列数据时非常有用,可以快速计算增长率、波动性等。
value_counts()
: 检查分类变量的分布、识别数据不平衡、发现数据输入错误(例如,拼写错误)。
unique()
: 快速查看分类变量的所有可能类别。
累积函数: 计算总销售额的增长趋势、累计投资回报。
diff()
和 pct_change()
: 分析股票价格的日涨跌幅、传感器读数的瞬时变化率。
【1】统计某一列/整个df元素出现次数:
1
df["python"].value_counts()
【2】去重:
1
2
# df.unique() # AttributeError: 'DataFrame' object has no attribute 'unique'
df["java"].unique()
【3】累加:
1
df.cumsum()
【4】累乘:
1
df.cumprod()
【5】标准差:
1
df.std()
【6】方差:
1
df.var()
【7】累计最小值/累计最大值:
1
2
df.cummin()
df.cummax()
【8】差分:(当前值-前一个值)
1
display(df, df.diff())
计算滞后2期的差分:
1
display(df, df.diff(periods=2))
【9】计算百分比变化:((当前值-前一个值)/ 前一个值)
1
display(df, df.pct_change())
选择题
-
给定
s = pd.Series([10, 20, 10, 30, 20])
,执行s.value_counts()
的结果是什么?A.
Series([10, 20, 30], index=[2, 2, 1])
B.
Series([10, 20, 30], index=[10, 20, 30])
C.
Series([2, 2, 1], index=[10, 20, 30])
D.
Series([2, 2, 1], index=[20, 10, 30])
答案:C
-
以下哪个函数用于计算 Series 中所有唯一值的 NumPy 数组?
A.
s.value_counts()
B.s.unique()
C.s.nunique()
D.s.drop_duplicates()
答案:B
编程题
- 创建一个 DataFrame
stock_prices
,包含'Date'
(日期) 和'Price'
(价格) 两列,其中'Date'
是按顺序排列的日期(例如,pd.date_range
),'Price'
填充随机浮点数。 - 计算
'Price'
列的每日价格变化(diff
)。 - 计算
'Price'
列的每日百分比变化(pct_change
)。 - 计算
'Price'
列的累积最大值和累积最小值。 - 假设
'Price'
列中有一些重复的价格。统计每个价格出现的次数。 - 打印每一步操作后的结果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 准备 data
dates = pd.date_range(start='2025-07-01', periods=10, freq='D')
prices = [150.5, 160.2, 150.5, 170.1, 165.3, 180.7, 150.5, 175.4, 160.2, 190.8] # 包含重复价格
data = {'Date': dates, 'Price': prices}
# 创建df
stock_prices = pd.DataFrame(data=data)
display(stock_prices)
# 计算 'Price' 列的每日价格变化(diff)。
diff_ = stock_prices["Price"].diff()
display(diff_)
# 计算 'Price' 列的每日百分比变化(pct_change)
pct = stock_prices["Price"].pct_change()
display(pct)
# 计算 'Price' 列的累积最大值和累积最小值。
cummax_ = stock_prices["Price"].cummax()
cummin_ = stock_prices["Price"].cummin()
display(cummax_, cummin_)
# 假设 'Price' 列中有一些重复的价格。统计每个价格出现的次数
uni = stock_prices["Price"].unique()
counts = stock_prices["Price"].value_counts()
display(uni, counts)
4.高级统计指标
协方差和相关性是衡量两个变量之间线性关系的重要统计指标。
协方差:协方差表示的是两个变量的总体的误差,这与只表示一个变量误差的方差不同。 如果两个变量的变化趋势一致,也就是说如果其中一个大于自身的期望值,另外一个也大于自身的期望值,那么两个变量之间的协方差就是正值。 如果两个变量的变化趋势相反,即其中一个大于自身的期望值,另外一个却小于自身的期望值,那么两个变量之间的协方差就是负值。
协方差只能研究两组数据之间的关系,当要研究多组数据之间的关系时就要用到协方差矩阵。
df.cov(min_periods=None, ddof=1)
:- 计算 DataFrame 中所有属性(列)之间的协方差矩阵。
- 协方差矩阵是一个对称矩阵,对角线元素是每个属性的方差,非对角线元素是每对属性之间的协方差。
min_periods
: 整数,计算协方差所需的最小非NA
观测数。ddof
: 自由度,默认为1
。
Series.cov(other, min_periods=None, ddof=1)
:- 计算 Series 与另一个 Series 或 DataFrame 列之间的协方差。
相关系数:相关系数是最早由统计学家卡尔·皮尔逊设计的统计指标,是研究变量之间线性相关程度的量,一般用字母 r 表示。由于研究对象的不同,相关系数有多种定义方式,较为常用的是皮尔逊相关系数。
相关系数是用以反映变量之间相关关系密切程度的统计指标。相关系数是按积差方法计算,同样以两变量与各自平均值的离差为基础,通过两个离差相乘来反映两变量之间相关程度;着重研究线性的单相关系数。
皮尔逊相关系数的值在
[-1,1]
之间,大于零是正相关,小于零则表示负相关,其值越接近于1或-1则表示关系越紧密,越接近于零则表示其相关性越小。
相关系数其实是在协方差的基础上进行计算的。
df.corr(method='pearson', min_periods=None)
:- 计算 DataFrame 中所有属性(列)之间的相关性系数矩阵。
- 相关性系数矩阵也是一个对称矩阵,对角线元素为 1,非对角线元素是每对属性之间的相关性系数。
- 相关性系数公式: 皮尔逊相关系数 r(X,Y)=fractextCov(X,Y)sqrttextVar(X)textVar(Y)。取值范围在 [−1,1] 之间。
method
: 指定计算方法,默认为'pearson'
(皮尔逊相关系数)。其他选项包括'kendall'
(肯德尔秩相关)和'spearman'
(斯皮尔曼秩相关)。
df.corrwith(other, axis=0, drop=False, method='pearson', numeric_only=False)
:- 计算 DataFrame 中每一列与另一个 Series 或 DataFrame 中每一列之间的相关性系数。
- 返回一个 Series,其索引是原始 DataFrame 的列名,值是与
other
对应的相关系数。
pandas
在底层调用高度优化的NumPy
函数,这些函数又依赖于 BLAS/LAPACK 等线性代数库,从而确保了协方差和相关性矩阵计算的高性能。
特征选择: 在机器学习中,高相关性的特征可能存在冗余。可以考虑移除其中一个,以减少模型复杂性、避免多重共线性。
理解数据关系: 帮助数据科学家理解数据集中不同特征之间的相互依赖关系。
主成分分析 (PCA): PCA 的核心就是通过分析协方差矩阵(或相关系数矩阵)来找到数据的主要变化方向。
异常检测: 某些异常值可能会显著影响协方差和相关性,需要谨慎处理。
【1】协方差矩阵:
1
2
3
4
5
6
data = np.random.randint(0, 100, (10, 3))
df = pd.DataFrame(data=data, index=list("ABCDEFGHIJ"), columns=["python", "java", "golang"])
df.iloc[5, 0] = None
df.iloc[8, 2] = None
display(df)
df.cov()
计算2列的协方差:
1
df["python"].cov(df["java"])
【2】相关系数矩阵:
1
df.corr()
单一属性和所有其他属性的相关性系数:
1
df.corrwith(df["java"])
【3】可视化相关性矩阵(通常是热力图)
1
2
3
4
5
6
7
8
9
10
11
12
13
import seaborn as sns
import matplotlib.pyplot as plt
plt.figure(figsize=(6, 5))
data = np.random.randint(0, 100, (10, 3))
df = pd.DataFrame(data=data, index=list("ABCDEFGHIJ"), columns=["python", "java", "golang"])
df.iloc[5, 0] = None
df.iloc[8, 2] = None
df_corr = df.corr()
sns.heatmap(df_corr, annot=True, cmap='coolwarm', fmt='.2f')
plt.title("相关性系数 矩阵")
# 字体设置(配置可以参考:https://juejin.cn/post/7016243818647420958)
# plt.rcParams['font.sans-serif'] = ['SimHei']
plt.show()
选择题
-
以下哪个函数用于计算 DataFrame 中所有属性之间的相关性系数矩阵?
A.
df.cov()
B.df.corr()
C.df.corrwith()
D.df.dot()
答案:B,C选项用于计算 DataFrame 与另一个 Series 或 DataFrame 的列间相关系数
-
如果两个变量的皮尔逊相关系数为 −0.9,这意味着什么?
A. 它们之间没有线性关系。
B. 它们之间存在非常强的正线性关系。
C. 它们之间存在非常强的负线性关系。
D. 它们之间存在非线性关系。
答案:C
编程题
- 创建一个 DataFrame
student_performance
,包含'Math_Score'
,'Physics_Score'
,'Chemistry_Score'
三列,填充随机整数分数。 - 计算并打印所有科目之间的协方差矩阵。
- 计算并打印所有科目之间的相关性系数矩阵。
- 计算
'Math_Score'
与'Physics_Score'
之间的协方差。 - 计算
'Chemistry_Score'
与所有其他科目之间的相关性系数。 - 解释协方差和相关性系数矩阵的结果。
1
2
3
4
5
6
7
8
9
10
11
12
13
data = np.random.randint(0, 101, (10, 3))
student_performance = pd.DataFrame(data=data, columns=["Math_Score", "Physics_Score", "Chemistry_Score"])
display(student_performance)
# 计算并打印所有科目之间的协方差矩阵
cov_matrix = student_performance.cov()
display(cov_matrix)
# 计算并打印所有科目之间的相关性系数矩阵
corr_matrix = student_performance.corr()
display(corr_matrix)
# 计算 'Math_Score' 与 'Physics_Score' 之间的协方差
display(student_performance["Math_Score"].cov(student_performance["Physics_Score"]))
# 计算 'Chemistry_Score' 与所有其他科目之间的相关性系数
display(student_performance.corrwith(student_performance["Chemistry_Score"]))