特征工程之数据规范化

2020-06-15 17:45:03 浏览数 (1)

无量纲化

极差标准化(Min-nax)

Min-max区间缩放法(极差标准化),将数值缩放到[0 1]区间

极大值标准化(Max-abs)

Max-abs (极大值标准化),标准化之后的每一维特征最大要素为1,其余要素均小于1,理论公式如下:

标准差标准化(z-score)

z-score 标准化(标准差标准化)为类似正态分布,均值为0,标准差为1 ,其中均值为,标准差为

归一化——总和标准化

归一化(总和标准化),归一化的目的是将所有数据变换成和为1的数据,常用于权重的处理,在不同数据比较中,常用到权重值来表示其重要性,往往也需要进行加权平均处理。

非线性归一化

非线性归一化:对于所属范围未知或者所属范围是全体实数,同时不服从正态分布的数据, 对其作Min-max标准化、z-score标准化或者归一化都是不合理的。 要使范围为R的数据映射到区间[0,1]内,需要作一个非线性映射。而常用的有sigmoid函数、arctan函数和tanh函数。

代码语言:javascript复制
import seaborn as sns
import numpy as np

df = sns.load_dataset('iris') 
print(df.shape)
df.head()
代码语言:javascript复制
(150, 5)

sepal_length

sepal_width

petal_length

petal_width

species

0

5.1

3.5

1.4

0.2

setosa

1

4.9

3.0

1.4

0.2

setosa

2

4.7

3.2

1.3

0.2

setosa

3

4.6

3.1

1.5

0.2

setosa

4

5.0

3.6

1.4

0.2

setosa

代码语言:javascript复制
# 1.Min-max 区间缩放法-极差标准化
# 自己手写理论公式来实现功能
# 缩放到区间 [0 1]
def Min_max(df):
    x_minmax = []
    for item in df.columns.tolist()[:4]:
        MM = (df[item] - np.min(df[item]))/(np.max(df[item])-np.min(df[item]))
        x_minmax.append(MM.values)
    return np.array(np.matrix(x_minmax).T)[:5]
Min_max(df)
代码语言:javascript复制
array([[0.22222222, 0.625     , 0.06779661, 0.04166667],
       [0.16666667, 0.41666667, 0.06779661, 0.04166667],
       [0.11111111, 0.5       , 0.05084746, 0.04166667],
       [0.08333333, 0.45833333, 0.08474576, 0.04166667],
       [0.19444444, 0.66666667, 0.06779661, 0.04166667]])
代码语言:javascript复制
# 直接调用 sklearn 模块的 API 接口
# 极差标准化(最大最小值标准化)
from sklearn.preprocessing import MinMaxScaler

mms = MinMaxScaler()
x_minmax_scaler = mms.fit_transform(df.iloc[:, :4])
x_minmax_scaler[:5]
代码语言:javascript复制
array([[0.22222222, 0.625     , 0.06779661, 0.04166667],
       [0.16666667, 0.41666667, 0.06779661, 0.04166667],
       [0.11111111, 0.5       , 0.05084746, 0.04166667],
       [0.08333333, 0.45833333, 0.08474576, 0.04166667],
       [0.19444444, 0.66666667, 0.06779661, 0.04166667]])
代码语言:javascript复制
# 2.MaxAbs 极大值标准化
# 自己手写理论公式来实现功能

def MaxAbs(df):
    x_maxabs_scaler = []
    for item in df.columns.tolist()[:4]:
        Max = np.abs(np.max(df[item]))
        MA = np.abs(df[item])/Max
        x_maxabs_scaler.append(MA)
    return np.array(np.matrix(x_maxabs_scaler).T)[:5]

MaxAbs(df)     
代码语言:javascript复制
array([[0.64556962, 0.79545455, 0.20289855, 0.08      ],
       [0.62025316, 0.68181818, 0.20289855, 0.08      ],
       [0.59493671, 0.72727273, 0.1884058 , 0.08      ],
       [0.58227848, 0.70454545, 0.2173913 , 0.08      ],
       [0.63291139, 0.81818182, 0.20289855, 0.08      ]])
代码语言:javascript复制
# 直接调用 sklearn 模块的 API 接口
# 极大值标准化
from sklearn.preprocessing import MaxAbsScaler

