菜鸟笔记
提升您的技术认知

Python 对数据one-hot编码

离散特征的编码分为2种情况:

1.我们在进行那些有大小关系的变量离散,小雨,中雨,大雨,

{“小雨”:1,“中雨”:2,“雨天”:3},这里面有一定数量的大小关系,这种映射的讲解在法1:标签的处理

2.只是换个名字的标签处理晴天,阴天,雨天这种标签没有大小的关系,那就考虑one-hot编码,或者说产生哑变量。

连续变量的离散化处理

比如说,分数,需要将数据划分为“0到60”,“61到79”,“79到100”几个分数组。用的是pd.cut(data,bins),这里的data是我们要分割的分数数据,bins是[0,60,79,100]。类似函数可学习pd.qcut

import pandas as pd
df = pd.DataFrame({"key":['green','red', 'blue'],
            "data1":['a','b','c'],"sorce": [33,61,99]})
bins=[0,61,80,100]
cats=pd.cut(df["sorce"],bins)
print(cats)
group_name=["不及格","及格","优秀"]
cats2=pd.cut(df["sorce"],bins,labels=group_name,right=False)
#df["sorce"]为数据
#bins指定划分
#right指定区间闭合方向
#labels指定切分结果的标签
print(cats2)
############结果
0      (0, 61]
1      (0, 61]
2    (80, 100]
Name: sorce, dtype: category
Categories (3, object): [(0, 61] < (61, 80] < (80, 100]]
0    不及格
1     及格
2     优秀
Name: sorce, dtype: category
Categories (3, object): [不及格 < 及格 < 优秀]

那我们可以设计0-60分的需要编码为1,61-79为合格,80-100为优秀,这个和上面的第一条类似,只是需要一个数据划分的步骤,详见法2的相关处理。

pd.cut(data,4,precision=2) ,根据最大值与最小值计算等长面元长度。将数据分成4组(无法使各个面元中含有相同数量的数据点)精确度2位小数。

pd.qcut(data,[0,0.1,0.5,0.9,1]),根据样本分位数bins对数据进行面元划分,设置的是自定义分位数,0到1之间的数值,包含端点

法1.标签的处理:

#建立对应关系
label2current_service = dict(zip(range(0, len(set(df['current_service']))), sorted(list(set(df['current_service'])))))

current_service2label = dict(zip(sorted(list(set(df['current_service']))), range(0, len(set(df['current_service'])))))

# 原始数据的标签映射
df['current_service'] = df['current_service'].map(current_service2label)

#df['current_service']是一列代表类别的数据,上面是重新编码
from sklearn import  svm
clf = svm.SVC(decision_function_shape='ovr')
clf.fit(X_trainData, df['current_service'])

y_test_predict = model.predict(X_testData)

y_test_predict_DateFrame=pd.DataFrame(y_test_predict,columns=["predict"],index=X_testData.index)

#标签还原   
y_test_predict_DateFrame['predict'] = y_test_predict_DateFrame['predict'].map(label2current_service)
  

上面是一个数据处理,模型训练,预测比较完整的处理流程,如果需要更明了一点的可参考:官方文档

#-*-coding=utf-8-*-
import pandas as pd  
df = pd.DataFrame([  
            ['green', 'M', 10.1, 'class1'],   
            ['red', 'L', 13.5, 'class2'],   
            ['blue', 'XL', 15.3, 'class1']])  
  
df.columns = ['color', 'size', 'prize', 'class label']  
  
size_mapping = {  
           'XL': 3,  
           'L': 2,  
           'M': 1}  
df['size'] = df['size'].map(size_mapping)  
  
class_mapping = {label:idx for idx,label in enumerate(set(df['class label']))}  
df['class label'] = df['class label'].map(class_mapping)
print('----------------------------------------------------------------')
 
print(df)
参考来源:https://blog.csdn.net/dongyanwen6036/article/details/78555163

这个结果第一个显示的是法1 ,映射的编码。下面的结果是法2,pandas 有一个get_dummies函数。具体见法2的介绍

 

法2.计算指标/哑变量one-hot编码

将分类变量装换为“哑变量矩阵”(dummy matrix).如果DataFrame的某一列中含有K个不同的值,则可以派生出一个K列矩阵或者DataFrame(其值全为0和1)。pandas 有一个get_dummies函数可以实现该功能(当然自己动手也可以哒)

 参考:利用Python进行数据分析 第七章 

pandas.get_dummies(dataprefix=Noneprefix_sep='_'dummy_na=Falsecolumns=Nonesparse=Falsedrop_first=Falsedtype=None)[source]¶

#!/ Mypython
# -*- coding: utf-8 -*-
# @Time    : 2018/9/15 21:19
# @Author  : LinYimeng
# @File    : ceshi.py
# @Software: PyCharm
import pandas as pd
df = pd.DataFrame({"key":['green','red', 'blue'],
            "data1":['a','b','c'],"sorce": [33,61,99]})
