特徵工程中常用的數據處理方式

特徵工程

學習地址

數據集地址

Tip1:特徵無量綱化的常見操作方法

作爲筆記。
第一招,從簡單的特徵量綱處理開始,這裏介紹了3種無量綱化操作的方法。

無量綱化:即nondimensionalize 或者dimensionless,是指通過一個合適的變量替代,將一個涉及物理量的方程的部分或全部的單位移除,以求簡化實驗或者計算的目的。——百度百科

進行進一步解釋,比如有兩個字段,一個是車行走的公里數,另一個是人跑步的距離,他們之間的單位其實差異還是挺大的,其實兩者之間無法進行比較的,但是我們可以進行去量綱,把他們的變量值進行縮放,都統一到某一個區間內,比如0-1,便於不同單位或者量級之間的指標可以進行比較or加權!

下面的是sklearn裏的一些無量綱化的常見操作方法。

from sklearn.datasets import load_iris  
#導入IRIS數據集  
iris = load_iris()

#標準化,返回值爲標準化後的數據  
from sklearn.preprocessing import StandardScaler  
StandardScaler().fit_transform(iris.data)  

#區間縮放,返回值爲縮放到[0, 1]區間的數據  
from sklearn.preprocessing import MinMaxScaler  
MinMaxScaler().fit_transform(iris.data)  

#歸一化,返回值爲歸一化後的數據
from sklearn.preprocessing import Normalizer  
Normalizer().fit_transform(iris.data)

Tip2:怎麼進行多項式or對數的數據變換?

數據變換,這個操作在特徵工程中用得還是蠻多的,一個特徵在當前的分佈下無法有明顯的區分度,但一個小小的變換則可以帶來意想不到的效果

多項式變換

按照指定的degree,進行多項式操作從而衍生出新變量(當然這是針對每一列特徵內的操作)。

舉個栗子:

from sklearn.datasets import load_iris  
#導入IRIS數據集  
iris = load_iris()
iris.data[0]

# Output: array([ 5.1,  3.5,  1.4,  0.2])
tt = PolynomialFeatures().fit_transform(iris.data)  
tt[0]

# Output: array([  1.  ,   5.1 ,   3.5 ,   1.4 ,   0.2 ,  26.01,  17.85,   7.14, 1.02,  12.25,   4.9 ,   0.7 ,   1.96,   0.28,   0.04])

因爲PolynomialFeatures()方法默認degree是2,所以只會進行二項式的衍生。

一般來說,多項式變換都是按照下面的方式來的:

$$
f = kx + b 一次函數(degree爲1)\

f = ax^2 + b*x + w 二次函數(degree爲2)\

f = ax^3 + bx^2 + c*x + w 三次函數(degree爲3)
$$

這類的轉換可以適當地提升模型的擬合能力,對於在線性迴歸模型上的應用較爲廣泛。

對數變換

這個操作就是直接進行一個對數轉換,改變原先的數據分佈,而可以達到的作用主要有:

1)取完對數之後可以縮小數據的絕對數值,方便計算;

2)取完對數之後可以把乘法計算轉換爲加法計算;

3)還有就是分佈改變帶來的意想不到的效果。

numpy庫裏就有好幾類對數轉換的方法,可以通過from numpy import xxx 進行導入使用。

代碼集合

from sklearn.datasets import load_iris  
#導入IRIS數據集  
iris = load_iris()

#多項式轉換  
#參數degree爲度,默認值爲2 
from sklearn.preprocessing import PolynomialFeatures  
PolynomialFeatures().fit_transform(iris.data)  

#對數變換
from numpy import log1p  
from sklearn.preprocessing import FunctionTransformer  
#自定義轉換函數爲對數函數的數據變換  
#第一個參數是單變元函數  
FunctionTransformer(log1p).fit_transform(iris.data)  

Tip3:常用的統計圖在Python裏怎麼畫?

這裏的話我們介紹幾種很簡單但也很實用的統計圖繪製方法,分別有條形圖、餅圖、箱體圖、直方圖以及散點圖,關於這幾種圖形的含義這邊就不多做解釋了。

效果圖:

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述

代碼集合

# 導入一些常用包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

%matplotlib inline
plt.style.use('fivethirtyeight')

#解決中文顯示問題,Mac
%matplotlib inline
from matplotlib.font_manager import FontProperties


# 引入第 1 個數據集 Salary_Ranges_by_Job_Classification
salary_ranges = pd.read_csv('./data/Salary_Ranges_by_Job_Classification.csv')

# 引入第 2 個數據集 GlobalLandTemperaturesByCity
climate = pd.read_csv('./data/GlobalLandTemperaturesByCity.csv')
# 移除缺失值
climate.dropna(axis=0, inplace=True)
# 只看中國
# 日期轉換, 將dt 轉換爲日期,取年份, 注意map的用法
climate['dt'] = pd.to_datetime(climate['dt'])
climate['year'] = climate['dt'].map(lambda value: value.year)
climate_sub_china = climate.loc[climate['Country'] == 'China']
climate_sub_china['Century'] = climate_sub_china['year'].map(lambda x:int(x/100 +1))

# 設置顯示的尺寸
plt.rcParams['figure.figsize'] = (4.0, 4.0) # 設置figure_size尺寸
plt.rcParams['image.interpolation'] = 'nearest' # 設置 interpolation style
plt.rcParams['image.cmap'] = 'gray' # 設置 顏色 style
plt.rcParams['savefig.dpi'] = 100 #圖片像素
plt.rcParams['figure.dpi'] = 100 #分辨率
plt.rcParams['font.family'] = ['Arial Unicode MS'] #正常顯示中文

