七、数值型数据统计

七、数值型数据统计

数值型数据描述统计概论

数据分析思想中重要的一环就是统计学分析,这涉及到常见统计学指标的运用及分析,需要数据分析师掌握相关统计学知识。

常见指标主要有:

  1. 算数平均值
  2. 加权平均值
  3. 最值、中位数
  4. 频数、众数
  5. 四分位数
  6. 方差、标准差

1. 算数平均值(arithmetic mean)

样本中的每个值都是真值与误差的和,算数平均值表示对真值的无偏估计。

数学表示

样本: S = [ s 1 , s 2 , s 3 , … , s n ] S = [s_1, s_2, s_3, …, s_n] S=[s1,s2,s3,,sn]

算数平均值: M e a n = ( s 1 + s 2 + s 3 + . . . + s n ) n Mean = \frac{(s_1 + s_2 + s_3 + ... + s_n)}{n} Mean=n(s1+s2+s3+...+sn)

python表示

数据集

S = [s1, s2, s3, ..., sn]

样本中的每个值都是真值与误差的和。

算数平均值:

mean = (s1 + s2 + s3 + ... + sn) / n

求算数平均值的函数和方法

Numpy 中使用mean 函数

import numpy
numpy.mean(数据数组, axis=, dtype=数据类型)

Pandas 中 的Series 和 DataFrame 都使用 mean 方法

import pandas
s = pandas.Series(...)
s.mean()
df = pandas.DataFrame(...)
df.mean([axis=]))

示例

# 测试数据
data = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
]

import numpy
print(numpy.mean(data))  # 求所有
print(numpy.mean(data, axis=0))  # 轴0行(垂直方向)
print(numpy.mean(data, axis=1))  # 轴1行(水平方向)

import pandas
s = pandas.Series([1, 2, 3, 4])
print(s.mean())

df = pandas.DataFrame(data)
print(df.mean())  # 等同于 df.mean(axis=0)
print(df.mean(axis=0))
print(df.mean(axis=1))

2. 加权平均值(weighted average)

求平均值时,考虑不同样本的重要性,赋予不同的权重。

样本: S = [ s 1 , s 2 , s 3 , … , s n ] S = [s_1, s_2, s_3, …, s_n] S=[s1,s2,s3,,sn]

权重: W = [ w 1 , w 2 , w 3 , … , w n ] W =[w_1, w_2, w_3, …, w_n] W=[w1,w2,w3,,wn]

加权平均值:
a = s 1 w 1 + s 2 w 2 + . . . + s n w n w 1 + w 2 + . . . + w n a = \frac{s_1w_1 + s_2w_2 + ... + s_nw_n}{w_1+w_2+...+w_n} a=w1+w2+...+wns1w1+s2w2+...+snwn

求加权平均值的函数

a = numpy.average(数据数组, weights=权重数组, axis=)

示例

import numpy

# 一维数据
data = [1, 2, 3]
weight = [10, 5, 1]# 权重

print(numpy.average(data))  # 求所有
print(numpy.average(data, weights=weight))  # 求所有

# 二维数据
data = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
]
weight = [
    [10, 10, 10],
    [20, 20, 20],
    [30, 30, 30],
]  # 权重

import numpy
print(numpy.average(data))  # 求所有
print(numpy.average(data, weights=weight))  # 求所有
print(numpy.average(data, axis=0))  # 轴0行(垂直方向),权重默认全为1
print(numpy.average(data, weights=weight, axis=0))  # 轴0行(垂直方向)
print(numpy.average(data, weights=weight, axis=1))  # 轴1行(水平方向)

3. 最值

最值分析即求一组数据的最小值、最大值、极差等数据指标,结合业务进行分析的方法

极差

是指在一组数据中最大值和最小值的差值。

numpy提供了一些求最值的API:

求最大值/最小值/极差

np.max/min/ptp(a, axis=)  # axis 省略代表所有数据求最大
# 或
a.max/min/ptp(axis=)  # a 为 ndarray 数组

求最大值索引 / 最小值索引

np.argmax/argmin(a, axis=)  # axis 省略代表所有数据求最大
# 或
a.argmax/argmin(axis=)  # a 为 ndarray 数

示例

import numpy as np

data = np.array([
    [4, 9, 3],
    [1, 5, 6],
    [2, 7, 8]
])
print(data)

# 计算 全部最小值:
mymin = data.min()
# 计算 行方向 最小值:
mymin = data.min(axis=0)
# 计算 列方向 最小值:
mymin = data.min(axis=1)
print(mymin)

# 求极差
myptp = data.ptp()
myptp = data.ptp(axis=0)
myptp = data.ptp(axis=1)
myptp = np.ptp(data, axis=1)
print(myptp)

将两个同维数组中对应元素中最大/最小元素构成一个新的数组

np.maximum(a, b)
np.minimum(a, b)

示例

import numpy as np

a = np.array([
    [4, 9, 3],
    [1, 5, 6],
    [2, 7, 8]
])

b = np.array([
    [1, 5, 2],
    [4, 8, 9],
    [3, 7, 6]
])

mymax = np.maximum(a, b)
print(mymax)

pandas提供了一些求最值的API:

求最大值/最小值/极差

Series.max/min()
# 或
DataFrame.max/min(axis=)

求最大值索引 / 最小值索引

Series.idxmax/dixmin(axis=)
# 或
DataFrame.idxmax/idxmin(axis=)  # 返回最大值的行标签

4. 中位数

将多个样本按照大小排序,取中间位置的元素。

若样本数量为奇数,中位数为最中间的元素即 3000

# 如下数据中位数为3000
[1, 2000, 3000, 4000, 10000000]

若样本数量为偶数,中位数为最中间的两个元素的平均值

# 如下数据中位数为3500
[1,2000,3000,4000,5000,10000000]

numpy求中位数的API:

numpy.median(a, axis=)  # 求 数组a 的中位数

pandas求中位数的API:

Series.median(axis=)
# 或
DataFrame.median(axis=)

示例

import pandas as pd
import numpy as np

# 读取 JSON 文件的内容
data = pd.read_json("ratings.json")
print(data)

# 获取每个人评分的中位数
mymedian = data.median()

# 获取每部电影评分的中位数
mymedian = data.median(axis=1)
print(mymedian)

# 用numpy 获取每个人评分的中位数
arr = data.values  # arr 绑定 ndarray 数组
mymedian = np.median(arr, axis=0)
print(mymedian)

5. 频数与众数

频数指一组数据中各离散值出现的次数。

众数是指一组数据中出现次数最多的值。

示例:

import numpy as np
import pandas as pd

# Series 的 value_counts() 方法求频数
data = np.array(['bmw', 'bmw', 'bz', 'audi', 'bz', 'bmw'])
cars = pd.Series(data)
vc = cars.value_counts()  # 频数
print(vc)

# Series 的 mode() 方法求众数
mode = cars.mode()  # 众数
print(mode)

6 .四分位数

所谓四分位数,即把数值由小到大排列并分成四等份,处于三个分割点位置的数值就是四分位数。

四分位数的三个位置:

  • 第1四分位数 (Q1),又称“较小四分位数”,等于该样本中所有数值由小到大排列后第25%的数字。
  • 第2四分位数 (Q2),又称“中位数”,等于该样本中所有数值由小到大排列后第50%的数字。
  • 第3四分位数 (Q3),又称“较大四分位数”,等于该样本中所有数值由小到大排列后第75%的数字。

示例:

import numpy as np

L1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
L2 = [1, 2, 3, 10,  100, 101, 102, 103]
n1 = np.quantile(L1, [0.25, 0.5, 0.75])
print(n1)  # [3. 5. 7.]

n2 = np.quantile(L2, q=[0.25, 0.5, 0.75])
print(n2)  # [  2.75  55.   101.25]
# 四分位数
import pandas as pd

data = pd.read_json("ratings.json")
print(data)

# 求取 四分位数
myquantile = data.quantile([.0, .25, .5, .75, 1.])
print(myquantile)

7. 方差、标准差

标准差(Standard Deviation) ,中文又常称均方差,在概率统计中最常使用作为统计分布程度上的测量。
标准差能反映一个数据集的离散程度,是方差的算术平方根平均数相同的两组数据,标准差未必相同。

总体方差公式
σ 2 = ∑ i = 1 N ( x i − x ˉ ) 2 N \sigma^2 = \frac{\sum_{i=1}^{N}{{(x_i-\bar x)}^2}}{N} σ2=Ni=1N(xixˉ)2

总体标准差公式
σ = ∑ i = 1 N ( x i − x ˉ ) 2 N \sigma = \sqrt{\frac{\sum_{i=1}^{N}{{(x_i-\bar x)}^2}}{N}} σ=Ni=1N(xixˉ)2

样本方差公式
σ 2 = ∑ i = 1 N ( x i − x ˉ ) 2 N − 1 \sigma^2 = \frac{\sum_{i=1}^{N}{{(x_i-\bar x)}^2}}{N-1} σ2=N1i=1N(xixˉ)2

样本标准差公式
σ = ∑ i = 1 N ( x i − x ˉ ) 2 N − 1 \sigma = \sqrt{\frac{\sum_{i=1}^{N}{{(x_i-\bar x)}^2}}{N-1}} σ=N1i=1N(xixˉ)2

方差、标准差计算步骤

样本(sample):
S = [ s 1 , s 2 , s 3 , . . . , s n ] S = [s_1, s_2, s_3, ..., s_n] S=[s1,s2,s3,...,sn]

平均值:
m = s 1 + s 2 + s 3 + . . . + s n n m = \frac{s_1 + s_2 + s_3 + ... + s_n}{n} m=ns1+s2+s3+...+sn

离差(deviation):表示某组数据距离某个中心点的偏离程度
D = [ d 1 , d 2 , d 3 , . . . , d n ] d i = S i − m D = [d_1, d_2, d_3, ..., d_n]\\ d_i = S_i-m D=[d1,d2,d3,...,dn]di=Sim
离差方:
Q = [ q 1 , q 2 , q 3 , . . . , q n ] q i = d i 2 Q = [q_1, q_2, q_3, ..., q_n]\\ q_i=d_i^2 Q=[q1,q2,q3,...,qn]qi=di2

总体方差(variance):
v = ( q 1 + q 2 + q 3 + . . . + q n ) n v = \frac{(q_1+q_2+q_3 + ... + q_n)}{n} v=n(q1+q2+q3+...+qn)

总体标准差(standard deviation):
s = v s = \sqrt{v} s=v

样本方差:
v ′ = ( q 1 + q 2 + q 3 + . . . + q n ) n − 1 v' = \frac{(q_1+q_2+q_3 + ... + q_n)}{n-1} v=n1(q1+q2+q3+...+qn)
​ 样本方差分母为n-1, 称之为“贝塞尔校正”,这是因为抽取样本时候,采集的样本主要是落在中心值附近,那么通过这些样本计算的方差会小于等于对总体数据集方差的无偏估计值。为了能弥补这方面的缺陷,那么我们把公式的n改为n-1,以此来提高方差的数值。称为贝塞尔校正系数。

样本标准差:
s ′ = v ′ s' = \sqrt{v'} s=v

求算数标准差的函数和方法

Numpy 中使用std 函数

import numpy
numpy.std(数据数组, axis=, ddof=0)

Pandas 中 的Series 和 DataFrame 都使用 std 方法,默认doff=1 即求样本标准差

import pandas
s = pandas.Series(...)
s.std(
    axis=None,
    ddof=1)
df = pandas.DataFrame(...)
df.std(axis=, ddof=1)  # ddof=0是样本标准差

示例

# 标准差

import numpy as np
import pandas as pd

