### Pandas
#### 数据处理
##### 数据清洗
+ 收集的数据存在脏数据、异常数据、空数据
+ **重复值处理**
+ 检测与处理重复值
1. 记录重复 (重复行) series unique : 不限于两行内容完全一致,关键列信息一致也可以认为是重复行
1. 方法一、利用列表 (list) 进行去重 , 自定义去重函数
2. `DF_name.drop_duplicates(self, subset: Optional[Union[Hashable, Sequence[Hashable]]] = None, keep: Union[str, bool] = "first", inplace: bool = False, ignore_index: bool = False,)`
+ 参数
| 参数 | 描述 |
| ---------------- | ------------------------------------------------------------ |
| **subset** | 列名,可选,默认为None,选取某几列,如果存在重复列,认为原 DF 中该行重复 |
| **keep** | **{‘first’, ‘last’, False}**, 默认值 ‘first’
**first**: 保留第一次出现的重复行,删除后面的重复行。
**last**: 删除重复项,除了最后一次出现。
**False**:删除所有重复项。 |
| **inplace** | 布尔值,默认为False,是否直接在原数据上删除重复项或删除重复项后返回副本。(inplace=True表示直接在原来的DataFrame上删除重复项,而默认值False表示生成一个副本。) |
| **ignore_index** | 忽略 列 |
2. 特征重复 (重复列) -- 根据两列之间的相关性 (相似度) 来确定
+ **相似度[-1, 1]**
+ **1** : 正相关
+ **0** : 无关
+ **-1** : 负相关
+ `df.corr(self, method="pearson", min_periods=1)`
+ 参数
+ **method** : *{"pearson", "kendall", "spearman"}* 计算相似度的方法, 默认 pearson ,常用
+ 实例
```python
import pandas as pd
df1 = pd.DataFrame([
[10, 20],
[50, 100],
[20, 40]],
columns=["A", "B"]
)
# method 计算相似度的方法, 默认 pearson ,常用
# 可选 {"pearson", "kendall", "spearman"}
print(df1.corr(method="pearson"))
"""
正相关
A B
A 1.0 1.0
B 1.0 1.0
"""
df2 = pd.DataFrame([
[10, 0],
[50, 100],
[20, -20]],
columns=["A", "B"]
)
print(df2.corr(method="pearson"))
"""
A B
A 1.000000 0.921551
B 0.921551 1.000000
"""
```
+ **空值 (缺失值) 处理**
1. 检测缺失值
1. 使用 `DF_name.isnull()` 的方式判断, 如果是缺失值返回 True,否则返回 False (通常与 sum() 连用 `.isnull().sum()` 返回空值的数目) ***常用于 Series***
```python
import pandas as pd
df2 = pd.DataFrame([
[10, ],
[50, 100],
[20, -20]],
columns=["A", "B"]
)
# 检测缺失值
print(df2.isnull())
"""
A B
0 False True
1 False False
2 False False
"""
print(df2.isnull().sum())
"""
A 0
B 1 1个缺失值
dtype: int64
"""
print(df2.notnull())
print(df2.notnull().sum())
"""
A B
0 True False
1 True True
2 True True
A 3
B 2
dtype: int64
"""
```
2. `DF_name.notnull()` : 如果不是缺失值返回 True , 否则返回 False **常用于 *Series***
3. `DF_name.info()` : **常用于 *DataFrame***
```python
import pandas as pd
df2 = pd.DataFrame([
[10, ],
[50, 100],
[20, -20]],
columns=["A", "B"]
)
print(df2.info())
"""
RangeIndex: 3 entries, 0 to 2
Data columns (total 2 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 A 3 non-null int64
1 B 2 non-null float64
dtypes: float64(1), int64(1)
memory usage: 176.0 bytes
None
"""
```
2. 处理缺失值
1. 删除 : `DF_name.dropna(self, axis=0, how="any", thresh=None, subset=None, inplace=False)`
+ 参数
| 参数 | 描述 |
| ----------- | ------------------------------------------------------------ |
| **axis** | **{0 or 'index', 1 or 'columns'}, default 0** **0** --> 删除行 , **1** --> 删除列 |
| **how** | **{'any', 'all'}, default 'any'**
**any** --> 该行或列存在空值则删除
**all** --> 该行或列全为空值则删除 |
| **thresh** | **int, optional**设定阈值,缺失值个数大于该阈值,整行(axis=0)或整列(axis=1)才会被删除 |
| **subset** | subset=[1,2], 删除指定列(1,2)中包含缺失值的行 |
| **inplace** | 默认为 False 不改变原数据 , 为 True 时改变其原数据 |
+ 实例
```python
import pandas as pd
df2 = pd.DataFrame([
[10, ],
[50, 100],
[20, -20]],
columns=["A", "B"]
)
# 处理缺失值
df2.dropna(axis=0, how="any", inplace=True)
print(df2)
"""
A B
1 50 100.0
2 20 -20.0
"""
```
2. 填充 : `DF_name["计量填充"]/DF_name完全填充.fillna(self, value=None, method=None, axis=None, inplace=False, limit=None, downcast=None,)`
+ 参数
| 参数 | 描述 |
| ----------- | ------------------------------------------------------------ |
| **value** | **填充值** 与 method 只能同时存在一个 |
| **method** | **{‘pad’, ‘ffill’,‘backfill’, ‘bfill’, None}, default None**
**pad/ffill**:用**前一个**非缺失值去填充该缺失值
**backfill/bfill**:用***\*下一个\****非缺失值填充该缺失值
***\*None\****:指定一个值去替换缺失值(缺省默认这种方式) |
| **axis** | 修改填充方向 |
| **inplace** | True、False
**True**:直接修改原对象
**False**:创建一个副本,修改副本,原对象不变(缺省默认) |
| **limit** | limit参数:限制填充个数 |
3. 插值法 : 在自变量和因变量之间的,建立一个模型(方程)新得数据输入模型---产生插值结果
+ **线性插值 interp1d ** : 自变量和因变量之间具有一次线性关系(y=ax+b) 多元一次
+ **多项式,非线性插值 lagrange ** : 拉格朗日 拟合的是一个多项式;自变量和因变量是线性关系和非线性关系都可以很好的拟合
+ 实例
```python
from scipy.interpolate import interp1d # 线性插值
# 线性插值不能很好地拟合非线性问题
from scipy.interpolate import lagrange
# 拉格朗日 拟合的是一个多项式;自变量和因变量是线性关系和非线性关系都可以很好的拟合
import numpy as np
import pandas as pd
x_data = np.array([1, 2, 3, 4, 5, 6, 7])
y_data = np.array([3, 5, 7, 9, np.nan, np.nan, 15]) # 2x+1
y_data2 = np.array([2, 8, 18,32, np.nan, np.nan, 98]) # 2* x^2
df = pd.DataFrame(data={"A":x_data, "B":y_data})
print(df)
# b_nona = df["B"].notnull()
# print(b_nona)
# 取出非空值
new_df = df.dropna(how='any', axis=0) # axis=0删除行
# 插值的使用
# 1、拟合方程(模型)
linear = interp1d(new_df["A"], new_df["B"])
# print("插值结果", linear([5,6])) # 预测
# lagrange 限制输入数据类型为数组
lar = lagrange(new_df["A"].values, new_df["B"].values)
print("插值结果", lar([5,6]), type(lar([5,6])))
print('-'*50)
# na_mask = df["B"].isnull()
# new_x = df.loc[na_mask, "A"] # 新的输入数据
# print(new_x.values)
# new_y = linear(new_x.values) # 新的输出数据
# df.loc[na_mask, "B"] = new_y
#
# print("插值后的结果\n", df)
```
+ **异常值处理**
+ 检测与处理异常值
+ 异常值是指数据中个别值的数值明显偏离其他的数值,有时也称为 **离群点**
+ 检测异常值 : 监测数据中是否有录入错误以及不合理的数据
+ **具体业务法**
+ 根据对业务的理解,制订一个合理的范围,超出此范围则为异常值
+ **3 σ(sigma)原则**
+ 又称为 **拉依达法则**,假设数据属于正态分布数据,返回不属于正态分布的数据 *仅适用于对正态或近似正态分布的样本数据进行处理*
+ 该法则就是先假设一组检测数据只含有随机误差,对原始数据进行计算处理得到标准差,然后按一定的概率确定一个区间,认 为误差超过这个区间的就属于异常值。
+ 数据的数值分布几乎全部集中在区间(μ-3σ,μ+3σ)内,超出这个范围的 数据仅占不到 0.3%。故根据小概率原理,可以认为超出 3σ的部分数据为异常数 据。 表
+ **箱线图分析法**
+ 提供了识别异常值得一个标准,即异常值通常被定义为**小于 QL-1.5IQR** 或**大于 QU+1.5IQR** 的值
+ **QL** 称为下四分位数,表示全部观察值中有四分之一的数据取值比它小。
+ **QU** 称为上四分位数,表示全部观察值中有四分之一的数据取值比它大。
+ **IQR** 称为四分位数间距,是上四分位数 QU 与下四分位数 QL 之差,其间包含 了全部观察值的一半。
+ 四分位数给出了数据分布的中心、散布和形状的某种指示,具有一定的鲁棒 性,即 25%的数据可以变得任意远而不会很大地扰动四分位数,所以异常值通常 不能对这个标准施加影响。鉴于此,箱线图识别异常值的结果比较客观,因此在 识别异常值方面具有一定的优越性
+ 实例
```python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 产生数据 (50 人的成绩) 生成异常值 [-10, 120]
# arr = np.random.uniform(-10, 120, size=50)
arr = np.random.uniform(-10, 0, size=3)
# 生成 50 个数据
arr = np.hstack((arr, np.arange(200, 400, 4)))
# print(arr)
df = pd.DataFrame({"成绩": arr})
# print(df)
# 异常值处理
# 1. 具体业务法
def get_normal_score(val):
low = 0
high = 100
return low <= val <= high
# 在正常范围 返回 True 异常值返回 False
mark1 = df["成绩"].transform(get_normal_score)
final_df1 = df.loc[mark1, :]
# 3 σ 法
def three_sigma(val):
# 均值
mean_val = val.mean()
std_val = val.std()
low = mean_val - 3 * std_val
high = mean_val + 3 * std_val
return (low <= val) & (val <= high)
mark2 = df["成绩"].transform(three_sigma)
print(mark2.values, mark2.shape)
final_df2 = df.loc[mark2, :]
print(type(final_df2))
# 箱线图分析法 (最小值、最大值、下四分位数(QL)、上四分位数(QU)、中位数)
# IQR = QU - QL
# low = QL - 1.5 * IQR
# high = QU + 1.5 * IQR
def box_analysis(val):
# 上下四分位数
QL, QU = val.quantile([0.25, 0.75])
IQR = QU - QL
low = QL - 1.5 * IQR
high = QU + 1.5 * IQR
return (low <= val) & (val <= high)
mark3 = df["成绩"].transform(box_analysis)
print(mark3.values, mark3.shape)
final_df3 = df.loc[mark3, :]
print(type(final_df3))
print(final_df3)
```