# 繪製條形圖
salary_ranges['Grade'].value_counts().sort_values(ascending=False).head(10).plot(kind='bar')
# 繪製餅圖
salary_ranges['Grade'].value_counts().sort_values(ascending=False).head(5).plot(kind='pie')
# 繪製箱體圖
salary_ranges['Union Code'].value_counts().sort_values(ascending=False).head(5).plot(kind='box')
# 繪製直方圖
climate['AverageTemperature'].hist()
# 繪製散點圖
x = climate_sub_china['year']
y = climate_sub_china['AverageTemperature']
fig, ax = plt.subplots(figsize=(10,5))
ax.scatter(x, y)
plt.show()

Tip4:怎麼去除DataFrame裏的缺失值?

這個我們經常會用,當我們發現某個變量的缺失率太高的時候,我們會直接對其進行刪除操作,又或者說某一行我不想要了,想單獨刪除這一行數據,這個我們該怎麼處理呢?這裏介紹一個方法,DataFrame.dropna(),具體可以看下圖:

在這裏插入圖片描述

從方法介紹可以看出,我們可以指定 axis 的值,如果是0,那就是按照行去進行空值刪除,如果是1則是按照列去進行操作,默認是0。

同時,還有一個參數是how ,就是選擇刪除的條件,如果是 any則是如果存在一個空值,則這行(列)的數據都會被刪除,如果是 all的話,只有當這行(列)全部的變量值爲空纔會被刪除,默認的話都是any

好了,舉幾個栗子,我們還是用climate數據集:

# 引入數據集
import pandas as pd
climate = pd.read_csv('./data/GlobalLandTemperaturesByCity.csv')
# 保留一部分列
data = climate.loc[:,['dt','AverageTemperature','AverageTemperatureUncertainty','City']]
data.head()

統計有多少缺失值

# 查看有多少缺失值
print(data.isnull().sum())
print('\n')
# 查看缺失值佔比
print(data.isnull().sum()/len(data))

在這裏插入圖片描述

刪除操作

# 原始模樣
print(data.head())
print('\n')

# 默認參數axis=0,根據索引(index)刪除指定的行,刪除第0行數據
print(data.drop(0).head())
print('\n')

# axis=1,根據列名(columns)刪除指定的列,刪除'dt'列
print(data.drop('dt',axis=1).head())
print('\n')

# 移除含有缺失值的行,直接結果作爲新df
data.dropna(axis=0, inplace=True)

在這裏插入圖片描述

Tip5:怎麼把被錯誤填充的缺失值還原?

上個小錦囊講到我們可以對缺失值進行丟棄處理,但是這種操作往往會丟失了很多信息的,很多時候我們都需要先看看缺失的原因,如果有些缺失是正常存在的,我們就不需要進行丟棄,保留着對我們的模型其實幫助會更大的。

此外,還有一種情況就是我們直接進行統計,它是沒有缺失的,但是實際上是缺失的,什麼意思?就是說缺失被人爲(系統)地進行了填充,比如我們常見的用0、-9、-999、blank等來進行填充缺失,若真遇見這種情況,我們可以這麼處理呢?

很簡單,那就是還原缺失!

單個操作

# 引入數據集(皮馬印第安人糖尿病預測數據集)
pima_columns = ['times_pregment','plasma_glucose_concentration','diastolic_blood_pressure','triceps_thickness',
                'serum_insulin','bmi','pedigree_function','age','onset_disbetes']

pima = pd.read_csv('./data/pima.data', names=pima_columns)


# 處理被錯誤填充的缺失值0,還原爲 空(單獨處理)
pima['serum_insulin'] = pima['serum_insulin'].map(lambda x:x if x !=0 else None)
# 檢查變量缺失情況
pima['serum_insulin'].isnull().sum()

# Output:374

批量操作

# 批量操作 還原缺失值
columns = ['serum_insulin','bmi','plasma_glucose_concentration','diastolic_blood_pressure','triceps_thickness']

for col in columns:
    pima[col].replace([0], [None], inplace=True)

# 檢查變量缺失情況
pima.isnull().sum()

在這裏插入圖片描述

Tip6:怎麼定義一個方法去填充分類變量的空值?

之前我們說過如何刪除掉缺失的行,但是如何我們需要的是填充呢?比如說用衆數來填充缺失,或者用某個特定值來填充缺失值?這個也是我們需要掌握的特徵工程的方法之一,對於用特定值填充缺失,其實比較簡單了,我們可以直接用fillna() 方法就可以,下面我來講一個通用的辦法,除了用特定值填充,我們還可以自定義,比如說用”衆數“來填充等等。

這裏我們用到了TransformerMixin方法,然後自定義一個填充器來進行缺失值的填充。

這裏我們造一個數據集來測試我們的代碼:

# 本次案例使用的數據集
import pandas as pd
X = pd.DataFrame({'city':['tokyo',None,'london','seattle','san fancisco','tokyo'],
                  'boolean':['y','n',None,'n','n','y'],
                  'ordinal_column':['somewhat like','like','somewhat like','like','somewhat like','dislike'],
                  'quantitative_column':[1,11,-.5,10,None,20]})
X

在這裏插入圖片描述

可以看出,這個數據集有三個分類變量,分別是boolean、city和ordinal_column,而這裏面有兩個字段存在空值。