mas = MaxAbsScaler()
x_maxabs_scaler = mas.fit_transform(df.iloc[:, :4])
x_maxabs_scaler[:5]
代码语言:javascript复制
array([[0.64556962, 0.79545455, 0.20289855, 0.08      ],
       [0.62025316, 0.68181818, 0.20289855, 0.08      ],
       [0.59493671, 0.72727273, 0.1884058 , 0.08      ],
       [0.58227848, 0.70454545, 0.2173913 , 0.08      ],
       [0.63291139, 0.81818182, 0.20289855, 0.08      ]])
代码语言:javascript复制
# 3.z-score 标准差标准化
# 自己手写理论公式来实现功能
# 标准化之后均值为 0,标准差为 1
def z_score(df):
    N, x_z = df.shape[0], []
    for item in df.columns.tolist()[:4]:
        mean = np.sum(df[item])/N
        std = np.sqrt(np.sum((df[item]-mean)**2)/N)
        Z = (df[item] - mean)/std
        x_z.append(Z)
    return np.array(np.matrix(x_z).T)[:5]
z_score(df)
代码语言:javascript复制
array([[-0.90068117,  1.01900435, -1.34022653, -1.3154443 ],
       [-1.14301691, -0.13197948, -1.34022653, -1.3154443 ],
       [-1.38535265,  0.32841405, -1.39706395, -1.3154443 ],
       [-1.50652052,  0.09821729, -1.2833891 , -1.3154443 ],
       [-1.02184904,  1.24920112, -1.34022653, -1.3154443 ]])
代码语言:javascript复制
# 直接调用 sklearn 模块的 API 接口
# 标准差标准化
from sklearn.preprocessing import StandardScaler

ss = StandardScaler()
x_std_scaler = ss.fit_transform(df.iloc[:, :4])
x_std_scaler[:5]
代码语言:javascript复制
array([[-0.90068117,  1.01900435, -1.34022653, -1.3154443 ],
       [-1.14301691, -0.13197948, -1.34022653, -1.3154443 ],
       [-1.38535265,  0.32841405, -1.39706395, -1.3154443 ],
       [-1.50652052,  0.09821729, -1.2833891 , -1.3154443 ],
       [-1.02184904,  1.24920112, -1.34022653, -1.3154443 ]])
代码语言:javascript复制
# 4.归一化---总和归一化
# 自己手写理论公式来实现功能
# 处理成所有数据和为1,权重处理
def feature_importance(df):
    x_sum_scaler = []
    for item in df.columns.tolist()[:4]:
        S = np.sum(df[item])
        FI = df[item]/S
        x_sum_scaler.append(FI)
    return np.array(np.matrix(x_sum_scaler).T)[:5]
feature_importance(df)
代码语言:javascript复制
array([[0.0058186 , 0.00763192, 0.00248359, 0.00111173],
       [0.00559042, 0.00654165, 0.00248359, 0.00111173],
       [0.00536224, 0.00697776, 0.00230619, 0.00111173],
       [0.00524815, 0.0067597 , 0.00266099, 0.00111173],
       [0.00570451, 0.00784998, 0.00248359, 0.00111173]])
代码语言:javascript复制
# 非线性归一化
# 自己手写理论公式来实现功能
# sigmoid 函数归一化
def sigmoid(df):
    x_sigmoid = []
    for item in df.columns.tolist()[:4]:
        S = 1/(1 np.exp(-df[item]))
        x_sigmoid.append(S)
    return np.array(np.matrix(x_sigmoid).T)[:5]
sigmoid(df)
代码语言:javascript复制
array([[0.9939402 , 0.97068777, 0.80218389, 0.549834  ],
       [0.99260846, 0.95257413, 0.80218389, 0.549834  ],
       [0.9909867 , 0.96083428, 0.78583498, 0.549834  ],
       [0.9900482 , 0.95689275, 0.81757448, 0.549834  ],
       [0.99330715, 0.97340301, 0.80218389, 0.549834  ]])

连续变量离散化(粗度)

连续变量离散化又可以归纳为粗细度调整的问题。

有些时候我们需要对数据进行粗粒度、细粒度划分,以便模型更好的学习到特征的信息,比如:

  • 粗粒度划分(连续数据离散化):将年龄段0~100岁的连续数据进行粗粒度处理,也可称为二值化或离散化或分桶法
  • 细粒度划分:在文本挖掘中,往往将段落或句子细分具体到一个词语或者字,这个过程称为细粒度划分

对于连续变量,为什么还需要进行离散化呢? 离散化有很多的好处,比如能够使我们的模型更加的简单、高效且低耗内存等优点, 因为相对于连续类型数据,离散类型数据的可能性更少。

