目录
B.1分类数据(categorical or nominal data)
2.2. 利用sklearn提供二值化模块Binarizer实现二值化
特征的类型由其所有值的集合决定,通常有如下几种。
A.数值型(连续型)
- 特征的值如果是整数或浮点数,那么这类特征就是"数值型"的,也可以分别称为整数型特征或浮点数型特征。
B.离散型
- 特征取值数量有限,每个值表示一种状态、类别,不能进行计算。
- 特征的值如果是字符串,这些值不能直接输入机器学习算法中,通常要经过转换,例如使用 OneHot 编码实现转换。
- 分类型特征的值如果是数字,这些值并不是定量的,计算值、中位数等没有什么意义。
B.1分类数据(categorical or nominal data)
- 是只能归于某一类别的非数字型数据,它是对事物进行分类的结果,数据表现为类别,是用文字来描述的。例如:
- 例如,“性别”的值一般是"男"或者"女",即使分别用1和0表示,也不意味有某种顺序。
- 再如,"职业"的值可能是"商、农、工、士"中的些值没有顺序(也没有高低贵贱之分)。
B.1.1二分类型*
- 特征的值如果只有两种状态,比如0或1,那么这类特征就是"二值型的,显然它也是分类型的。二值型特征也可以称为"二元型特征"或者"布尔型特征"。
- 有的二值型特征的两个状态是等价的,例如在性别中,用0表示女,也可以用0表示男,这两个状态并不存在不同的权重。与之不同的是,另外-类二值型特征,其不同状态表示不同的重要程度,通常用1表示更重要的状态,用0表示另一种状态。例如,对普通大众的HTV检验,呈阳性的用1表示,呈阴性的用0表示——就正常社会群体而言,携带HIV病毒的人数是稀少的。在如此得到的数据中,0的数量就比较多,这样的数据称为"稀疏的"。
B.1.2多分类*
- 特征的值如果只有多种状态,"职业"的值可能是"商、农、工、士"中的些值没有顺序(也没有高低贵贱之分)。
B.2 顺序数据(Ordinal data)
- 是只能归于某一有序类别的非数字型数据。顺序数据虽然也是类别,但这些类别是有序的。
顺序型
对于前面的多分类型特征和二值型特征的值,其排序都没有意义。如果有像"职称"这样的特征,其值分别为"讲师"、"副教授"、"教授",从某个角度讲,它们就具有顺序,这样的特征称为顺序型特征。顺序型特征的值可以是数字。
-
*例:
-
(1)将产品分为一等品、二等品、三等品、次品等;
-
(2)考试成绩可以分为优、良、中、及格、不及格等;
-
(3)一个人的受教育程度可以分为小学、初中、高中、大学及以上
-
(4)一个人对某一事物的态度可以分为非常同意、同意、保持中立、不同意、非常不同意,等,问卷调查(李克特量表常使用)
-
此外,顺序型特征还可以通过对连续型特征离散化而得到。比如,学生的考试成绩按照下面的原则划分等级∶A(90~100分)B(75~<90分)人C(60~<75分)、D(45~<60分)、E(45分以下)。
- 之所以要分辨不同类型的特征,是因为机器学习算法对特征的类型会有所偏好,不合适的就要通过特征变换,以适合算法对数据的要求。并且,通过特征变换之后,数据的可解释性可得到提高。
1. 特征数值化(分类型特征转数值)
1.1. df.replace方法 字符串替换为数值
#将数据集中的Y、N替换为数字,比如用1替换Y,用0替换N,
df1=df.replace({"N": 0, 'Y': 1})
df1
1.2. sklearn中专有模块LabelEncoder
字符串转数值 数值
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
le.fit_transform(df['hypertension']) #包括了训练又包含了转换
#实例化LabelEncoder,得到了一个实现特征数值化的模型实例,用它训练特征中的数据,即可得到其中的枚举值。
#特征"hypertension"是分类或者二值型的,le实例能自动从0开始,将每个值用整数替换。
1.3. 项目案例
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder() # ①
le.fit(['white', 'green', 'red', 'green', 'white']) # ②
le.classes_ # ③
>>>
ray(['green', 'red', 'white'], dtype='<U5')
①创建了模型;②用参数中的数据进行训练,创建了能够对含有“white”、“green”、“red”三个值的特征进行数值化的模型le;③显示自动分类的结果。从结果来看,三个字符串依次对应0、1、2。
le.transform(["green", 'green', 'green', 'white']) # ④
#使用②训练的模型对另外一批数据(参数内显示的数据)进行转换,得到了所示的结果。
#前面所使用过的fit_transform相当于②和④的合并。
>>>
array([0, 0, 0, 2])
#如果④中出现了超出所得分类的参数,就会报错了
le.transform(["green", 'green', 'green', 'blue'])
2. 特征二值化
不论是连续型特征还是离散型特征,都可以进行二值化变换,其通常则是∶
2.1. np.where函数完成阈值判断和赋值
#任务:以平均值为阈值,对特征“Exposed day”进行二值化
import numpy as np
pm25['bdays'] = np.where(pm25["Exposed days"] > pm25["Exposed days"].mean(), 1, 0)
pm25.sample(5)
#新增加的特征"bdays"是对"Exposed days"二值化之后所得到的二值型特征。
#用np.where 函数完成了阈值的判断和相应赋值。#
#print(type(pm25["Exposed days"].mean()))
2.2. 利用sklearn提供二值化模块Binarizer实现二值化
#可以使用scikit-learn提供的二值化模块 Binarizer 实现特征二值化
from sklearn.preprocessing import Binarizer
bn = Binarizer(threshold=pm25["Exposed days"].mean()) # ①
result = bn.fit_transform(pm25[["Exposed days"]]) # ②
#参数是 pm25([“[Exposed days"]]),旨在得到一个形状为一列的 DataFrame对象
pm25['sk-bdays'] = result
pm25.sample(10)
binarzne的函数
#另外,与模块Biaizer 等效的还有一个 名为binarzne的函数。
from sklearn.preprocessing import binarize
fbin = binarize(pm25[['Exposed days']], threshold=pm25['Exposed days'].mean())
fbin[[1, 50, 100, 150, 200]]
#在 scikit-leam的模块中,有一些模块类似于Binarizer,
#会对应一个同名的函数,在使用的时候,这两者等效。
>>>
array([[0],
[0],
[0],
[1],
[1]])
- np.random.normal(loc=0.0, scale=1.0, size=None)
- 参数解释:
- loc(float):此概率分布的均值(对应着整个分布的中心centre
- scale(float):此概率分布的标准差(对应于分布的宽度,scale越大,图形越矮胖;scale越小,图形越瘦高)
- size(int or tuple of ints):输出的shape,默认为None,只输出一个值
动手练习
import datetime
print(pd.read_csv("mydata/marathon.csv").head())
def convert_time(s):
h,m,s = map(int, s.split(":"))
return datetime.timedelta(hours=h, minutes=m, seconds=s)
marathon = pd.read_csv("mydata/marathon.csv",
converters={"split":convert_time,
"final":convert_time})
marathon.head(3)
marathon['split'] = marathon['split'].astype(int) * 1e-9
marathon['final'] = marathon['final'].astype(int) * 1e-9
marathon.head()
marathon['frac'] = 1 - 2 * marathon['split'] / marathon["final"]
marathon.head()
marathon['split_frac'] = np.where(marathon['frac']>0, 0, 1)
marathon.sample(10)
3. OneHot编码
import pandas as pd
g = pd.DataFrame({"gender": ["man", 'woman', 'woman', 'man', 'woman']})
g
特征"gender"的值除了man就是 woman,按照前面对特征类内述.它是分类型特征,也是二值型特征。并且,经用"数值化"的方式处理过这种类型的特征,但是数值化会带来原本没有的”大小关系”。 为了避免这种“副作用”的出现,换一种处理方式
3.1. pd.get_dummies生成哑变量
pd.get_dummies(g)
自动生成了两个新特征
dummies 英 [ˈdʌmiz] 美 [ˈdʌmiz] n. (尤指缝制或陈列服装用的)人体模型;仿制品;仿造物;笨蛋;蠢货
pandas.get_dummies(data, prefix=None, prefix_sep='_', dummy_na=False, columns=None, sparse=False, drop_first=False, dtype=None)
其作用是将分类型特征转化为“虚拟变量”(也译为“哑变量”)
-
prefix:str, list of str, 或 dict of str, 默认为 None 用于追加DataFrame列名称的字符串。
-
prefix_sep:str, 默认为 ‘_’如果附加前缀,则使用分隔符/分隔符。或者像这样传递列表或字典prefix。
-
dummy_na:bool, 默认为 False 忽略False NaN。
-
columns:list-like, 默认为 None 要编码的DataFrame中的列名。如果columns为None,则所有具有的列object或者categorydtype将被转换。
-
sparse:bool, 默认为 False
-
dummy-encoded列是否应由a支持SparseArray(True)或常规NumPy数组(False)。
** dropfirst:bool, 默认为 False* 是否通过删除第一个级别从k个分类级别中获取k-1个虚拟对象
pd.get_dummies(g,prefix="1",prefix_sep="_")
persons = pd.DataFrame({"name":["Newton", "Andrew Ng", "Jodan", "Bill Gates"],
'color':['white', 'yellow', 'black', 'white']})
persons
df_dum = pd.get_dummies(persons['color'], drop_first=True)
persons.merge(df_dum, left_index=True, right_index=True)# 按索引值进行连接
#三个类别也一样创建虚拟变量,并且还是要去掉一个冗余特征
3.2. sklearn中的OneHotEncoder
from sklearn.preprocessing import OneHotEncoder
ohe = OneHotEncoder()
features = ohe.fit_transform(persons[['color']])
#features
print(features)
features.toarray()
data=pd.DataFrame(features.toarray())
data
OneHotEncoder模块的使用方法与前面已介绍过的scikit-leam中其他块的使用方法一样,不再赘述。但是,在OneHotEncoder模块中,没有提类似get_dummies中的参数drop_first,要去掉一个虚拟变量,只能用Numpy的数组切片操作。
features.toarray()[:, 1:]
动手练习:
df = pd.DataFrame({
"color": ['green', 'red', 'blue', 'red'],
"size": ['M', 'L', 'XL', 'L'],
"price": [29.9, 69.9, 99.9, 59.9],
"classlabel": ['class1', 'class2', 'class1', 'class1']
})
df
df["classlabel"].unique()
>>>
array(['class1', 'class2'], dtype=object)
# 第1题 对'classlabel'进行onehot编码
from sklearn.preprocessing import OneHotEncoder
ohe = OneHotEncoder()
cl = ohe.fit_transform(df[['classlabel']])
cl.toarray()
fs_two=pd.DataFrame(cl.toarray()[:,1:],columns=["classlabel_"])
fs_two
df = pd.concat([df, fs_two], axis=1)
df
# 第2题
df = pd.read_csv("/home/aistudio/data/data170095/breast-cancer.data", header=None).iloc[:, 1:]
dataset = df.values
X = dataset[:, 0:8]
X = X.astype(str)
Y = dataset[:, 8]
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OneHotEncoder
import numpy as np
encoded_x = None
for i in range(0, X.shape[1]):
label_encoder = LabelEncoder() # 数值化
feature = label_encoder.fit_transform(X[:,i])
feature = feature.reshape(X.shape[0], 1)
onehot_encoder = OneHotEncoder(sparse=False) # OneHot编码
feature = onehot_encoder.fit_transform(feature)
if encoded_x is None:
encoded_x = feature
else:
encoded_x = np.concatenate((encoded_x, feature), axis=1)
print("X shape: : ", encoded_x.shape)
X shape: : (286, 41)
label_encoder = LabelEncoder()
label_encoder = label_encoder.fit(Y)
label_encoded_y = label_encoder.transform(Y)
label_encoded_y
4. 数据变换
4.1. 多项式变换
import numpy as np
X = np.arange(6).reshape(3, 2)
X
>>>
array([[0, 1],
[2, 3],
[4, 5]])
- 这个简单的数据包含两个变量(列、特征),分别用x1、x2表示,
- 如果要用这两个变量创建一个最高项为2的多项式,即
- 1+x1+x2+x1²+x1x2+x2² 式①
- 用此多项式的各项对原数据进行计算,并将结果作为新特征,这就是所谓的“多项式变换”。
from sklearn.preprocessing import PolynomialFeatures # ③
poly = PolynomialFeatures(2) # ④
poly.fit_transform(X)
>>>
array([[ 1., 0., 1., 0., 0., 1.],
[ 1., 2., 3., 4., 6., 9.],
[ 1., 4., 5., 16., 20., 25.]])
引入了scikit-leam的多项式模型PolynomialFeatures,④创建此模型实例,其中的参数2表示创建最高项为2的多项式,即如同“式①”那样。4.1的结果为根据“式①”各项计算的所得内容。
4.2. Box_Cox变换
dc_data = pd.read_csv('/home/aistudio/data/data170095/sample_data.csv')
#数据进行处理之前,先观察它的分布
%matplotlib inline
import matplotlib.pyplot as plt
h = plt.hist(dc_data['AIR_TIME'], bins=100)
#array和asarray都可以将结构数据转化为ndarray,但是主要区别就是当数据源是ndarray时,
#array仍然会copy出一个副本,占用新的内存,但asarray不会。
#dc_data【'AIR_TIME】中的数据不是标准的正态分布,下面就对它进行变换
from scipy import stats
transform = np.asarray(dc_data[['AIR_TIME']].values)
print(transform)
dft = stats.boxcox(transform)[0] # ⑤
hbc = plt.hist(dft, bins=100)
- scipy是一个专门用于科学计算的第三方库,它提供Box-Cox变换函数,即可实现Box-Cox变换。
- 再绘制直方图看看效果,操作让数据更趋于"正态分布"。
- 除在scipy提供了实现Box-Cox变换的函数外,在scikit-lcam中也有相应函数供使用。
Box-Cox属于广义幂变换,sklearn.preprocessing中的power_transform函数的命名也符合了这种说法。
#Box-Cox属于广义幂变换,sklearn.preprocessing中的power_transform函数的命名也符合了这种说法。
#利用power_transform函数,除了可以实现Box-Cox变换
from sklearn.preprocessing import power_transform
dft2 = power_transform(dc_data[['AIR_TIME']], method='box-cox') # ⑥
hbcs = plt.hist(dft2, bins=100)