# 填充分類變量(基於TransformerMixin的自定義填充器,用衆數填充)
from sklearn.base import TransformerMixin
class CustomCategoryzImputer(TransformerMixin):
    def __init__(self, cols=None):
        self.cols = cols
        
    def transform(self, df):
        X = df.copy()
        for col in self.cols:
            X[col].fillna(X[col].value_counts().index[0], inplace=True)
        return X
    
    def fit(self, *_):
        return self   
    
# 調用自定義的填充器
cci = CustomCategoryzImputer(cols=['city','boolean'])
cci.fit_transform(X)

在這裏插入圖片描述

Tip7:怎麼定義一個方法去填充數值變量的空值?

這個錦囊和上一個差不多了,不過這個換一個方法 Imputer

同樣的,我們還是造一個數據集:

# 本次案例使用的數據集
import pandas as pd
X = pd.DataFrame({'city':['tokyo',None,'london','seattle','san fancisco','tokyo'],
                  'boolean':['y','n',None,'n','n','y'],
                  'ordinal_column':['somewhat like','like','somewhat like','like','somewhat like','dislike'],
                  'quantitative_column':[1,11,-.5,10,None,20]})
X

在這裏插入圖片描述

可以看出,這個數據集有一個數值變量quantitative_columns,存在一行缺失值,我們直接調用sklearnpreprocessing方法裏的Imputer

# 填充數值變量(基於Imputer的自定義填充器,用衆數填充)
from sklearn.preprocessing import Imputer
class CustomQuantitativeImputer(TransformerMixin):
    def __init__(self, cols=None, strategy='mean'):
        self.cols = cols
        self.strategy = strategy
        
    def transform(self, df):
        X = df.copy()
        impute = Imputer(strategy=self.strategy)
        for col in self.cols:
            X[col] = impute.fit_transform(X[[col]])
        return X
    
    def fit(self, *_):
        return self
    
# 調用自定義的填充器
cqi = CustomQuantitativeImputer(cols = ['quantitative_column'], strategy='mean')
cqi.fit_transform(X)

在這裏插入圖片描述

Tip8:怎麼把幾個圖表一起在同一張圖上顯示?

未來幾個特徵錦囊的內容會使用泰坦尼克號的數據集,大家可以在下面的鏈接去下載數據哈。

Titanic數據集下載:https://www.kaggle.com/c/titanic/data

首先我們要知道,做特徵工程之前知道數據的分佈和關聯情況是極爲重要的,因此把這些信息做一些可視化的操作是很重要的操作和技能,今天我們就來學習下怎麼畫很多張圖,然後可以一併顯示在同一張上吧,專業來說就是畫子圖。

導入數據集

# 導入相關庫
import pandas as pd 
import numpy as np 
from pandas import Series,DataFrame

# 導入泰坦尼的數據集
data_train = pd.read_csv("./data/titanic/Train.csv")
data_train.head()

在這裏插入圖片描述

代碼彙集

import matplotlib.pyplot as plt

# 設置figure_size尺寸
plt.rcParams['figure.figsize'] = (8.0, 6.0) 

fig = plt.figure()

# 設定圖表顏色
fig.set(alpha=0.2)  

# 第一張小圖
plt.subplot2grid((2,3),(0,0))           
data_train['Survived'].value_counts().plot(kind='bar')
plt.ylabel(u"人數")  
plt.title(u"船員獲救情況 (1爲獲救)")

# 第二張小圖
plt.subplot2grid((2,3),(0,1))
data_train['Pclass'].value_counts().plot(kind="bar")
plt.ylabel(u"人數")
plt.title(u"乘客等級分佈")

# 第三張小圖
plt.subplot2grid((2,3),(0,2))
plt.scatter(data_train['Survived'], data_train['Age'])
plt.ylabel(u"年齡") 
plt.grid(b=True, which='major', axis='y') 
plt.title(u"按年齡看獲救分佈 (1爲獲救)")

# 第四張小圖,分佈圖
plt.subplot2grid((2,3),(1,0), colspan=2)
data_train.Age[data_train.Pclass == 1].plot(kind='kde')   
data_train.Age[data_train.Pclass == 2].plot(kind='kde')
data_train.Age[data_train.Pclass == 3].plot(kind='kde')
plt.xlabel(u"年齡")
plt.ylabel(u"密度") 
plt.title(u"各等級的乘客年齡分佈")
plt.legend((u'頭等艙', u'2等艙',u'3等艙'),loc='best')

# 第五張小圖
plt.subplot2grid((2,3),(1,2))
data_train.Embarked.value_counts().plot(kind='bar')
plt.title(u"各登船口岸上船人數")
plt.ylabel(u"人數")  
plt.show()

在這裏插入圖片描述

我們從上面的可視化操作結果可以看出,其實可以看出一些規律,比如說生還的機率比死亡的要大,然後獲救的人在年齡上區別不大,然後就是有錢人(坐頭等艙的)的年齡會偏大等。

Tip9:怎麼把畫出堆積圖來看佔比關係?

Titanic數據集下載:https://www.kaggle.com/c/titanic/data

上次的錦囊我知道了怎麼把幾張圖放在一張圖上去顯示,但是這個只是一種排版方式的操作,今天分享一個畫堆積圖的方法,可以用來看類別佔比關係,有助於我們去了解數據,發現數據裏的規律。

導入數據集