离散化的通用流程如下: (1)对此特征进行排序。特别是对于大数据集,排序算法的选择要有助于节省时间, 提高效率,减少离散化的整个过程的时间开支及复杂度。 (2)选择某个点作为候选断点,用所选取的具体的离散化方法的尺度进行衡量此候选断点是否满足要求。 (3)若候选断点满足离散化的衡量尺度,则对数据集进行分裂或合并,再选择下一个候选断点,重复步骤(2)(3)。 (4)当离散算法存在停止准则时,如果满足停止准则,则不再进行离散化过程,从而得到最终的离散结果。

特征二值化

思想:设定一个划分的阈值,当数值大于设定的阈值时,就赋值为1,;反之赋值为0。 (提示:赋值的值可以根据实际需要来自定义设定)

阈值阈值 典例(年龄粗划分):

代码语言:javascript复制
# 特征二值化
# 自己手写理论公式来实现功能
def Binarizer(ages):
    ages_binarizer = []
    print('>>>原始的定量数据n', ages)
    for age in ages:
        if (age > 0) and (age <= 18):
            ages_binarizer.append(0)
        elif (age >= 19) and (age <= 40):
            ages_binarizer.append(1)
        elif (age >= 41) and (age <= 60):
            ages_binarizer.append(2)
    print('n>>>特征二值化之后的定性数据n', ages_binarizer)
    return ages_binarizer 

ages = [4, 6, 56, 48, 10, 12, 15, 26, 20, 30, 34, 23, 38, 45, 41, 18]
Binarizer(ages)
代码语言:javascript复制
>>>原始的定量数据
 [4, 6, 56, 48, 10, 12, 15, 26, 20, 30, 34, 23, 38, 45, 41, 18]

>>>特征二值化之后的定性数据
 [0, 0, 2, 2, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 0]





[0, 0, 2, 2, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 0]
代码语言:javascript复制
# 直接调用 sklearn 模块的 API 接口
# binary 二值化
# 使用上面的 IRIS 数据集 
from sklearn.preprocessing import Binarizer

# 阈值自定义为 3.0
# 大于阈值映射为 1,反之为 0
b = Binarizer(threshold=3.0)  
x_binarizer = b.fit_transform(df.iloc[:, :4])
x_binarizer[:5]
代码语言:javascript复制
array([[1., 1., 0., 0.],
       [1., 0., 0., 0.],
       [1., 1., 0., 0.],
       [1., 1., 0., 0.],
       [1., 1., 0., 0.]])

无监督离散化

概念及工作原理 (一)分箱法 分箱法又分为等宽(宽度)分箱法和等频(频数)分箱法,它们的概念介绍如下:

  1. 等宽分箱法(基于属性/特征值大小区间来划分):按照相同宽度将数据分成几等份。
  2. 等频分箱法(基于样本数量区间来划分):将数据分成几等份,每等份数据里面的个数(数量/频数)是一样的。

(二)聚类划分 聚类划分:使用聚类算法将数据聚成几类,每一个类为一个划分。

理论公式及推导 设有一维特征 ,理论假设如下:

(1)等宽分箱法: 假设 X 的最小值 ,最大值 ,那么按照等宽分箱法定义可以将 X 划分成 4 等份,其区间划分为[0, 20], [21, 40], [41, 60], [61, 80],每一个区间对应着一个离散值。

推广通用理论(请注意:为了方便计算,k 从 1 开始,而不是从 0 开始): 设 X 属性值的 ,将连续数据按照等宽法定义离散为 等份,则: 离散值为 划分属性值宽度为 那么划分区间为 k 等份,每个区间对应着一个离散值

(2)等频分箱法: 假设 X 的样本数量有 80 个,那么按照等频分箱法定义,可以划分为 4 等份,每 20 个样本划分为 1 等份。

(3)聚类划分: 使用 K-Means 聚类算法进行无监督划分为 k 等份。

优缺点 无监督的方法的缺陷在于它对分布不均匀的数据不适用,对异常点比较敏感。

代码语言:javascript复制
# 等宽分箱法
# 自己手写理论公式来实现功能
def equal_width_box(data):
    # 划分的等份数、储存等宽分箱离散后的数据
    k, data_width_box = 3, data
    # 分箱的宽度、区间起始值(最小值)、离散值
    width, start, value = (max(data)-min(data))/k, min(data), list(range(1, k 1))
    for i in range(1, k 1):
        # 实现公式 [a (k−1)∗width, a k∗width]
        left = start (i-1)*width  # 左区间
        right = start (i*width)  # 右区间
        print('第 %d 个区间:[%.2f, %.2f]'%(i, left, right))

        for j in range(len(data)):
            if (data[j] >= left) and (data[j] <= right):  # 判断是否属于 value[i] 区间
                data_width_box[j] = value[i-1]

    return data_width_box