data = pd.read_json("ratings.json")
print(data)

print('----求标准差----')
print(np.std(data, axis=0))
print(data.std(axis=0, ddof=0))

print('----求样本标准差----')
print(np.std(data, axis=0, ddof=1))
print(data.std(axis=0))

宏观数值统计

pandas的DataFrame和Series 提供了describe()方法可以方便的统计DataFrame每一列的常见统计学指标结果,进行宏观分析。

DataFrame.describe() 方法

作用

​ 生成描述性统计。

调用格式

DataFrame.describe(
    percentiles=None,
    include=None,
    exclude=None,
)

参数详解:

参数 说明
percentiles 百分位数:类似数组, 要包含在输出中的百分比。默认情况下,“百分位数”为[.25,.5,.75],返回第25、50和75个百分位。
include 包含哪些列,值可以是列表、'All’表示全部字段
exclude 排除哪些列,值可以是字段名或列表

示例:

print(data.describe())

DataFrame.info() 方法

作用:

​ 用于显示数据集的摘要。我们使用dataframe.info()功能。

调用格式

DataFrame.info(
    verbose=None,  # 是否打印完整的摘要
)

8. 协方差、相关系数、相关系数矩阵

相关性分析

相关性分析是研究两个或两个以上处于同等地位的随机变量间的相关关系的统计分析方法。例如,人的身高和体重之间;空气中的相对湿度与降雨量之间的相关关系都是相关分析研究的问题。
相关性分析侧重于发现随机变量间的种种相关特性,在工农业、水文、气象、社会经济和生物学等方面都有应用。

1. 协方差

关键字: 协方差(covariance)

通过两组统计数据计算而得的协方差可以评估这两组统计数据的相似程度。

协方差公式:

C o v ( X , Y ) = ∑ ( x i − x ‾ ) ( y i − y ‾ ) N Cov(X,Y)=\frac{\sum(x_i-\overline{x})(y_i-\overline{y})}{N} Cov(X,Y)=N(xix)(yiy)
两组样本

A = [a1, a2, ..., an]
B = [b1, b2, ..., bn]

两组平均值

mean_a = (a1 + a2 +...+ an)/n
mean_b = (b1 + b2 +...+ bn)/n

两组离差(用样本中的每一个元素减去平均数,求得数据的误差程度):

dev_a = [a1, a2, ..., an] - mean_a
dev_b = [b1, b2, ..., bn] - mean_b

两组协方差

cov_ab = mean(dev_a * dev_b)
cov_ba = mean(dev_b * dev_a)

协方差的意义

协方差可以简单反映两组统计样本的相关性,值为正,则为正相关;值为负,则为负相关,绝对值越大相关性越强。

协方差公式理解

(1)当 a n a_n an b n b_n bn符号全部相同时,结果为正(趋势相同,正相关);

(2)当 a n a_n an b n b_n bn符号全部相反时,结果为正(趋势相同,正相关);

(3)当其中有一组为正,另一组为负时,结果为负(趋势相反,负相关).

示例:计算两组数据的协方差,并绘图观察。

# 协方差示例

import numpy as np
import matplotlib.pyplot as plt

a = np.array([1, 3, 1, 4, 1, 5, 1, 6])
b = np.array([2, 4, 2, 5, 2, 6, 2, 7])
c = np.array([-0.5, -1, -0.5, -2, -0.5, -3, -0.5, -4])

x = np.arange(0, len(a))

plt.figure("Convariance Demo", facecolor="lightgray")
plt.plot(x, a, label="a")
plt.plot(x, b, label="b")
plt.plot(x, c, label="c")

# 求a-b, a-c之间的协方差
## 求平均值
avg_a = np.mean(a)
avg_b = np.mean(b)
avg_c = np.mean(c)

## 离差
dev_a = a - avg_a
dev_b = b - avg_b
dev_c = c - avg_c

## 协方差
cov_ab = np.mean(dev_a * dev_b)
cov_ac = np.mean(dev_a * dev_c)

print("cov_ab:", cov_ab)
print("cov_ac:", cov_ac)

plt.legend()
plt.show()

执行结果:

控制台输出:

con_ab: 3.6875
con_ac: -2.375

可视化:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hZWZCp1p-1639225739445)(./img/%E5%8D%8F%E6%96%B9%E5%B7%AE.png)]

示例2:

# 协方差, 相关系数, 相关矩阵

import numpy as np
import pandas as pd

data = pd.read_json("ratings.json")
print(data)

# 计算两组数据的协方差
a = data['John Carson']
b = data['Michelle Peterson']
# 计算均值
mean_a = np.mean(a)
mean_b = np.mean(b)
# 计算离差
dev_a = a - mean_a
dev_b = b - mean_b
# 计算协方差:
cov_ab = np.mean(dev_a * dev_b)
print('协方差:', cov_ab)  # 0.16666666666666666 大于0,说明两组数据正相关。

2.相关系数

关键字: 相关系数(correlation coefficient)

如何表示两个数据样本相关性有多强?如何度量?这就需要用到相关系数。

协方差除去两组统计样本标准差的乘积是一个[-1, 1]之间的数,该结果称为统计样本的相关系数。

相关系数公式
r ( X , Y ) = C o v ( X , Y ) V a r [ X ] ∙ V a r [ Y ] r(X,Y)=\frac{Cov(X,Y)}{\sqrt{Var[X]}\bullet\sqrt{Var[Y]}} r(X,Y)=Var[X] Var[Y] Cov(X,Y)

# a组样本 与 b组样本做对照后的相关系数
cov_ab/(std_a * std_b)
# b组样本 与 a组样本做对照后的相关系数
cov_ba/(std_b * std_a)
# a样本与a样本作对照   b样本与b样本做对照   二者必然相等
cov_ab/(std_a * std_b) = cov_ba/(std_b * std_a)