# 導入相關庫
import pandas as pd 
import numpy as np 
from pandas import Series,DataFrame

# 導入泰坦尼的數據集
data_train = pd.read_csv("./data/titanic/Train.csv")
data_train.head()

在這裏插入圖片描述

代碼彙集

# 設置figure_size尺寸
plt.rcParams['figure.figsize'] = (5.0, 4.0) 

#看看各乘客等級的獲救情況
fig = plt.figure()
fig.set(alpha=0.8)

Survived_0 = data_train.Pclass[data_train.Survived == 0].value_counts()
Survived_1 = data_train.Pclass[data_train.Survived == 1].value_counts()
df=pd.DataFrame({u'獲救':Survived_1, u'未獲救':Survived_0})
df.plot(kind='bar', stacked=True)
plt.title(u"各乘客等級的獲救情況")
plt.xlabel(u"乘客等級") 
plt.ylabel(u"人數") 
plt.show()

在這裏插入圖片描述

Tip10:怎麼對滿足某種條件的變量修改其變量值?

Titanic數據集下載:

https://www.kaggle.com/c/titanic/data

這裏我們使用loc函數,這個方式實在是太好用了!

首先我們先理解一下這個loc應該怎麼用吧,然後再舉幾個實戰例子來理解一下。

我們要知道loc函數的意思就是通過行標籤索引行數據,最直接的就是看看文檔,引用文檔裏的數據集:

df = pd.DataFrame([[1, 2], [4, 5], [7, 8]],index=['cobra', 'viper', 'sidewinder'],columns=['max_speed', 'shield'])
df

在這裏插入圖片描述

下面的小例子就是從文檔裏拿過來的,很全面的示例了一些應用操作。

在這裏插入圖片描述
在這裏插入圖片描述

那麼通過上面的學習,你大概也知道了loc的簡單用法了,下面就介紹下在特徵工程裏我們清洗某些數據時候,可以通過這函數來修改變量值,從而達到我們的某些目的。

下面我們還是用泰坦尼號的數據集:

# 導入相關庫
import pandas as pd 
import numpy as np 
from pandas import Series,DataFrame

# 導入泰坦尼的數據集
data_train = pd.read_csv("./data/titanic/Train.csv")
data_train['Age'].value_counts().sort_index()

在這裏插入圖片描述

我們可以看出有些年齡有小於1歲的,比如0.42、0.67之類的,我們這裏就使用一下loc來把這些小於1歲的修改爲1歲吧,如果沒有意外,應該歲數爲1的統計數會變爲14個。

data_train.loc[(data_train.Age<=1),'Age'] = 1
data_train['Age'].value_counts().sort_index()

在這裏插入圖片描述

Tip11:怎麼通過正則提取字符串裏的指定內容?

這個正則表達式在我們做字符提取中是十分常用的,先前有一篇文章有介紹到怎麼去使用正則表達式來實現我們的目的,大家可以先回顧下這篇文章。

圖文並茂地帶你入門正則表達式

Titanic數據集下載:

https://www.kaggle.com/c/titanic/data

# 導入相關庫
import pandas as pd 
import numpy as np 
from pandas import Series,DataFrame
import re

# 導入泰坦尼的數據集
data_train = pd.read_csv("./data/titanic/Train.csv")
data_train.head()

在這裏插入圖片描述

我們現在可以提取下這name裏的稱謂,比如Mr、Miss之類的,作爲一個新列,代碼如下:

data['Title'] = data['Name'].map(lambda x: re.compile(", (.*?)\.").findall(x)[0])
data.head()

在這裏插入圖片描述

我們之前看這代碼其實有點懵的,不過這是因爲大家可能對正則表達式的規則不太熟悉,所以下面有幾個相關的可以參考下。

import re
str = 'xxdaxxabxxacabxxcdabddbxxssbdffbggxx'
# 一個'.'就是匹配\n(換行符)以外的任何字符
print(re.findall(r'a.b',str))

# 一個'*'前面的字符出現0次或以上
print(re.findall(r'a*b',str))

# 匹配從.*前面的字符爲起點,到後面字符爲終點的所有內容,直到返回所有
print(re.findall(r'xx.*xx',str))

# 非貪婪,和上面的一樣,不過是用過一次就不會再用,,以列表的形式返回
print(re.findall(r'xx.*?xx',str))

# 非貪婪,與上面是一樣的,只是與上面相比,多了一個括號,只保留括號中的內容
print(re.findall(r'xx(.*?)xx',str))

# 保留a,b中間的內容
print(re.findall(r'xx(.+?)xx',str))
print(re.findall(r'xx(.+?)xx',str)[0])