data = [4, 6, 56, 48, 10, 12, 15, 26, 20, 30, 34, 23, 38, 45, 41, 18]
equal_width_box(data)
代码语言:javascript复制
第 1 个区间:[4.00, 21.33]
第 2 个区间:[21.33, 38.67]
第 3 个区间:[38.67, 56.00]





[1, 1, 3, 3, 1, 1, 1, 2, 1, 2, 2, 2, 2, 3, 3, 1]
代码语言:javascript复制
# 聚类划分
import seaborn as sns
import numpy as np
from sklearn.cluster import KMeans

data = sns.load_dataset('iris')
X = data.iloc[:,1]
kmeans = KMeans(n_clusters=4)  # 离散为 4 等份
kmeans.fit_transform(np.array(X).reshape(-1, 1))  # 只取一个特征进行聚类离散化
print('>>>原始数据:', X.tolist())
print('>>>聚类离散后:', kmeans.labels_)
代码语言:javascript复制
>>>原始数据: [3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.4, 3.0, 3.0, 4.0, 4.4, 3.9, 3.5, 3.8, 3.8, 3.4, 3.7, 3.6, 3.3, 3.4, 3.0, 3.4, 3.5, 3.4, 3.2, 3.1, 3.4, 4.1, 4.2, 3.1, 3.2, 3.5, 3.6, 3.0, 3.4, 3.5, 2.3, 3.2, 3.5, 3.8, 3.0, 3.8, 3.2, 3.7, 3.3, 3.2, 3.2, 3.1, 2.3, 2.8, 2.8, 3.3, 2.4, 2.9, 2.7, 2.0, 3.0, 2.2, 2.9, 2.9, 3.1, 3.0, 2.7, 2.2, 2.5, 3.2, 2.8, 2.5, 2.8, 2.9, 3.0, 2.8, 3.0, 2.9, 2.6, 2.4, 2.4, 2.7, 2.7, 3.0, 3.4, 3.1, 2.3, 3.0, 2.5, 2.6, 3.0, 2.6, 2.3, 2.7, 3.0, 2.9, 2.9, 2.5, 2.8, 3.3, 2.7, 3.0, 2.9, 3.0, 3.0, 2.5, 2.9, 2.5, 3.6, 3.2, 2.7, 3.0, 2.5, 2.8, 3.2, 3.0, 3.8, 2.6, 2.2, 3.2, 2.8, 2.8, 2.7, 3.3, 3.2, 2.8, 3.0, 2.8, 3.0, 2.8, 3.8, 2.8, 2.8, 2.6, 3.0, 3.4, 3.1, 3.0, 3.1, 3.1, 3.1, 2.7, 3.2, 3.3, 3.0, 2.5, 3.0, 3.4, 3.0]
>>>聚类离散后: [1 3 1 3 1 2 1 1 3 3 2 1 3 3 2 2 2 1 2 2 1 2 1 1 1 3 1 1 1 1 3 1 2 2 3 1 1
 1 3 1 1 0 1 1 2 3 2 1 2 1 1 1 3 0 3 3 1 0 3 0 0 3 0 3 3 3 3 0 0 0 1 3 0 3
 3 3 3 3 3 0 0 0 0 0 3 1 3 0 3 0 0 3 0 0 0 3 3 3 0 3 1 0 3 3 3 3 0 3 0 1 1
 0 3 0 3 1 3 2 0 0 1 3 3 0 1 1 3 3 3 3 3 2 3 3 0 3 1 3 3 3 3 3 0 1 1 3 0 3
 1 3]

类别数据处理

很多算法模型不能直接处理字符串数据,因此需要将类别型数据转换成数值型数据

序号编码(Ordinal Encoding)

通常用来处理类别间具有大小关系的数据,比如成绩(高中低)

假设有类别数据X=[x1,x2,…,xn],则序号编码思想如下:

  • (1)确定X中唯一值的个数K,将唯一值作为关键字,即Key=[x1,x2,…,xk]
  • (2)生成k个数字作为键值,即Value=[0,1,2,…,k]
  • (3)每一个唯一的类别型元素对应着一个数字,即键值对dict={key1:0, key2:1,…, keyk:k}
代码语言:javascript复制
# 序号编码
# 自己手写理论公式实现功能(可优化)
import seaborn as sns