# get_dummies(data,....) 在不指定新列的列名的情况下,将以data原标签对为列名
print("-------df---------")
print(df)
df_dummies1 =pd.get_dummies(df["key"])
print('''-------pd.get_dummies(df["key"])--df_dummies1-------''')
print(df_dummies1)
#prefix参数可以给哑变量的名字加上一个前缀
df_dummies2 =pd.get_dummies(df["key"],prefix="key")
print('''---=pd.get_dummies(df["key"],prefix="key")----df_dummies2-----''')
print(df_dummies2)
#如果不指定data列的话,默认是所有的分类变量进行one_hot处理
df_dummies3 =pd.get_dummies(df)
print("-------pd.get_dummies(df)---df_dummies3------")
print(df_dummies3)
#prefix参数可以给哑变量的名字加上一个前缀,如果是多个则需要一个列参数
df_dummies4 =pd.get_dummies(df,prefix=["class","like"])
print('''-------pd.get_dummies(df,prefix=["class","like"])----df_dummies4-----''')
print(df_dummies4)


df_dummies5 =pd.get_dummies(df,columns=["key","sorce"])
print('''---=pd.get_dummies(df,columns=["key","sorce"])----df_dummies5-----''')
print(df_dummies5)

同时在pandas可以指定 columns参数,pd.get_dummies(df,columns=["key","sorce"])指定被编码的列,返回被编码的列和不被编码的列;prefix参数可以给哑变量的名字加上一个前缀。

也可以类似的尝试:
# 性别
data['Sex'] = data['Sex'].map({'female': 0, 'male': 1}).astype(int)
-------df---------
  data1    key  sorce
0     a  green     33
1     b    red     61
2     c   blue     99
-------pd.get_dummies(df["key"])---df_dummies1------
   blue  green  red
0   0.0    1.0  0.0
1   0.0    0.0  1.0
2   1.0    0.0  0.0
---=pd.get_dummies(df["key"],prefix="key")----df_dummies2-----
   key_blue  key_green  key_red
0       0.0        1.0      0.0
1       0.0        0.0      1.0
2       1.0        0.0      0.0
-------pd.get_dummies(df)----df_dummies3-----
   sorce  data1_a  data1_b  data1_c  key_blue  key_green  key_red
0     33      1.0      0.0      0.0       0.0        1.0      0.0
1     61      0.0      1.0      0.0       0.0        0.0      1.0
2     99      0.0      0.0      1.0       1.0        0.0      0.0
-------pd.get_dummies(df,prefix=["class","like"])---df_dummies4------
   sorce  class_a  class_b  class_c  like_blue  like_green  like_red
0     33      1.0      0.0      0.0        0.0         1.0       0.0
1     61      0.0      1.0      0.0        0.0         0.0       1.0
2     99      0.0      0.0      1.0        1.0         0.0       0.0
---=pd.get_dummies(df,columns=["key","sorce"])----df_dummies5-----
  data1  key_blue  key_green  key_red  sorce_33  sorce_61  sorce_99
0     a       0.0        1.0      0.0       1.0       0.0       0.0
1     b       0.0        0.0      1.0       0.0       1.0       0.0
2     c       1.0        0.0      0.0       0.0       0.0       1.0

Process finished with exit code 0

结合pd.cut,处理连续变量

bins=[0,61,80,100]
cats=pd.cut(df["sorce"],bins)
print(cats)
group_name=["不及格","及格","优秀"]
cats2=pd.cut(df["sorce"],bins,labels=group_name,right=False)
print(cats2)
print(pd.get_dummies(cats2,prefix="sorce"))#   right是否是区间闭端
#prefix指定0-1编码后列名前缀
#结果
   sorce_不及格  sorce_及格  sorce_优秀
0        1.0       0.0       0.0
1        0.0       1.0       0.0
2        0.0       0.0       1.0

合并():要注意使用merge还是join

#merge是因为两个合并的对象,有相同的列,merge以这些相同的列为索引进行合并。按照索引合并,就会出现两个sorce,不可以join

#join实现按索引合并,而不管他们有么有相同的列.同时可以指定on ="keyname',则把两个df 按照索引链接,并将原索引为新的“keyname”列,重新设置0,1,2..的索引

#join此处不可以,ValueError: columns overlap but no suffix specified: Index(['sorce'], dtype='object')
#merge是因为两个合并的对象,有相同的列,merge以这些相同的列为索引进行合并。
df_new= pd.merge(df,df_dummies3)
print(df_new)
print(df_new.columns)

----------------
  data1    key  sorce  data1_a  data1_b  data1_c  key_blue  key_green  key_red
0     a  green     33      1.0      0.0      0.0       0.0        1.0      0.0
1     b    red     61      0.0      1.0      0.0       0.0        0.0      1.0
2     c   blue     99      0.0      0.0      1.0       1.0        0.0      0.0
Index(['data1', 'key', 'sorce', 'data1_a', 'data1_b', 'data1_c', 'key_blue',
       'key_green', 'key_red'],
      dtype='object')

----------------------
#merge此处不可以, 两个没有相同的列。pandas.tools.merge.MergeError: No common columns to perform merge on
#join实现按索引合并,而不管他们有么有相同的列.同时可以指定on ="keyname',则把两个df 按照索引链接,并将原索引为新的“keyname”列,重新设置0,1,2..的索引
df_new= df.join(df_dummies6)
print(df_new)
print(df_new.columns)
-------------------
data1    key  sorce  sorce_不及格  sorce_及格  sorce_优秀
0     a  green     33        1.0       0.0       0.0
1     b    red     61        0.0       1.0       0.0
2     c   blue     99        0.0       0.0       1.0
Index(['data1', 'key', 'sorce', 'sorce_不及格', 'sorce_及格', 'sorce_优秀'], dtype='object')