通过相关系数可以分析两组数据的相关性:

  • 若相关系数越接近于0,越表示两组样本越不相关
  • 若相关系数越接近于1,越表示两组样本正相关
  • 若相关系数越接近于-1,越表示两组样本负相关

示例:在上一些示例中,加入如下代码,输出案例中两组数据的相关系数:

print('a b 的相关系数:', cov_ab/(np.std(a)*np.std(b)))
print('a c 的相关系数:', cov_ac/(np.std(a)*np.std(c)))

3. 相关系数矩阵

关键字: 相关系数矩阵(correlation coefficient matrix)

以下是计算相关系数矩阵的方法。
[ v a r _ a s t d _ a × s t d _ a c o v _ a b s t d _ a × s t d _ b c o v _ b a s t d _ b × s t d _ a v a r _ b s t d _ b × s t d _ b ] \left[ \begin{array}{c} \frac{var\_a}{std\_a \times std\_a} & \frac{cov\_ab}{std\_a \times std\_b} \\ \frac{cov\_ba}{std\_b \times std\_a} & \frac{var\_b}{std\_b \times std\_b}\\ \end{array} \right ] [std_a×std_avar_astd_b×std_acov_bastd_a×std_bcov_abstd_b×std_bvar_b]
矩阵正对角线上的值都为1。(同组样本与自己相比绝对正相关)
[ 1 c o v _ a b s t d _ a × s t d _ b c o v _ b a s t d _ b × s t d _ a 1 ] \left[ \begin{array}{ccc} 1 & \frac{cov\_ab}{std\_a \times std\_b} \\ \frac{cov\_ba}{std\_b \times std\_a} & 1\\ \end{array} \right ] [1std_b×std_acov_bastd_a×std_bcov_ab1]
numpy.corrcoef函数求得相关系数矩阵:

# 返回值为一个相关系数矩阵:[[1,        ab相关系数],
#                        [ba相关系数, 1       ]]
numpy.corrcoef(a, b=None)

示例代码:

# 基于numpy给出的corrcoef接口输出相关系数矩阵
print(np.corrcoef(a, b))

执行结果:

[[1.         0.39605902]
 [0.39605902 1.        ]]

其中[0,1]或[1,0]即为相关系数.

pandas.corr()方法求得相关系数矩阵:

DataFrame.corr()

示例代码:

# 基于numpy给出的corrcoef接口输出相关系数矩阵
print(df.corr())

完整示例代码

# 协方差, 相关系数, 相关矩阵
import numpy as np
import pandas as pd

data = pd.read_json("ratings.json")

# 计算两组数据的协方差
a = data['John Carson']
b = data['Michelle Peterson']

# 使用 numpy.corrcoef 或pandas.corr 计算相关系数矩阵
# 基于numpy给出的corrcoef函数输出相关系数矩阵
ccm = np.corrcoef(a, b)
print(ccm)
# 使用 DataFrame.corrcoef方法输出相关系数矩阵
ccm = data.corr()
print(ccm)

9. Pandas 特殊值处理

pandas提供了apply函数方便的处理Series与DataFrame;apply函数支持逐一处理数据集中的每个元素都会执行一次目标函数,把返回值存入结果集中。

调用格式

def myfunc(x):  # x 为传输数据, 对于DataFrame为数组
    return y  # 返回值
Series.apply(func)
DataFrame.apply(func, axis=0)

Series.apply示例:

import pandas as pd

s = pd.Series(['80公斤', '83公斤', '78公斤', '74公斤'])

def func(x):
    return int(x[:2])

s2 = s.apply(func)
print("处理前:")
print(s)
print("处理后:")
print(s2)

DataFrame.apply示例:

import pandas as pd

data = pd.read_json("ratings.json")

def func(x):
    '''缺失值使用平均值mean填补'''
    # pd.isna() 用于检测一个数组的缺失值,返回缺失值掩码
    x[pd.isna(x)] = x.mean()
    return x

# 行(垂直方向) 对 缺失值填补平均值
print("处理前:")
print(data)
data.apply(func, axis=0)
print("处理后:")
print(data)

9. Pandas数据排序

Pandas有两种排序方式,它们分别是:

  1. 按标签排序
  2. 按实际值排序

按行标签排序

使用sort_index()方法,通过传递axis参数和排序顺序,可以对DataFrame进行排序。 默认情况下,按照升序对行标签进行排序。

调用格式 :

DataFrame.sort_index(
    axis=0,  # 轴向
    ascending = True,  # 排序顺序
    inplace = False,  # 是否改变原DataFrame有数据(默认不改变)
    kind = 'quicksort',  # 排序方法,默认为快速排序
)

示例:

import pandas as pd

data = {
    'Name': pd.Series(
        ['Tom', 'James', 'Ricky', 'Vin',
         'Steve', 'Minsu', 'Jack', 'Lee',
         'David', 'Gasper', 'Betina', 'Andres']),
    'Age': pd.Series([25, 26, 25, 23,
                      30, 29, 23, 34,
                      40, 30, 51, 46]),
    'Rating': pd.Series([4.23, 3.24, 3.98, 2.56,
                         3.20, 4.6, 3.8, 3.78,
                         2.98, 4.80, 4.10, 3.65])
}

unsorted_df = pd.DataFrame(data)
sorted_df = unsorted_df.sort_index(ascending=False)
print("排序前:")
print(unsorted_df)
print("排序后:")
print(sorted_df)

按列值排序

调用格式:

DataFrame.sort_values(
    by,                # 用于排序字段的名字或名字列表
    axis=0,            # 轴向
    ascending=True,    # 排序顺序(默认升序)
    inplace=False,     # 是否改变原DataFrame有数据(默认不改变)
    kind='quicksort',  # 排序方法,默认为快速排序
)

示例:

import pandas as pd

data = {
...  # 使用以上数据
}

unsorted_df = pd.DataFrame(data)
sorted_df = unsorted_df.sort_values(ascending=False,
                                    by='Age')