def LabelEncoding(df):
    x, dfc = 'species', df
    key = dfc[x].unique()  # 将唯一值作为关键字
    value = [i for i in range(len(key))]  # 键值
    Dict = dict(zip(key, value))  # 字典,即键值对
    for i in range(len(key)):
        for j in range(dfc.shape[0]):
            if key[i] == dfc[x][j]:
                dfc[x][j] = Dict[key[i]]
    dfc[x] = dfc[x].astype(np.float32)
    return dfc[:5]

data = sns.load_dataset('iris')
le = LabelEncoding(data)
le
代码语言:javascript复制
C:ProgramDataAnaconda3libsite-packagesipykernel_launcher.py:13: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  del sys.path[0]

sepal_length

sepal_width

petal_length

petal_width

species

0

5.1

3.5

1.4

0.2

0.0

1

4.9

3.0

1.4

0.2

0.0

2

4.7

3.2

1.3

0.2

0.0

3

4.6

3.1

1.5

0.2

0.0

4

5.0

3.6

1.4

0.2

0.0

代码语言:javascript复制
# 调用 sklearn 模块的 API 接口
from sklearn.preprocessing import LabelEncoder

le = LabelEncoder()
x_le = le.fit_transform(data['species'])
x_le
代码语言:javascript复制
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])

独热编码(One-hot Encoding)

通常用于处理类别间不具有大小关系的特征,比如血型(A型血、B型血、AB型血、O型血), 独热编码会把血型变成一个稀疏向量,A型血表示为(1,0,0,0),B型血表示为(0,1,0,0),AB型血表示为(0,0,1,0),O型血表示为(0,0,0,1) 提示 (1)在独热编码下,特征向量只有某一维取值为1,其余值均为0,因此可以利用向量的稀疏来节省空间 (2)如果类别型的唯一类别元素较多,可能会造成维度灾难,因此需要利用特征选择来降低维度

假设有类别数据X=[x1,x2,…,xn],则独热编码思想如下:

  • (1)确定X中唯一值的个数K,将唯一值作为关键字,即Key=[x1,x2,…,xk]
  • (2)生成k个数字为1的一维数组作为键值,即Value=[1,1,1,…,k]
  • (3)每一个唯一的类别型元素对应着一个数字,即键值对dict={key1:0, key2:1,…, keyk:k}
  • (4)创建一个空的数组v=V(n维 x k维)=np.zeros((n, k))
  • (5)将数值对应的那一维为1,其余为0,最后将V与原始数据合并即可
代码语言:javascript复制
# 独热编码
# 自己手写理论实现功能
import seaborn as sns
import pandas as pd
import numpy as np

def OneHotEncoding(df):
    x, dfc = 'species', df.copy()
    key = dfc[x].unique()  # (1)
    value = np.ones(len(key))  # (2)
    Dict = dict(zip(key, value))  # (3)
    v = np.zeros((dfc.shape[0], len(key)))  # (4)
    for i in range(len(key)):
        for j in range(dfc.shape[0]):
            if key[i] == dfc[x][j]:
                v[j][i] = Dict[key[i]]  # (5)
    dfv = pd.DataFrame(data=v, columns=['species_']   key)
    return pd.concat([dfc, dfv], axis=1)

data = sns.load_dataset('iris')
ohe = OneHotEncoding(data)
ohe.head()

sepal_length

sepal_width

petal_length

petal_width

species

species_setosa

species_versicolor

species_virginica

0

5.1

3.5

1.4

0.2

setosa

1.0

0.0

0.0

1

4.9

3.0

1.4

0.2

setosa

1.0

0.0

0.0

2

4.7

3.2

1.3

0.2

setosa

1.0

0.0

0.0

3

4.6

3.1

1.5

0.2

setosa

1.0

0.0

0.0

4

5.0

3.6

1.4

0.2

setosa

1.0

0.0

0.0

代码语言:javascript复制
# 调用 sklearn 模块的 API 接口
# 注意要先序号编码再独热哑编码

from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import LabelEncoder

def string_strip(x):
    return x.strip()  # 去除字符串周围的特殊字符(如:逗号、空格等)

ohe_data = np.array(list(map(string_strip, data['species'].tolist())))

le = LabelEncoder()
ohe = OneHotEncoder()

x_le = le.fit_transform(ohe_data)
x_ohe = ohe.fit_transform(x_le.reshape(-1,1)).toarray()
x_ohe[:5]
代码语言:javascript复制
array([[1., 0., 0.],
       [1., 0., 0.],
       [1., 0., 0.],
       [1., 0., 0.],
       [1., 0., 0.]])

