機器學習-特徵工程-Feature generation 和 Feature selection

  1. 概述:上節我們說了特徵工程是機器學習的一個核心內容。而後我們已經學習了特徵工程中的基礎內容,分別是missing value handling和categorical data encoding的一些方法技巧。可是光會前面的一些內容,還不足以應付實際的工做中的不少狀況,例如若是我們的原始數據的features太多,我們應該選擇那些features做爲我們訓練的features?或者我們的features太少了,我們能不能利用現有的features再創造出一些新的與我們的target有更加緊密聯繫的features呢?這些都是我們feature engineering中常常遇到的場景,這裏涉及到的一些經常使用技術也是每個作機器學習或是數據分析的工程師必需要掌握的。上面提到的技術,我們一般叫作:feature generation和feature selection。下面我們就來講一說這兩個技術點吧
  2. Feature generation。對於這個技術點,其實沒有什麼訣竅,就是一個,深入理解我們的數據的意義再加上一點點創造力。你們是否是很懵逼,哈哈,這就完啦????哈哈固然不是啦,可是這一塊缺失沒有一個統一的模式,具備必定的隨機性。可是經過總結,我們能夠總結一下經常使用的模式,方便你們在應用的時候參考。                                                                                        2.1 Interaction。這個其實就是至關於交叉的意思,我們能夠將幾個features直接的拼接在一塊兒,造成一個「有意思」的新的feature,記住必定要有意義的,不然你不但白搞了,甚至原來好好的數據都被你搞砸了,不要爲了裝逼而裝逼,咱要裝逼於無形之中。那麼這個有什麼意義呢?首先它能將多個columns裝換成一個column,方便我們的數據處理;其次在有些特定的數據中,這種interaction更加能反映出數據的本質。具體怎麼操做了,我們經過一個簡單的代碼來展現,注意我只截取了我代碼的一部分,默認數據都已經加載完畢,因此不要糾結個人代碼的變量和數據哈,你們主要看過程和思路
    interactions = data_raw["category"]+"_"+data_raw["country"]
    baseline_data = baseline_data.assign(category_country = label_encoder.fit_transform(interactions))

    上面的第一句代碼就是我們interaction的部分,第二句是講interaction事後的數據label encoding而且加入到我們的數據集裏面,簡單明瞭。上面是將原始數據中的category 和 country鏈接在一塊兒從而造成一個新的feature                                       2.2 numerical transforming。這是什麼意思呢,對於有些numerical data的columns,他們的數據分佈是很不均勻的,或者說他們的數值太大或者過小,有的時候不適合我們的數據的訓練,可能會出現vanishing gradient或者gradient explode的狀況。具體啥叫vanishing gradient和gradient exploding,我們在後面的內容在慢慢解釋。暫時只須要知道這是個很麻煩的事情就行了,會致使我們訓練的模型不那麼牛逼就好了。那麼我們經過什麼方法解決呢?這裏主要經過一些常見的數學的方式來解決,例如用log 或者 sqrt等等方式。我們能夠經過下面的代碼來簡單的展現一下html

    np.sqrt(baseline_data['goal'])
    np.log(baseline_data['goal'])

    從上面我們能夠看出,這裏我們主要仍是經過numpy裏面提供的API進行處理的,很是簡單,簡單跟1同樣,好了這裏就說到這了。    對了,忘記一個事兒,就是numerical transforming在tree-based模型中沒有什麼卵用的,由於tree-based的全部模型都是scale invariant的,就是tree-based模型都是不care數據的大小分佈的。                                                                           2.3 rolling。這個就比較高級一點啦(相比前兩種方式),首先我們先要明白rolling的概念,其實rolling就是至關於在我們的數據(series)上面卡上一個fixed-size的小window,而後對於這個window覆蓋的數據進行一些簡單的計算,例如:counting,mean,sum等等。若是你們仍是以爲不懂,我把它的官方連接貼在這裏,你們本身去看看,裏面還有不少實例:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.rolling.html#pandas.Series.rolling 。那麼我先寫一個簡單的小例子給你們參考一下哈api

    launched = pd.Series(data_raw.index,data_raw.launched,name="count_7_days").sort_index()
    count_7_days = launched.rolling('7d').count()
    count_7_days.index = launched.values
    count_7_days
    = count_7_days.reindex(data_raw.index)

    我先簡單解釋一下上面代碼的意思哈,第一句是讓時間做爲這個series的index,第二句rolling是計算最近7天的的數量,第三第四句是講數據還原到以前的index的順序,房間從新join到原來的數據集中。那麼rolling這種方式通常在什麼狀況下用呢?通常在你的數據有datetime的時候,或者前面數據會影響到後面的結果的時候,你們能夠考慮一下下,可是這個是不必定的,仍是須要你們有必定的creativity的。例如上面的例子就是統計最近7天一共上傳的APP的數量,來判斷某一個APP是否被下載的應用場景。通常狀況下,最近上傳的APP數量太多,被下載的機率就越低,因此他們仍是有必定關聯關係的。因此我generate一個新的feature仍是有必定道理的。                                                                                                                                                       2.4 Time delta。從這個命名中我們能夠知道,這個跟time確定有關係,這個你們猜的很對。time delta也是有必定隨機性的,有時須要有時也不須要,也是要根據實際的數據的特性來決定的,甚至是根據工程師本身來決定的,跟上面的rolling有點類似。爲了方便解釋這其中的細節,我也是直接來一個例子而後慢慢解釋app

    def time_since_last_project_same_category(series):
        return series.diff().dt.total_seconds()/3600
    df = data_raw[['category','launched']].sort_values('launched')
    group_category = df.groupby('category')
    timedeltas = group_category.transform(time_since_last_project_same_category)
    timedeltas = timedeltas.fillna(timedeltas.mean()).reindex(baseline_data.index)

    上面前兩行是一個計算相鄰datatime之間的相差多少個小時,第三行建立一個按照排序好的launched time爲index的dataframe, 第四行是按照category的條件來group前面建立的df, 第五行是計算group裏面相鄰數據之間的time delta,而且返回一個series, 第六行是填充這些空數據,而且按照原始數據的方式index從新排序方便加入到原始數據。流程就這樣結束了。上面的場景是計算同一個category相鄰app上傳的時間差,這個其實也是會影響到我們的APP是否被下載的因素。因此這個也是我們的一個creativity,實際狀況中變幻無窮,必定要根據實際狀況來定,不能爲了裝逼而裝逼,必定要根據實際的業務須要,不然拔苗助長。 好了,其實關於feature generation還有不少種方式,例若有些事計算兩個columns之間的差值,取模等等,這裏沒有統一的標準,惟一的捷徑和key就是我們必定得理解我們每個columns和dataset的實際業務的意思,不然再牛逼的generation也拯救不了你。下面我們進入到這一章的最後一節feature selection吧。dom

  3. Feature selection。當我們吧missing value, categorical data handling, feature generation這個繁雜的步驟都走完了,我們就來到了feature engineering的最後一步了,那就是feature selection。根據意思就是我們到底我們最後選擇哪些數據來訓練我們的模型,數據選的好,模型的適用範圍,效率,準確性都更好,不然我們前面的努力可能會毀於一旦。關於feature selection我我的以爲是我的經驗和一些selection技術的結合,才能選出最好的features做爲訓練的樣本。我的經驗,就是工程師本身對於數據的理解程度,有些features一看就和target沒有半毛錢的關係,我們確定直接排除這些features,例如我們的手機設備號和手機價格一看就一點關係都沒有,我們確定直接刪除手機設備號這個feature;有些features一看就和target有很強的關係,例如手機內存大小和手機的價格一看就有很強的關聯性,因此我們確定要選擇這個內存的feature。我的經驗以外還有不少模棱兩可的features怎麼辦呢?就跟我前面說的那樣,我們還能夠用一些技術手段來選擇。下面我們來介紹兩種經常使用的feature selection的技術。                                                                                                                                                   3.1 F-classification method。這種方式是單獨計算每個column和target的關聯性,而後選出關聯性最強的f個columns,這裏f的值是我們自定義的。具體的實現細節我們不須要了解的那麼深,由於sklearn已經幫助我們造好輪子了,從下面的代碼,我們來感覺一下它的魅力吧
    from sklearn.feature_selection import SelectKBest, f_classif
    selector = SelectKBest(score_func = f_classif, k = 5)
    train,valid,test = get_data_splits(baseline_data, 0.1)
    feature_cols = train.columns.drop("outcome")
    X_new = selector.fit_transform(train[feature_cols],train["outcome"] )

    #get back to the features we kept
    features = pd.DataFrame(selector.inverse_transform(X_new), index = train.index, columns = feature_cols)
    #drop the columns that the values are all 0s
    feature_cols_final = features.columns[features.var()!=0]
    features_final = features[feature_cols_final]機器學習

    從上面的代碼我們能夠看出來,首先得從sklearn.feature_selection這個模塊中引進SelectKBest和f_classif兩個子模塊;第二步就是建立一個Selector實例對象,這個selector最終返回多少個features是經過我們的參數K來控制的,selector的最終選擇哪些features也是經過f_classif這個函數來控制的;最後就是這個selector的transform了,將features和target做爲參數分別傳遞給他,他會自動搞定,而且返回K個features, 而後再將numpy array返回到dataframe的格式。這種方式的只能計算出每個feature和target的linear dependency,並不能一次性包括全部的features進行關聯性計算。                                                       3.2 L1 Regression。L1 Regression能夠直接包括全部的features一次性的計算這個columns和target的關聯性。關聯性越強,數值越大。它不須要制定最後返回多少個features,它是根據L1的結果自動幫助我們features。可是它的運行速度要遠遠慢於上面k-classif的方法,但是好處就是通常狀況下L1 Regression的運行結果要好於K-classif, 但也不必定澳,只能說大部分狀況是這樣的。函數

    from sklearn.linear_model import LogisticRegression
    from sklearn.feature_selection import SelectFromModel
    train,valid,test = get_data_splits(baseline_data, 0.1)
    X, y = train[train.columns.drop("outcome")], train["outcome"]
    logistic_model = LogisticRegression(C=1, penalty="l1", random_state=7).fit(X,y)
    selector = SelectFromModel(logistic_model,prefit=True)
    X_new = selector.transform(X)
    features = pd.DataFrame(selector.inverse_transform(X_new),index = train.index, columns = feature_cols)
    feature_cols_final = features.columns[features.var()!=0]

    總結:上面就是通常的的特徵工程的feature selection和feature generation的通常方法,我們上面講了不少種的方式,實際狀況中具體選擇哪種仍是要根據實際狀況,必定不要死讀書。feature generation通常就是interaction,numerical generation,rolling和time delta四種方式。feature selection通常用到的技術手段就是就是f-classif和L1 regression幾種方式。學習

相關文章
相關標籤/搜索