print("排序前:")
print(unsorted_df)
print("排序后:")
print(sorted_df)

此处可以实现 《保健品分析项目》

11. pandas分组聚合

分组聚合

pandas提供了功能类似于数据库中group by语句的用于拆分数据组的方法pd.groupby();该方法提供的是分组聚合步骤中的拆分功能,能根据索引或字段对数据进行分组(Split) 进而针对得到的多组数据执行聚合操作(Apply),最终合并为最终结果(Combine)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lmq4h1Ko-1639225739446)(./pandas_images/split_apply.png)]

分组

Pandas 使用 DataFrame.groupby()方法进行分组

调用方法:

DataFrame.groupby(
    by=None,
    axis=0,
    as_index=True,
    sort=True,
) -> DataFrameGroupBy

参数及其说明:

参数名称 说明
by 接收list, string, mapping或generator。用于确定进行分组的依据。无默认。
axis 表示操作的轴向, 默认对行进行操作。默认为0。
as_index 接收boo learn。表示聚合后的聚合标签是否以Data Frame索引形式输出。默认为True。
sort 接收boo learn。表示是否对分组依据分组标签进行排序。默认为True。

DataFrame.groupby()方法的返回类型为 : DataFrameGroupBy

示例:

# 分组

import numpy as np
import pandas as pd

data = pd.DataFrame({
    'student_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
                   12, 13, 14, 15, 16, 17, 18, 19, 20],
    'student_name': ['Alex', 'Amy', 'Allen', 'Alice',
                     'Ayoung', 'Billy', 'Brian', 'Bran',
                     'Bryce', 'Betty', 'Emma', 'Marry',
                     'Allen', 'Jean', 'Rose', 'David',
                     'Tom', 'Jack', 'Daniel', 'Andrew'],
    'class_id': [1, 1, 1, 2, 2, 2, 3, 3, 3, 4,
                 1, 1, 1, 2, 2, 2, 3, 3, 3, 2],
    'gender': ['M', 'M', 'F', 'F', 'M', 'M', 'F', 'F',
               'M', 'M', 'F', 'F', 'M', 'M', 'F', 'F',
               'M', 'M', 'F', 'F'],
    'age': [20, 21, 22, 20, 21, 22, 23, 20, 21, 22, 20,
            21, 22, 23, 20, 21, 22, 20, 21, 22],
    'score': [98, 74, 67, 38, 65, 29, 32, 34, 85, 64, 52,
              38, 26, 89, 68, 46, 32, 78, 79, 87]})

print(data)

data_grouped = data.groupby('class_id')  # 根据班级分组

print(data_grouped)
print(data_grouped.agg(len))
# data_grouped.agg(np.mean)

说明

用groupby方法分组后的结果并不能直接查看,而是被存在内存中,输出的是内存地址。实际上分组后的DataFrameGroupBy对象类似于字典,键索引为分组的索引值,值为分组后的Series或DataFrame 。

DataFrame.GroupBy对象是可迭代对象

对 DataFrameGroupBy 进行迭代访问可以得到分组的值和对应的子表,格式如下:

for k, v in DataFrameGroupBy 对象:
      语句块

示例:

for class_id , df in data_grouped:
    print("班级为:", class_id, '子表为:', df)

DataFrame.GroupBy对象的常用方法:

方法名 说明
.size() 计算组内元素个数。如果 as_index=True,返回保存在Series 中的每组的行数,如果as_index=False返回DataFrame
.mean() 计算每组的均值,缺失值除外.
.median() 计算每组的中位数,缺失值除外.
.std() 计算每组的标准差,缺失值除外.
.count() 计算每组的数据个数,缺失值除外.
.get_group(name) 根据分组时的名称构建一个DataFrame,参数name是用于分组的DataFrame中的特征值
.max() 返回每组的最大值
.idxmax() 返回每组的最大值的索引
.min() 返回每组的最小值
.idxmin() 返回每组的最小值的索引
.sum() 计算每组值的和
.head(n) 返回每组的前n个值。
.tail(n) 返回每组的后n个值。
.agg(func) 使用函数func对每组进行聚合处理
.apply(func) 使用func 对特殊值进行处理

示例:

# ... 承接上述示例
data_grouped = data.groupby('gender')  # 根据性别分组
#  返回各个分组个数的Series
print(data_grouped.size())
# 返回男生分组的DataFrame
print(data_grouped.get_group('M'))

data_grouped = data.groupby(['class_id', 'gender'])
#  返回具有复合索引 class_id gender的分组个数的Series
print(data_grouped.size())
# 返回1班男生分组的DataFrame
print(data_grouped.get_group((1, 'M')))

聚合

聚合函数为每个组返回聚合值。当创建了分组(groupby)对象,就可以对每个分组的其他字段数据执行求和、求标准差等操作。

  • 使用聚合函数agg进行组内计算:
# 计算班级的平均分
class_mean = data_grouped.agg({'score': np.mean})
print(class_mean)

结果

              score
class_id           
1         59.166667
2         60.285714
3         56.666667
4         64.000000
  • 对于不同字段希望做不同聚合操作时:
# 计算班级的最大年龄和平均分
class_info = data_grouped.agg({
    'age': np.max,
    'score': np.mean
})
print(class_info)

结果

          age      score
class_id                
1          22  59.166667
2          23  60.285714
3          23  56.666667
4          22  64.000000
          age score           
  • 同一字段可以计算多个聚合数据,返回带有复合索引的DataFrame
# 计算班级年龄最大值,分数最高值和分数均值
class_info = data_grouped.agg({
    'age': np.max,
    'score' : [np.max, np.mean]
})
print(class_info)

执行结果

          age score           
         amax  amax       mean
class_id                      
1          22    98  59.166667
2          23    89  60.285714
3          23    85  56.666667
4          22    64  64.00000

pandas支持的聚合函数有:

方法名称 说明
count 计算分组的数目,包括缺失值。
head 返回每组的前n个值。
max 返回每组最大值。
mean 返回每组的均值。
median 返回每组的中位数。
cumcount 对每个分组中组员的进行标记,0至n-1。
size 返回每组的大小。
min 返回每组最小值。
std 返回每组的标准差。
sum 返回每组的和。

透视表

透视表(pivot table)是各种电子表格程序和其他数据分析软件中一种常见的数据汇总工具。它根据一个或多个键对数据进行分组聚合,并根据每个分组进行数据汇总。

作用:

创建一个扩展的透视表的 DataFrame.

透视表的DataFrame.pivot_table方法

DataFrame.pivot_table(
    values=None,  # 聚合的列
    index=None,  # 分组的列名或者列表,用于行显示
    columns=None,  # 分组的列名或者列表,用于列显示
    aggfunc='mean',  # 聚合函数,默认是'numpy.mean' 均值
    fill_value=None,  # 缺省值填充,默认NaN
    margins=False,  # 添加行和列的汇总, 默认不添加
    margins_name='All'  # 汇总名称,默认为"All"
) -> 'DataFrame'

示例

# pivot table

import numpy as np
import pandas as pd

data = pd.DataFrame({
    'student_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
                   12, 13, 14, 15, 16, 17, 18, 19, 20],
    'student_name': ['Alex', 'Amy', 'Allen', 'Alice',
                     'Ayoung', 'Billy', 'Brian', 'Bran',
                     'Bryce', 'Betty', 'Emma', 'Marry',
                     'Allen', 'Jean', 'Rose', 'David',
                     'Tom', 'Jack', 'Daniel', 'Andrew'],
    'class_id': [1, 1, 1, 2, 2, 2, 3, 3, 3, 4,
                 1, 1, 1, 2, 2, 2, 3, 3, 3, 2],
    'gender': ['M', 'M', 'F', 'F', 'M', 'M', 'F', 'F',
               'M', 'M', 'F', 'F', 'M', 'M', 'F', 'F',
               'M', 'M', 'F', 'F'],
    'age': [20, 21, 22, 20, 21, 22, 23, 20, 21, 22, 20,
            21, 22, 23, 20, 21, 22, 20, 21, 22],
    'score': [98, 74, 67, 38, 65, 29, 32, 34, 85, 64, 52,
              38, 26, 89, 68, 46, 32, 78, 79, 87]})

print(data)

#以class_id与gender做分组汇总数据, 聚合统计score列, 针对age 的每个值列级分组统计,添加行、列小计
result = data.pivot_table(
    index=['class_id', 'gender'],
    columns=['age'],
    values=['score'],
    margins=True,
    aggfunc='max')
print(result)


执行结果:

                score                      
age                20    21    22    23 All
class_id gender                            
1        F       52.0  38.0  67.0   NaN  67
         M       98.0  74.0  26.0   NaN  98
2        F       68.0  46.0  87.0   NaN  87
         M        NaN  65.0  29.0  89.0  89
3        F       34.0  79.0   NaN  32.0  79
         M       78.0  85.0  32.0   NaN  85
4        M        NaN   NaN  64.0   NaN  64
All              98.0  85.0  87.0  89.0  98

day10

八、pandas可视化

pandas基于matplotlib封装了很多可视化相关方法,可以方便的绘制各种常用图形。即使用图表的方式显示Series或DataFrame中的数据。

Pandas 使用可以使用通用的方法 Series.plot() 和 DataFrame.plot方法绘图

调用格式

Series/DataFrame.plot(
    x=None, # x 轴选用数据列的标签
    y=None, # y 轴选用数据列的标签
    kind='line',  # 线型: 默认为'line'
    subplots=False,   # 子图
    layout=(rows, columns),  # 元组,子图的布局
    figsize=(width, height),  # 宽和高,单位为英寸
    use_index=True,  # x 轴刻度索引
    title='str',  # 标题
    grid=None,   # 是否画网格线
    xticks=[...],  # 同 matplotlib xticks
    yticks=[...],  # 同 matplotlib yticks
    xlim=(begin, end)  # 同 matplotlib
    xlabel=None,  # 同 matplotlib
    ylim=(begin, end)  # 同 matplotlib
    rot=None,  # ticks 的旋转角度
    fontsize=None,   # 字体大小
    colormap=None,   # cmap 颜色映射, 同 matplotlib
    stacked=False,   # 是否创建叠加柱状图,默认为False
    ...  
)

线性kinds 关键字参数的取值如下:

kind : str
    The kind of plot to produce:
    - 'line' : line plot (default)  # 折线图
    - 'bar' : vertical bar plot  # 垂直柱状图
    - 'barh' : horizontal bar plot  # 水平柱状图
    - 'hist' : histogram  # 直方图
    - 'box' : boxplot  # 箱线图
    - 'kde' : Kernel Density Estimation plot  # 密度图
    - 'density' : same as 'kde'
    - 'area' : area plot
    - 'pie' : pie plot  # 饼图
    - 'scatter' : scatter plot  # 散点图
    - 'hexbin' : hexbin plot.

1. 折线图

首先来学习一下pandas如何把Series与DataFrame中的数据以折线图的方式呈现:
Series数据可视化可以使用Series.plot() 方法

示例:

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

s = pd.Series(np.random.normal(10, 1, 10))
s.plot()  # 使用默认的索引作为 x 轴坐标
plt.show()

示例2

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

s = pd.Series(np.random.normal(10, 1, 10))
s.index = pd.date_range('2021-1-1', periods=10)
s.plot()  # 使用默认的索引作为 x 轴坐标
plt.show()

DataFrame数据可视化可以使用DataFrame.plot() 方法

示例:

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

df = pd.DataFrame(np.random.randn(10, 2),
                  columns=['a', 'b'])
print(df)

df.plot()
plt.show()

2. 柱状图

绘制柱状图相关API:

Series/DataFrame.plot(kind='bar'/'barh')
Series/DataFrame.plot.bar/barh()