[

所以,看了這些後,應該就可以理解上面的pattern的含義了!

Tip12:如何利用字典批量修改變量值?

這裏我們假設有這麼一種情況,一個字段裏的變量值,需要把某幾個變量值修改爲同一個值,然後其他幾個變量值修改爲另外一個,那麼我們有什麼簡單的辦法可以完成呢?這邊,我推薦一個字典映射的辦法!

Titanic數據集下載:

https://www.kaggle.com/c/titanic/data

# 導入相關庫
import pandas as pd 
import numpy as np 
from pandas import Series,DataFrame
import re

# 導入泰坦尼的數據集
data_train = pd.read_csv("./data/titanic/Train.csv")
# 提取其中幾列
data = data_train.loc[:,['PassengerId','Name']]

# 提取稱謂
data['Title'] = data['Name'].map(lambda x: re.compile(", (.*?)\.").findall(x)[0])
data.Title.value_counts()

在這裏插入圖片描述

就好像我剛剛所說的,需要把黃色框框裏的變量值修改掉,而且是按照我們的想法,比如captDr合爲一體,統一叫officer

# 定義一個空字典來收集映射關係
title_Dict = {}
title_Dict.update(dict.fromkeys(['Capt', 'Col', 'Major', 'Dr', 'Rev'], 'Officer'))
title_Dict.update(dict.fromkeys(['Don', 'Sir', 'the Countess', 'Dona', 'Lady'], 'Royalty'))
title_Dict.update(dict.fromkeys(['Mme', 'Ms', 'Mrs'], 'Mrs'))
title_Dict.update(dict.fromkeys(['Mlle', 'Miss'], 'Miss'))
title_Dict.update(dict.fromkeys(['Mr'], 'Mr'))
title_Dict.update(dict.fromkeys(['Master','Jonkheer'], 'Master'))
title_Dict

在這裏插入圖片描述
我們把映射關係用字典來存儲,到時候直接可以拿來用。

data['Title'] = data['Title'].map(title_Dict)
data.Title.value_counts()

在這裏插入圖片描述

Tip13:如何對類別變量進行獨熱編碼?

很多時候我們需要對類別變量進行獨熱編碼,然後纔可以作爲入參給模型使用,獨熱的方式有很多種,這裏介紹一個常用的方法 get_dummies吧,這個方法可以讓類別變量按照枚舉值生成N個(N爲枚舉值數量)新字段,都是0-1的變量值。

# 導入相關庫
import pandas as pd 
import numpy as np 
from pandas import Series,DataFrame
import re

# 導入泰坦尼的數據集
data_train = pd.read_csv("./data/titanic/Train.csv")
# 提取其中幾列
data = data_train.loc[:,['PassengerId','Name']]

# 提取稱謂
data['Title'] = data['Name'].map(lambda x: re.compile(", (.*?)\.").findall(x)[0])

# 定義一個空字典來收集映射關係
title_Dict = {}
title_Dict.update(dict.fromkeys(['Capt', 'Col', 'Major', 'Dr', 'Rev'], 'Officer'))
title_Dict.update(dict.fromkeys(['Don', 'Sir', 'the Countess', 'Dona', 'Lady'], 'Royalty'))
title_Dict.update(dict.fromkeys(['Mme', 'Ms', 'Mrs'], 'Mrs'))
title_Dict.update(dict.fromkeys(['Mlle', 'Miss'], 'Miss'))
title_Dict.update(dict.fromkeys(['Mr'], 'Mr'))
title_Dict.update(dict.fromkeys(['Master','Jonkheer'], 'Master'))
data['Title'] = data['Title'].map(title_Dict)
data.Title.value_counts()

在這裏插入圖片描述

那麼接下來我們對字段Title進行獨熱編碼,這裏使用get_dummies,生成N個0-1新字段:

# 我們對字段Title進行獨熱編碼,這裏使用get_dummies,生成N個0-1新字段
dummies_title = pd.get_dummies(data['Title'], prefix="Title")
data = pd.concat([data,dummies_title], axis=1)
data.head()

在這裏插入圖片描述

對了,這裏有些同學可能會問,還有一種獨熱編碼出來的是N-1個字段的又是什麼?另外這種的話,我們是稱爲dummy encoding的,也就是啞變量編碼,它把任意一個狀態位去除,也就是說其中有一類變量值的啞變量表示爲全0。更多的內容建議可以百度深入瞭解哈。

Tip14:如何把“年齡”字段按照我們的閾值分段?

我們在進行特徵處理的時候,也有的時候會遇到一些變量,比如說年齡,然後我們想要按照我們想要的閾值進行分類,比如說低於18歲的作爲一類,18-30歲的作爲一類,那麼怎麼用Python實現的呢?

# 導入相關庫
import pandas as pd 
import numpy as np 
from pandas import Series,DataFrame

# 導入泰坦尼的數據集
data_train = pd.read_csv("./data/titanic/Train.csv")
# 修復部分age的值
data_train.loc[(data_train.Age<=1),'Age'] = 1
# 只保留部分值
data = data_train.loc[:,['PassengerId','Age']]
data.head()

在這裏插入圖片描述

然後,我們編輯代碼,按照我們的預期進行分組:

# 確定閾值,寫入列表
bins = [0, 12, 18, 30, 50, 70, 100]
data['Age_group'] = pd.cut(data['Age'], bins)

dummies_Age = pd.get_dummies(data['Age_group'], prefix= 'Age')
data = pd.concat([data, dummies_Age], axis=1)

data.head()

在這裏插入圖片描述

這樣子就很神奇了吧,把年齡按照我們的需求進行分組,順便使用獨熱編碼生成了新的字段。

Tip15:如何使用sklearn的多項式來衍生更多的變量?

關於這種衍生變量的方式,理論其實大家應該很早也都聽說過了,但是如何在Python裏實現,也就是今天在這裏分享給大家,其實也很簡單,就是調用sklearnPolynomialFeatures方法,具體大家可以看看下面的demo。

這裏使用一個人體加速度數據集,也就是記錄一個人在做不同動作時候,在不同方向上的加速度,分別有3個方向,命名爲x、y、z。

# 人體胸部加速度數據集,標籤activity的數值爲1-7
'''
1-在電腦前工作
2-站立、走路和上下樓梯
3-站立
4-走路
5-上下樓梯
6-與人邊走邊聊
7-站立着說話

'''
import pandas as pd
df = pd.read_csv('./data/activity_recognizer/1.csv', header=None)
df.columns = ['index','x','y','z','activity']
df.head()

在這裏插入圖片描述

那麼我們可以直接調用剛剛說的辦法,然後對於數值型變量多項式的變量擴展,代碼如下:

# 擴展數值特徵
from sklearn.preprocessing import PolynomialFeatures

x = df[['x','y','z']]
y = df['activity']

poly = PolynomialFeatures(degree=2, include_bias=False, interaction_only=False)

x_poly = poly.fit_transform(x)
pd.DataFrame(x_poly, columns=poly.get_feature_names()).head()

在這裏插入圖片描述

Tip16:如何根據變量相關性畫出熱力圖?

上次的錦囊有提及到如何使用sklearn來實現多項式的擴展來衍生更多的變量,但是我們也知道其實這樣子出來的變量之間的相關性是很強的,我們怎麼可以可視化一下呢?這裏介紹一個熱力圖的方式,調用corr來實現變量相關性的計算,同時熱力圖,顏色越深的話,代表相關性越強!

# 人體胸部加速度數據集,標籤activity的數值爲1-7
'''
1-在電腦前工作
2-站立、走路和上下樓梯
3-站立
4-走路
5-上下樓梯
6-與人邊走邊聊
7-站立着說話

'''
import pandas as pd
from sklearn.preprocessing import PolynomialFeatures

df = pd.read_csv('./data/activity_recognizer/1.csv', header=None)
df.columns = ['index','x','y','z','activity']

x = df[['x','y','z']]
y = df['activity']

# 多項式擴充數值變量
poly = PolynomialFeatures(degree=2, include_bias=False, interaction_only=False)

x_poly = poly.fit_transform(x)
pd.DataFrame(x_poly, columns=poly.get_feature_names()).head()

# 查看熱力圖(顏色越深代表相關性越強)
%matplotlib inline
import seaborn as sns

sns.heatmap(pd.DataFrame(x_poly, columns=poly.get_feature_names()).corr())

在這裏插入圖片描述

Tip17:如何把分佈修正爲類正態分佈?

在這裏插入圖片描述

下載地址:https://www.kaggle.com/c/house-prices-advanced-regression-techniques/data

import pandas as pd
import numpy as np
# Plots
import seaborn as sns
import matplotlib.pyplot as plt

# 讀取數據集
train = pd.read_csv('./data/house-prices-advanced-regression-techniques/train.csv')
train.head()

在這裏插入圖片描述

首先這個是一個價格預測的題目,在開始前我們需要看看分佈情況,可以調用以下的方法來進行繪製:

sns.set_style("white")
sns.set_color_codes(palette='deep')
f, ax = plt.subplots(figsize=(8, 7))
#Check the new distribution 
sns.distplot(train['SalePrice'], color="b");
ax.xaxis.grid(False)
ax.set(ylabel="Frequency")
ax.set(xlabel="SalePrice")
ax.set(title="SalePrice distribution")
sns.despine(trim=True, left=True)
plt.show()

在這裏插入圖片描述

我們從結果可以看出,銷售價格是右偏,而大多數機器學習模型都不能很好地處理非正態分佈數據,所以我們可以應用log(1+x)轉換來進行修正。那麼具體我們可以怎麼用Python代碼實現呢?

# log(1+x) 轉換
train["SalePrice_log"] = np.log1p(train["SalePrice"])

sns.set_style("white")
sns.set_color_codes(palette='deep')
f, ax = plt.subplots(figsize=(8, 7))

sns.distplot(train['SalePrice_log'] , fit=norm, color="b");

# 得到正態分佈的參數
(mu, sigma) = norm.fit(train['SalePrice_log'])

plt.legend(['Normal dist. ($\mu=$ {:.2f} and $\sigma=$ {:.2f} )'.format(mu, sigma)],
            loc='best')
ax.xaxis.grid(False)
ax.set(ylabel="Frequency")
ax.set(xlabel="SalePrice")
ax.set(title="SalePrice distribution")
sns.despine(trim=True, left=True)

plt.show()

在這裏插入圖片描述

Tip18:怎麼找出數據集中有數據傾斜的特徵?

今天我們用的是一個新的數據集,也是在kaggle上的一個比賽,大家可以先去下載一下:

在這裏插入圖片描述
下載地址:https://www.kaggle.com/c/house-prices-advanced-regression-techniques/data

import pandas as pd
import numpy as np
# Plots
import seaborn as sns
import matplotlib.pyplot as plt

# 讀取數據集
train = pd.read_csv('./data/house-prices-advanced-regression-techniques/train.csv')
train.head()

在這裏插入圖片描述

我們對數據集進行分析,首先我們可以先看看特徵的分佈情況,看下哪些特徵明顯就是有數據傾斜的,然後可以找辦法解決,因此,第一步就是要有辦法找到這些特徵。

首先可以通過可視化的方式,畫箱體圖,然後觀察箱體情況,理論知識是:

在箱線圖中,箱子的中間有一條線,代表了數據的中位數。箱子的上下底,分別是數據的上四分位數(Q3)和下四分位數(Q1),這意味着箱體包含了50%的數據。因此,箱子的高度在一定程度上反映了數據的波動程度。上下邊緣則代表了該組數據的最大值和最小值。有時候箱子外部會有一些點,可以理解爲數據中的“異常值”。而對於數據傾斜的,我們叫做“偏態”,與正態分佈相對,指的是非對稱分佈的偏斜狀態。在統計學上,衆數和平均數之差可作爲分配偏態的指標之一:如平均數大於衆數,稱爲正偏態(或右偏態);相反,則稱爲負偏態(或左偏態)。

# 丟棄y值
all_features = train.drop(['SalePrice'], axis=1)

# 找出所有的數值型變量
numeric_dtypes = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']
numeric = []
for i in all_features.columns:
    if all_features[i].dtype in numeric_dtypes:
        numeric.append(i)
        
# 對所有的數值型變量繪製箱體圖
sns.set_style("white")
f, ax = plt.subplots(figsize=(8, 7))
ax.set_xscale("log")
ax = sns.boxplot(data=all_features[numeric] , orient="h", palette="Set1")
ax.xaxis.grid(False)
ax.set(ylabel="Feature names")
ax.set(xlabel="Numeric values")
ax.set(title="Numeric Distribution of Features")
sns.despine(trim=True, left=True)

在這裏插入圖片描述
可以看出有一些特徵,有一些數據會偏離箱體外,因此屬於數據傾斜。但是,我們從上面的可視化中雖然看出來了,但是想要選出來還是比較麻煩,所以這裏引入一個偏態的概念,相對應的有一個指標skew,這個就是代表偏態的係數。

Skewness:描述數據分佈形態的統計量,其描述的是某總體取值分佈的對稱性,簡單來說就是數據的不對稱程度。

偏度是三階中心距計算出來的。

(1)Skewness = 0 ,分佈形態與正態分佈偏度相同。

(2)Skewness > 0 ,正偏差數值較大,爲正偏或右偏。長尾巴拖在右邊,數據右端有較多的極端值。

(3)Skewness < 0 ,負偏差數值較大,爲負偏或左偏。長尾巴拖在左邊,數據左端有較多的極端值。

(4)數值的絕對值越大,表明數據分佈越不對稱,偏斜程度大。

那麼在Python裏可以怎麼實現呢?

# 找出明顯偏態的數值型變量
skew_features = all_features[numeric].apply(lambda x: skew(x)).sort_values(ascending=False)

high_skew = skew_features[skew_features > 0.5]
skew_index = high_skew.index

print("本數據集中有 {} 個數值型變量的 Skew > 0.5 :".format(high_skew.shape[0]))
skewness = pd.DataFrame({'Skew' :high_skew})
skew_features.head(10)

在這裏插入圖片描述

Tip19:怎麼儘可能地修正數據傾斜的特徵?

上一個錦囊,分享了給大家通過skew的方法來找到數據集中有數據傾斜的特徵(特徵錦囊:怎麼找出數據集中有數據傾斜的特徵?),那麼怎麼去修正它呢?正是今天要分享給大家的錦囊!

還是用到房價預測的數據集:

在這裏插入圖片描述

下載地址:https://www.kaggle.com/c/house-prices-advanced-regression-techniques/data

import pandas as pd
import numpy as np
# Plots
import seaborn as sns
import matplotlib.pyplot as plt

# 讀取數據集
train = pd.read_csv('./data/house-prices-advanced-regression-techniques/train.csv')
![在這裏插入圖片描述](https://img-blog.csdnimg.cn/20200317220809685.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FJSFVCRUk=,size_16,color_FFFFFF,t_70)train.head()

我們通過上次的知識,知道了可以通過skewness來進行傾斜特徵的辨別,那麼對於修正它的辦法,這裏也先分享一個理論知識 —— box-cox轉換

線性迴歸模型滿足線性性、獨立性、方差齊性以及正態性的同時,又不丟失信息,此種變換稱之爲Box—Cox變換。

Box-Cox變換是Box和Cox在1964年提出的一種廣義冪變換方法,是統計建模中常用的一種數據變換,用於連續的響應變量不滿足正態分佈的情況。Box-Cox變換之後,可以一定程度上減小不可觀測的誤差和預測變量的相關性。Box-Cox變換的主要特點是引入一個參數,通過數據本身估計該參數進而確定應採取的數據變換形式,Box-Cox變換可以明顯地改善數據的正態性、對稱性和方差相等性,對許多實際數據都是行之有效的。—— 百度百科

在使用前,我們先看看原先傾斜的特徵有多少個。

# 丟棄y值
all_features = train.drop(['SalePrice'], axis=1)

# 找出所有的數值型變量
numeric_dtypes = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']
numeric = []
for i in all_features.columns:
    if all_features[i].dtype in numeric_dtypes:
        numeric.append(i)
        
# 找出明顯偏態的數值型變量
skew_features = all_features[numeric].apply(lambda x: skew(x)).sort_values(ascending=False)

high_skew = skew_features[skew_features > 0.5]
skew_index = high_skew.index

print("本數據集中有 {} 個數值型變量的 Skew > 0.5 :".format(high_skew.shape[0]))
skewness = pd.DataFrame({'Skew' :high_skew})
skew_features

本數據集中有 24 個數值型變量的 Skew > 0.5 :

在Python中怎麼使用Box-Cox 轉換呢?很簡單。

# 通過 Box-Cox 轉換,從而把傾斜的數據進行修正
for i in skew_index:
    all_features[i] = boxcox1p(all_features[i], boxcox_normmax(all_features[i] + 1))

然後我們再看看還有多少個數據傾斜的特徵吧!

# 找出明顯偏態的數值型變量
skew_features = all_features[numeric].apply(lambda x: skew(x)).sort_values(ascending=False)

high_skew = skew_features[skew_features > 0.5]
skew_index = high_skew.index
print("本數據集中有 {} 個數值型變量的 Skew > 0.5 :".format(high_skew.shape[0]))
skewness = pd.DataFrame({'Skew' :high_skew})

本數據集中有 15 個數值型變量的 Skew > 0.5 :

變少了很多,而且如果看他們的skew值,也會發現變小了很多。我們也可以看看轉換後的箱體圖情況。

# Let's make sure we handled all the skewed values
sns.set_style("white")
f, ax = plt.subplots(figsize=(8, 7))
ax.set_xscale("log")
ax = sns.boxplot(data=all_features[skew_index] , orient="h", palette="Set1")
ax.xaxis.grid(False)
ax.set(ylabel="Feature names")
ax.set(xlabel="Numeric values")
ax.set(title="Numeric Distribution of Features")
sns.despine(trim=True, left=True)

在這裏插入圖片描述

Tip20:怎麼簡單使用PCA來劃分數據且可視化呢?

PCA算法在數據挖掘中是很基礎的降維算法,簡單回顧一下定義:

PCA,全稱爲Principal Component Analysis,也就是主成分分析方法,是一種降維算法,其功能就是把N維的特徵,通過轉換映射到K維上(K<N),這些由原先N維的投射後的K個正交特徵,就被稱爲主成分。

我們在這裏使用的數據集iris,來弄一個demo:

# 導入相關庫
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
%matplotlib inline

#解決中文顯示問題,Mac
%matplotlib inline
from matplotlib.font_manager import FontProperties
# 設置顯示的尺寸
plt.rcParams['font.family'] = ['Arial Unicode MS'] #正常顯示中文

# 導入數據集
iris = load_iris()
iris_x, iris_y = iris.data, iris.target

# 實例化
pca = PCA(n_components=2)

# 訓練數據
pca.fit(iris_x)
pca.transform(iris_x)[:5,]

# 自定義一個可視化的方法
label_dict = {i:k for i,k in enumerate(iris.target_names)}
def plot(x,y,title,x_label,y_label):
    ax = plt.subplot(111)
    for label,marker,color in zip(
    range(3),('^','s','o'),('blue','red','green')):
        plt.scatter(x=x[:,0].real[y == label],
                   y = x[:,1].real[y == label],
                   color = color,
                   alpha = 0.5,
                   label = label_dict[label]
                   )
        
    plt.xlabel(x_label)
    plt.ylabel(y_label)
    
    leg = plt.legend(loc='upper right', fancybox=True)
    leg.get_frame().set_alpha(0.5)
    plt.title(title)

# 可視化
plot(iris_x, iris_y,"原始的iris數據集","sepal length(cm)","sepal width(cm)")
plt.show()

plot(pca.transform(iris_x), iris_y,"PCA轉換後的頭兩個正交特徵","PCA1","PCA2")

在這裏插入圖片描述
我們通過自定義的繪圖函數plot,把不同類別的y值進行不同顏色的顯示,從而看出在值域上分佈的差異。從原始的特徵來看,不同類別之間其實界限並不是十分明顯,如上圖所示。而進行PCA轉換後,可以看出不同類別之間的界限有了比較明顯的差異。

Tip21:怎麼簡單使用LDA來劃分數據且可視化呢?

LDA算法在數據挖掘中是很基礎的算法,簡單回顧一下定義:

LDA的全稱爲Linear Discriminant Analysis, 中文爲線性判別分析,LDA是一種有監督學習的算法,和PCA不同。PCA是無監督算法,。LDA是“投影后類內方差最小,類間方差最大”,也就是將數據投影到低維度上,投影后希望每一種類別數據的投影點儘可能的接近,而不同類別的數據的類別中心之間的距離儘可能的大。

我們在這裏使用的數據集iris,來弄一個demo:

# 導入相關庫
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
%matplotlib inline

#解決中文顯示問題,Mac
%matplotlib inline
from matplotlib.font_manager import FontProperties
# 設置顯示的尺寸
plt.rcParams['font.family'] = ['Arial Unicode MS'] #正常顯示中文

# 導入數據集
iris = load_iris()
iris_x, iris_y = iris.data, iris.target

# 實例化
lda = LinearDiscriminantAnalysis(n_components=2)

# 訓練數據
x_lda_iris = lda.fit_transform(iris_x, iris_y)


# 自定義一個可視化的方法
label_dict = {i:k for i,k in enumerate(iris.target_names)}
def plot(x,y,title,x_label,y_label):
    ax = plt.subplot(111)
    for label,marker,color in zip(
    range(3),('^','s','o'),('blue','red','green')):
        plt.scatter(x=x[:,0].real[y == label],
                   y = x[:,1].real[y == label],
                   color = color,
                   alpha = 0.5,
                   label = label_dict[label]
                   )
        
    plt.xlabel(x_label)
    plt.ylabel(y_label)
    
    leg = plt.legend(loc='upper right', fancybox=True)
    leg.get_frame().set_alpha(0.5)
    plt.title(title)

# 可視化
plot(iris_x, iris_y,"原始的iris數據集","sepal length(cm)","sepal width(cm)")
plt.show()

plot(x_lda_iris, iris_y, "LDA Projection", "LDA1", "LDA2")

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章