除了使用sklearn中的OneHotEncoder类得到哑特征,推荐大家使用Pandas中的get_dummies方法来创建哑特征,get_dummies默认会对DataFrame中所有字符串类型的列进行独热编码:

代码语言:javascript复制
pd.get_dummies(data)

sepal_length

sepal_width

petal_length

petal_width

species_setosa

species_versicolor

species_virginica

0

5.1

3.5

1.4

0.2

1

0

0

1

4.9

3.0

1.4

0.2

1

0

0

2

4.7

3.2

1.3

0.2

1

0

0

3

4.6

3.1

1.5

0.2

1

0

0

4

5.0

3.6

1.4

0.2

1

0

0

...

...

...

...

...

...

...

...

145

6.7

3.0

5.2

2.3

0

0

1

146

6.3

2.5

5.0

1.9

0

0

1

147

6.5

3.0

5.2

2.0

0

0

1

148

6.2

3.4

5.4

2.3

0

0

1

149

5.9

3.0

5.1

1.8

0

0

1

150 rows × 7 columns

二进制编码(Binary Encoding)

二进制编码主要分为两步,先用序号编码给每个类别赋予一个类别ID,然后将类别ID对应的二进制编码作为结果。 以A、B、AB、O血型为例,A型血的ID为1,二进制表示为001;B型血的ID为2,二进制表示为010; 以此类推可以得到AB型血和O型血的二进制表示。可以看出,二进制编码本质上是利用二进制对ID进行哈希映射,最终得到0/1特征向量,且维数少于独热编码,节省了存储空间。

代码语言:javascript复制
from collections import Counter
import pandas as pd
import math


def to_binary(data, col):
    """
    将数据中的某一列使用二进制编码进行替换

    :param data: 原始完整数据
    :param col: 需要使用二进制编码表示的列名称
    :return: 替换后的数据
    """

    # 以字典形式统计当前所选列数据共有多少种取值
    k_dict = Counter(data[col])

    # 计算根据当前取值个数所需要的二进制位数
    max_len = int(math.log2(len(k_dict)))

    # 对每个取值进行二进制映射
    for n, k in enumerate(k_dict.keys()):

        # 计算当前取值的二进制形式
        r = list(bin(n))[2:]

        # 以 0 补足缺少的位数
        r = ['0'] * (max_len - len(r))   r
        k_dict[k] = "".join(r)

    # 使用二进制映射,对所选列数据中的元素进行替换
    # 例如:以 '001' 进行替换
    col_data = data[col].map(k_dict)

    # 将一列数据以 '位' 进行拆分
    new_data = pd.DataFrame()
    for i in range(max_len):
        new_data[f'{col}_{i}'] = col_data.map(lambda x: list(x)[i])

    # 将二进制表示的特征与之前数据进行水平合并并返回
    return pd.concat([data, new_data], axis=1).drop(columns=[col])

重复数据处理

代码语言:javascript复制
#生成数据
data1,data2,data3,data4=['a',3],['b',2],['a',3],['c',2]
df=pd.DataFrame([data1,data2,data3,data4],columns=['col1','col2'])
print(df)
代码语言:javascript复制
  col1  col2
0    a     3
1    b     2
2    a     3
3    c     2
代码语言:javascript复制
#判断数据
isDuplicated=df.duplicated() #判断重复数据记录
print(isDuplicated)
代码语言:javascript复制
0    False
1    False
2     True
3    False
dtype: bool
代码语言:javascript复制
#删除重复的数据
print(df.drop_duplicates()) #删除所有列值相同的记录,index为2的记录行被删除
代码语言:javascript复制
  col1  col2
0    a     3
1    b     2
3    c     2
代码语言:javascript复制
print(df.drop_duplicates(['col1'])) #删除col1列值相同的记录,index为2的记录行被删除
代码语言:javascript复制
  col1  col2
0    a     3
1    b     2
3    c     2
代码语言:javascript复制
print(df.drop_duplicates(['col2'])) #删除col2列值相同的记录,index为2和3的记录行被删除
代码语言:javascript复制
  col1  col2
0    a     3
1    b     2
代码语言:javascript复制
print(df.drop_duplicates(['col1','col2'])) #删除指定列(col1和col2)值相同的记录,index为2的记录行被删除
代码语言:javascript复制
  col1  col2
0    a     3
1    b     2
3    c     2

0 人点赞