示例

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

apples = np.random.normal(50, 10, 12)   # 12个月 每个月苹果的销量

def to_string(x):
    return "%d-%d-%d" % (x.year, x.month, x.day)

months = pd.date_range('2020-01-01', periods=12, freq='M')
xticks = pd.Series(months).apply(to_string)

sales = pd.Series(apples)
sales.index = xticks

sales.plot.bar(rot=30)
# sales.plot.barh()
plt.show()

示例2

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

apples = np.random.normal(50, 10, 12)   # 12个月 每个月苹果的销量
oranges = np.random.normal(50, 10, 12)   # 12个月 每个月橘子的销量

def to_string(x):
    return "%d-%d-%d" % (x.year, x.month, x.day)

months = pd.date_range('2020-01-01', periods=12, freq='M')
xticks = pd.Series(months).apply(to_string)

sales = pd.DataFrame({
    'apple': apples,
    'orange': oranges
}, index=xticks)

sales.plot.bar(rot=30)
# sales.plot.barh()
plt.show()

3. 散点图

绘制散点图相关API:

Series/DataFrame.plot(kind='scatter')
Series/DataFrame.plot.scatter()

示例

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

apples = np.random.normal(50, 10, 12)   # 12个月 每个月苹果的销量
oranges = np.random.normal(50, 10, 12)   # 12个月 每个月橘子的销量
df = pd.DataFrame({'apples':apples, 'oranges':oranges},
    index=pd.date_range('2019-01-01', periods=12, freq='M')
)

df.plot.scatter(x='apples', y='oranges', c='apples', colormap='jet', s=80)
plt.show()

4. 饼状图

绘制饼状图相关API:

Series/DataFrame.plot(kind='pie')
Series/DataFrame.plot.pie()

示例:

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

data = np.array([22, 21, 25, 8])
labels = np.array(['Python', 'JS', 'Java', 'C++'])
data = pd.Series(data, index=labels)
data.plot.pie(figsize=(4, 4))
plt.show()

5. 直方图

绘制直方图相关API:

Series/DataFrame.plot(kind='hist')
Series/DataFrame.plot.hist()

示例

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

sample = [4, 1, 2, 3, 5, 3, 2, 4, 5, 2, 3, 2]
data = pd.Series(sample)
data.plot.hist()
print(data)
plt.show()

6. 箱线图

箱线图反应一组数据的集中趋势,四分位数的差可以反映一组数据的离散情况:
中位数高,表示平均水平较高;反之则表示平均水平较低。
箱子短,表示数据集中;箱子长,表示数据分散。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BFYpF0PH-1639225739446)(./pandas_images/pandas_box.jpg)]

四分位距IQR 为 Q3-Q1 即上四分位数-下四分位数

Q3+1.5IQR和Q1-1.5IQR处画两条与中位线一样的线段,这两条线段为异常值截断点,称其为内限

上边缘是内限的最大样本值

下边缘是内限的最小样本值

在Q3+3IQR和Q1-3IQR处画两条线段,称其为外限

在内限与外限之间的异常值为温和的异常值(mild outliers)用圆点’〇’表示

在外限以外的为极端的异常值(extreme outliers),用星号’*'表示

绘制箱线图相关API:

Series/DataFrame.plot(kind='box')
Series/DataFrame.plot.box()

示例

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

df = pd.DataFrame({
    'A':pd.Series(np.random.randn(100)),
    'B':pd.Series(np.random.randn(100)),
    'C':pd.Series(np.random.randn(100))
})
df.plot.box()
plt.show()

九、数据清洗

数据清洗主要操作

  1. 重复值处理

    删除或合并

  2. 缺失值处理:

    比如删除记录、数据填补、不处理等方法

  3. 异常值处理:

    可以剔除,或者修改为正常值,或者影响小的话不处理

1. 去重

检测与处理重复值

pandas提供了一个名为drop_duplicates的去重方法。该方法只对DataFrame或者Series类型有效。这种方法不会改变数据原始排列,并且兼具代码简洁和运行稳定的特点。该方法不仅支持单一特征的数据去重,还能够依据DataFrame的其中一个或者几个特征进行去重操作。

调用格式

Series/DataFrame.drop_duplicates(
    subset = None,
    keep = 'first',
    inplace = False,
    ignore_index = False,
) -> Series/DataFrame

参数说明

参数名 说明
subset 接收string或sequence。表示进行去重的列。
默认为None, 表示全部列。
keep 接收特定string。表示重复时保留第几个数据。
‘first’:保留第一个。‘last’:保留最后一个。
False:只要有重复都不保留。默认为’first’。
in place True表示是否在原表上进行操作。默认为False。
ignore_index 忽略索引,False: 不考虑索引的值(默认)。

示例

# 去重
import pandas as pd

data = {
    'name': ['zs', 'zs', 'ls', 'ww'],
    'age': [20, 20, 21, 20],
    'score': [90, 90, 100, 90]
}
df = pd.DataFrame(data)
print(df)

df1 = df.drop_duplicates()
print(df1)

df2 = df.drop_duplicates(subset='name')
print(df2)

df3 = df.drop_duplicates(subset='name', keep='last')
print(df3)

df4 = df.drop_duplicates(subset=['age', 'score'])
print(df4)


df5 = df.drop_duplicates(subset='age', keep=False)
print(df5)

2. 缺失值处理

检测失值

数据中的某个或某些特征的值是不完整的,这些值称为缺失值。pandas提供了识别缺失值的方法isnull以及识别非缺失值的方法notnull,这两种方法在使用时返回的都是布尔值True和False。结合sum函数和isnull、notnull函数,可以检测数据中缺失值的分布以及数据中一共含有多少缺失值。

相关方法:

# 检测缺失值,返回缺失值的掩码
Series/DataFrame.isnull()

# 检测非缺失值,返回非缺失值的掩码
Series/DataFrame.notnull()

示例:

import numpy as np
import pandas as pd

dates = pd.date_range('20201101', periods=4, freq='W')
df = pd.DataFrame(np.arange(1, 29).reshape(4, 7),
                  index=dates,
                  columns=['Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat', 'Sun'])

df.iloc[1, 0] = np.nan  # 设置为 缺失值 NaN
df.iloc[2, 5] = np.nan
print(df)

# df1接收, 判断是否有缺失数据NaN, 为True表示缺失数据:
mask = df.isnull()
print(mask)

# 每一列的缺失数据
s1 = df.isnull().sum()
print(s1)

# 整个表的缺失数据
number = s1.sum()
print(number)

处理缺失值

处理缺失值的方法有:

  1. 删除法
  2. 替换法
  3. 插值法

删除法

删除法分为删除观测记录(行)和删除特征(列)两种,pandas中提供了简便的删除缺失值的方法dropna,该方法既可以删除观测记录,亦可以删除特征。

pandas 提供的 dropna 方法

# Series 的 dropna 方法
Series.dropna(axis=0, inplace=False, how=None)

# DataFrame 的 dropna 方法
DataFrame.dropna(axis=0, how='any',
                 subset=None, inplace=False)

参数说明

参数名 说明
axis 接收0或1。表示轴向,0为删除记录(行),1为删除特征(列)。默认为0。
how 'any’表示只要有缺失值存在就执行删除操作。‘all’表示当且仅当全部为缺失值时执行删除操作。默认为’any’。
subset 接收类array数据。表示进行去重的列行。默认为None, 表示所有列/行。
inplace True表示是否在原表上进行操作。默认为False。

示例


import numpy as np
import pandas as pd

dates = pd.date_range('20201101', periods=4, freq='W')
df = pd.DataFrame(np.arange(1, 29).reshape(4, 7),
                  index=dates,
                  columns=['Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat', 'Sun'])

df.iloc[1, 0] = np.nan  # 设置为 缺失值 NaN
df.iloc[2, 5] = np.nan
print(df)

df1 = df.dropna()
print(df1)

df2 = df.dropna(axis=1)
print(df2)

# 仅关注 'Sat' 这一列
df3 = df.dropna(subset=['Sat'])
print(df3)

替换法

替换法是指用一个特定的值替换缺失值。离散型和连续型特征出现缺失值时的处理方法也是不同的。

​ 缺失值所在特征为连续型时,通常利用其均值、中位数和众数等描述其集中趋势的统计量来代替缺失值。
​ 缺失值所在特征为离散型时,则经常选择使用众数来替换缺失值。

常用的填补方法:

填补方法 方法描述
均值/中位数/众数 根据属性值的类型用该属性取值的
平均数/中位数/众数进行填补
使用固定值 将缺失的属性值用一个常量替换。
最近临填补 在记录中找到与缺失样本最接近的
样本的该属性值填补
回归方法 对带有缺失值的变量,根据已有数据
和与其有关的其他变量(因变量)的数据建立
拟合模型来预测缺失的属性值
插值法 插值法是利用已知点建立合适的插值函数f(x),
未知值由对应点x求出的函数值f(x)近似代替

示例:

import pandas as pd

data = pd.read_json("../../教学笔记/data/ratings.json")

def func(x):
    '''缺失值使用平均值mean填补'''
    # x[pd.isna(x)] = x.mean()
    # x[pd.isna(x)] = x.min()
    # x[pd.isna(x)] = x.max()
    x[pd.isna(x)] = x.median()
    return x

# 行(垂直方向) 对 缺失值填补平均值
print("处理前:")
print(data)
data.apply(func, axis=0)
print("处理后:")
print(data)

插值法

插值是从已知数据中找到相应规律,填充缺失值的过程。

删除法简单易行,但是会引起数据结构变动,样本减少;

替换法使用难度较低,但是会影响数据的标准差,导致信息量变动。

在面对数据缺失问题时,除了这两种方法之外,还有一种常用的方法—插值法。

scipy提供了插值算法可以通过一组散点得到一个符合一定规律插值器函数。这样当我们给插值器函数更多未知x,插值函数将会返回相应的y用于填补缺失值。

示例:

需求:统计各小区彩民买彩票的情况:

彩民数量 彩票购买量(注)
30 100
40 120
45 -
50 135
60 155
65 170

scipy提供了常见的插值算法可以通过一组散点得到一个符合一定规律插值器函数。若我们给插值器函数更多的散点x坐标序列,该函数将会返回相应的y坐标序列。

scipy提供的插值函数interp1d如下:

scipy.interpolate.interp1d(
    x,  # x 轴数值数组或类列表
    y,  # y 轴数值数组或类列表
    kind='linear',  # 值可以是'linear', 'nearest', 'zero',
                    # 'slinear', 'quadratic', 'cubic' 等
)

示例:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import scipy.interpolate as si

persons = [30, 40, 50, 60, 65]
counts = [100, 120, 135, 155, 170]

plt.scatter(x=persons, y=counts)
func = si.interp1d(x=persons, y=counts)
x = 45
plt.scatter(x=x, y=func(x), marker='^', color='red')
plt.show()

3. 异常值处理

异常值是指不符合规则的数值。如:学生成绩为 -3 分、人的年龄为 180岁等

检测与处理异常值的做法大体包含以下几种:

  • 简单统计量分析
    先对变量做一个描述性统计,找出哪些数据是不合理的,最常用的统计量是求最大值和最小值,判断变量是否在这个区间。
  • 3σ原则
    3σ原则又称为拉依达法则。这种判别处理方法仅适用于对正态或近似正态分布的样本数据进行处理。即超出均值±3σ范围的数据为异常值。
  • 箱线图分析
    箱线图提供了识别异常值的一个标准,即异常值通常被定义为小于QL-1.5IQR或大于QU+1.5IQR的值。

你可能感兴趣的:(python,数据挖掘,数据分析,python)