精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

機器學習特征工程的最佳實踐

人工智能 機器學習
在我們的實驗中,我們觀察到特征工程顯著提升了模型的性能,尤其是在與 EDA 和業務目標緊密結合的情況下。通過與領域專家和業務利益相關者合作完善假設,我們有望實現進一步的改進。

特征工程是模型訓練之前運行的關鍵過程,因為輸入數據的質量直接決定了模型輸出的質量。

雖然深度學習模型擅長從圖像或文本等非結構化數據中自動學習特征,但明確的特征工程對于表格數據集仍然至關重要。

在本文中,云朵君將展示特征工程對回歸任務的影響,特別關注具有混合數字、分類和基于時間的特征的大型表格數據集。

什么是特征工程

特征工程是從原始數據中選擇、轉換和創建新特征以提高機器學習模型性能的過程。

它涉及使用領域知識從數據中提取最相關的信息,并以適合所選機器學習算法的方式表示它。

特征工程的好處

精心設計的特征可以顯著提高模型的預測能力,即使是簡單的模型也可以掌握復雜的關系,因為它可以:

  • 降低數據稀疏性:大多數現實世界的數據集都是稀疏的,包含許多零值和缺失值。特征工程可以整合信息并創建更密集的表示,使模型更容易學習。
  • 處理多種數據類型: 原始數據有多種格式,例如數值、分類、文本和時間。特征工程將這些類型轉換為模型可以處理的數字格式。
  • 解決數據噪聲和異常值:特征工程減輕了噪聲數據和異常值的影響,從而產生了更穩健的模型。

當我們可以將特征格式化為直接對應于問題域中的有意義的概念時,它可以使模型的決策更具解釋性、準確性和穩健性。

特征工程中的常用技術

一些常見的特征工程技術包括:

對數轉換

  • 將對數應用于數值特征。
  • 可以使分布更加對稱,使模型呈現正態分布。
  • 最佳情況:處理傾斜的數值特征。

多項式特征創建

  • 通過將現有特征提升到冪(例如 x2、x3)來生成新特征。
  • 創建交互項(例如,x?y)。
  • 最佳情況:捕捉非線性關系。

分箱(離散化)

  • 將連續的數值分組到箱中。
  • 可以減少微小波動的影響并使關系更加線性。
  • 最佳情況:用線性模型處理非線性關系,數據包含顯著的異常值或偏差。

基于時間的特征

  • 提取星期幾、月份、年份、小時、季度,甚至更復雜的特征,如“是周末”、“是假期”。
  • 計算事件之間的時間差。
  • 最佳情況:季節性影響預測。

工作流程

雖然沒有一刀切的方法,但特征工程的一般工作流程通常涉及從定義問題和成功指標開始的整個項目生命周期。

在本文中,我將演示第 1 階段和第 2 階段(圖中的藍色框),特別關注特征工程。

圖:具有特征工程的機器學習項目工作流程圖:具有特征工程的機器學習項目工作流程


對于第 3 階段,“通過機器學習實現準確性”涵蓋了泛化的核心概念,假設了損失的根本原因。!

第一階段:基礎

1. 問題

對于在線零售業務,了解未來客戶支出對于營銷、庫存管理和戰略規劃至關重要。

讓我們想象這樣一個場景:企業在銷售增長方面苦苦掙扎,尋找可行的見解。

2. 成功指標

我選擇平均絕對誤差 (MAE)作為主要指標,因為它對偏斜數據具有穩健性(稍后,在 EDA 期間,我將討論目標變量:銷售額的數據分布)并選擇MSE作為支持指標。

3. EDA 和特征工程

這是初始階段數據準備的基礎部分。

為了演示,我將使用來自加州大學歐文分校機器學習庫的在線零售數據:直接在@公眾號:數據STUDIO 原文文末留言需要即可,云朵君將回復給大家:

圖:變量表圖:變量表

import os
import pandas as pd

df = pd.read_csv(csv_file_path)
df.info()

圖片圖片

該數據集有541,909 個數據點,具有八個特征:

已加載數據集已加載數據集

實際上,這些數據可以是簡單的 Excel 表,也可以是存儲在云服務器上的信息,或者我們可以組合多個數據源。

數據清理

在進入 EDA 之前,我將按照一般原則清理數據:

  • 保留數字類型: 如果某列應為數字(例如quantity、unitprice、customerid),請保留該列。使用數字類型進行數字運算會更加高效且更有意義。
  • 混合/字符串數據的對象類型: Pandas 中的dtypeobject指的是包含混合類型或主要為字符串的列。如果某列確實包含數字和字符串的混合,object則 dtype 為默認值。
  • 各種缺失數據: Pandas 會處理NaN缺失的數字數據和None缺失的對象數據。然而,當我們讀取數據時,缺失值可能表示為空字符串、特定文本(例如“N/A”),甚至只是空格,而 Pandas 可能無法自動將其解釋為NaN。我們需要識別這些值。

識別 NaN

對于具有混合數據類型的列,我將潛在的缺失值(如空格或“nan”字符串)轉換為NumPy’s NaN。

這對于后期的準確歸集是一個至關重要的準備。

import numpy as np 

obj_cols = [ 'invoiceno' , 'stockcode' , 'country' , 'invoicedate' ] 

# 列出潛在的 NaN 值
null_vals = [ '' , 'nan' , 'N/A' , None , 'na' , 'None' , 'none' ] 
removed_null = { item: np.nan for item in null_vals } 

for col in obj_cols: 
    df[col].replace(replaced_null, inplace= True ) 

df.info()

圖片圖片

現在,識別每列中缺失的數據(NumPy 的 NaN):

對于i, col in  enumerate (df.columns): 
    unique_num = df[col].nunique() 
    nan_num = df[col].isna(). sum () 
    print(f'{i}. {col} - {unique_num:,} data points (missing data: {nan_num:,})')

圖:每列中發現的缺失值圖:每列中發現的缺失值

處理description和customerid列中缺失的數據:

  • 我決定刪除description列,因為假設它對未來預測的影響有限。 注意:文本數據對于產品因式分解可能很有價值,尤其是在缺失部分比較有限的情況下。
  • 我保留了原有的customerid列來評估唯一用戶的影響,同時引入了一個新的is_registered二分類列(1:已注冊,0:未注冊),該列對應于每個客戶 ID,假設沒有 ID 的客戶未注冊。 注意:customerid這會導致基數過高。稍后我將使用二分類編碼來解決這個問題。
# 工程化之前復制基礎數據集
df_rev = df.copy() 

df_rev = df_rev.drop(columns='description')
df_rev['is_registered'] = np.where(df_rev['customerid'].isna(), 0, 1)

轉換數據類型

最后,考慮到潛在的特征工程,我轉換了invoicedate和 customerid的數據類型:

import pandas as pd

df_rev['invoicedate'] = pd.to_datetime(df_rev['invoicedate'])
df_rev['customerid'] = df_rev['customerid'].astype('Int64')
df_rev.info()

添加了第 7 列。第 5 列的數據類型已更新。添加了第 7 列。第 5 列的數據類型已更新。

探索性數據分析(EDA)和特征工程

清理完數據集后,我們現在可以轉到 EDA。

探索性數據分析 (EDA) 是一種專注于總結和可視化數據以了解其主要特征的數據分析技術。

從技術角度來說,我們可以執行無數次 EDA,尤其是在復雜數據集上。但我們的主要重點是揭示需要設計哪些特征,并深入了解數據預處理,從而提升模型性能。

任何其他分析都應該由模型本身處理,因為真正的底層模式要么太微妙,要么太復雜,我們無法手動發現。

因此,EDA 成為模型確定哪些分析(例如隱藏趨勢、群體差異)值得轉化為預測的第一步。

EDA 必須包含:

  1. 用于理解數據的基本分析(以單變量為重點) ;
  2. 基于與項目目標直接相關的假設進行的項目特定分析(以雙變量為重點)

1)基本分析(單變量重點)

這個初始階段是通過單獨分析每個變量來從根本上了解數據集。

首先,為了準備 EDA,我從列中提取了year、month,并按以下順序對數據進行排序:day_of_week,invoicedate,invoicedate

df_rev['invoicedate'] = pd.to_datetime(df_rev['invoicedate'])
df_rev['year'] = df_rev['invoicedate'].dt.year
df_rev['year_month'] = df_rev['invoicedate'].dt.to_period('M')
df_rev['month_name'] = df_rev['invoicedate'].dt.strftime('%b')
df_rev['day_of_week'] = df_rev['invoicedate'].dt.strftime('%a')
df_rev = df_rev.sort_values('invoicedate')

還推出了sales銷售分析專欄:

df_rev['sales'] = df_rev['quantity'] * df_rev['unitprice']

數據集如下:

圖片圖片

添加了第 8 列至第 12 列添加了第 8 列至第 12 列

了解數據分布

我繪制了數值特征的 PDF 和分類特征的直方圖,以識別異常值、傾斜和重尾等特征。

盡管真實的數據分布過于復雜而難以完全掌握,但分析對于有效的預處理和模型選擇至關重要。

數值列的 PDF

unitprice 和sales都是稀疏的,并且尾部嚴重,存在顯著的異常值。我將使用MAE作為評估指標,因為它對傾斜數據具有較好的魯棒性。

圖:unitprice和sales的PDF圖:unitprice和sales的PDF

圖:unitprice和sales的PDF

  • unitprice:最大值:38,970.0,最小值:-11,062.1,平均值:4.6,標準差:96.8
  • sales:最大值:168,469.6,最小值:-168,469.6,平均值:18.0,標準差:378.8

分類特征直方圖

invoiceno、year_month和day_of_week均勻分布:

圖片圖片

圖片圖片

圖片圖片

stockcode左側有一個峰值,右側有一個長尾,而quantity和country則顯示出退化分布,其中數據集中在幾個類別中:

圖片圖片

圖片圖片

圖片圖片

is_registered和year結果也是二分類的:

圖片圖片

圖片圖片

在此基礎上,我將進行針對特定項目的 EDA,以找出額外的特征工程機會。

2)項目特定的EDA

此階段深入研究,特別是尋找變量之間的關系,特別是潛在特征和目標變量之間的關系:sales。

首先,我將根據“銷售增長”這一挑戰的潛在解決方案提出三個假設。實際上,可以利用商業和專家的見解來完善這些假設。

假設1

“銷售趨勢是由一周中的某天或一個月中的某天決定的。”

鑒于數據集有限的 13 個月的銷售數據(二進制year),我關注較短的趨勢周期。

  • 需要設計的潛在特性is_weekend:day_of_month
  • 潛在商業解決方案:順應趨勢的大量促銷。

假設2

“產品銷售受時間和價格點驅動。”

需要設計的潛在特性:

  • unit_price_bin:unitprice離散化為“低”、“中”、“高”類別,直接解決價格影響和非線性。
  • product_avg_quantity_last_month:計算每個產品quantity在上一日歷月的平均銷量stockcode并獲取近期產品的受歡迎程度。
  • product_sales_growth_last_month:從 2 個月前到上個月stockcode的銷售額百分比變化,以確定流行產品。

潛在的商業解決方案:

  • 動態定價(通過促銷時機預測最佳價格點的模型)。
  • 定制產品推薦(預測產品因素相似性的模型)。

假設3

“活躍的顧客往往會購買更多商品,從而促進銷售。”

需要設計的潛在特性:

  • customer_recency_days:預測日期(上個月底)與客戶上次購買日期之間的天數,以評估近期購買的可能性。
  • customer_total_spend_ltm:客戶過去三個月產生的總銷售收入。這是對客戶近期貨幣價值的直接衡量。
  • customer_freq_ltm:過去三個月內客戶開具的唯一發票總數。這是直接影響銷售額的參與度指標之一。

潛在的商業解決方案:

  • 分層客戶忠誠度計劃(預測唯一用戶保留時間的模型)
  • 營銷媒體組合優化(預測新客戶價值的模型)

現在,執行 EDA 并決定要設計哪些特性。

假設 1

“銷售趨勢受一周中的某天或一個月中的某天的影響。”

除了11月的峰值之外,按月和按周劃分的銷售趨勢沒有出現明顯的模式。因此,我選擇不添加基于此假設的其他特征。

圖:按月份和星期幾劃分的銷售趨勢圖:按月份和星期幾劃分的銷售趨勢

假設2

“產品銷售受時間和價格點驅動。”

對于unit_price_bin,幾乎所有月份的三個價格區間的中線都接近于零。所有區間的四分位距 (IQR) 也很短,這表明 25-75 百分位數數據落在一個非常小的低量范圍內。

然而,我們可以看到異常值占據了主導地位,形成了明顯的分層。

因此,我決定添加特征unit_price,同時保留原有的粒度,使用箱內的精確值來預測數量。

圖:按價格范圍(低、中、高)劃分的月銷售總量及中位數和四分位距圖:按價格范圍(低、中、高)劃分的月銷售總量及中位數和四分位距

添加unit_price_bin到最終數據集:

import pandas as pd

# df_fin 將成為我們模型訓練的主要數據
df_fin = df_rev.copy() 

# 創建臨時數據
_df_prod_month_agg = df_fin.copy().groupby(['stockcode', 'year_month']).agg(
    prod_total_monthly_quantity=('quantity', 'sum'),
    prod_ave_monthly_price=('unitprice', 'mean')
).reset_index().sort_values(by=['stockcode', 'year_month'])

_df_prod_month_agg['unit_price_bin'] = pd.qcut(
    _df_prod_month_agg['prod_ave_monthly_price'],
    q=3,
    labels=['low', 'mid', 'high'],
    duplicates='drop'
)

_df_prod_bin_per_stockcode = _df_prod_month_agg.groupby('stockcode')['unit_price_bin'].agg(
    lambda x: x.mode()[0] ifnot x.mode().empty elseNone
).reset_index()

# 合并到主數據集 (df_fin)
df_fin = pd.merge(
    df_fin,
    _df_prod_bin_per_stockcode[['stockcode', 'unit_price_bin']],
    notallow='stockcode',
    how='left'
)

df_fin.info()

添加了第 13 列添加了第 13 列

product_avg_quantity_last_month也顯示出非常強的正相關性,這可以作為一個動量特征,表明上個月銷量好的產品本月也容易銷量好。我會添加這個特征。

圖:本月和上個月銷售的平均產品數量圖:本月和上個月銷售的平均產品數量

添加product_avg_quantity_last_month到最終數據集(也處理插補):

import pandas as pd

_df_prod_month_agg['product_avg_quantity_last_month'] = _df_prod_month_agg.groupby('stockcode')['prod_total_monthly_quantity'].shift(1)
_df_prod_last_month_agg = _df_prod_month_agg.groupby('stockcode')['product_avg_quantity_last_month'].mean().reset_index()
df_fin = pd.merge(
    df_fin,
    _df_prod_last_month_agg [['stockcode', 'product_avg_quantity_last_month']],
    notallow='stockcode',
    how='left'
)

# 缺失數據意味著在該期限內沒有售出任何產品。用零進行插補。
df_fin['product_avg_quantity_last_month'] = df_fin['product_avg_quantity_last_month'].fillna(value=0)
df_fin.info()

添加了第 14 列添加了第 14 列

另一方面,product_sales_growth_last_month它沒有表現出很強的線性/單調關系。考慮到這個特征的預測能力有限,我選擇不添加它。

圖:月度產品數量與上月銷售額增長率圖:月度產品數量與上月銷售額增長率

假設3

“活躍顧客傾向于購買更多產品并對銷售做出貢獻。”

customer_recency_days表明新近度較低的客戶(最近的購買,例如 x < 60 天)往往表現出更高的月銷售收入,表明呈反比關系(圖中紅色虛線)。

我將添加此特征來預測每月的銷售收入。

圖:月銷售額與客戶最近消費天數圖:月銷售額與客戶最近消費天數

添加customer_recency_days到數據集:

import pandas as pd 

# 創建臨時數據集
_df_all_customers_year_month = pd.MultiIndex.from_product(
    [df_fin['customerid'].unique(), df_fin['year_month'].unique()], # type: ignore
    names=['customerid', 'year_month']
).to_frame(index=False).sort_values(by=['customerid', 'year_month']).reset_index(drop=True)

_df_customer_monthly_agg = df_fin.copy().groupby(['customerid', 'year_month']).agg(
    monthly_sales=('sales', 'sum'),
    monthly_unique_invoices=('invoiceno', 'nunique'),
    monthly_last_purchase_date=('invoicedate', 'max')
).reset_index()

_df_cus = _df_all_customers_year_month.merge(_df_customer_monthly_agg, notallow=['customerid', 'year_month'], how='left').sort_values(by=['customerid', 'year_month'])

# 添加時間戳
_df_cus['pfin_last_purchase_date'] = _df_cus.groupby('customerid')['monthly_last_purchase_date'].shift(1)
_df_cus['invoice_timestamp_end'] = _df_cus['year_month'].dt.end_time

# 計算新近天數
_df_cus['customer_recency_days'] = (_df_cus['invoice_timestamp_end'] - _df_cus['pfin_last_purchase_date']).dt.days

# 合并和估算
df_fin['customer_recency_days'] = _df_cus['customer_recency_days']

max_recency = _df_cus['customer_recency_days'].max()
df_fin['customer_recency_days'] = df_fin['customer_recency_days'].fillna(value=max_recency + 30)

df_fin.info()

添加了第 15 列添加了第 15 列

customer_total_spend_ltm顯示出客戶過去三個月的總支出與其當前月銷售收入之間存在明顯的正相關關系。這表明,過去支出越高,當前收入就越高,這是一個非常有效的預測特征。我會添加這個特征。

圖:過去三個月的月銷售額與客戶總支出圖:過去三個月的月銷售額與客戶總支出

添加customer_total_spend_ltm:

_df_cus['customer_total_spend_ltm'] = _df_cus.groupby('customerid')['monthly_sales'].rolling(window=3, closed='left').sum().reset_index(level=0, drop=True)

df_fin['customer_total_spend_ltm'] = _df_cus['customer_total_spend_ltm']
df_fin['customer_total_spend_ltm'] = df_fin['customer_total_spend_ltm'].fillna(value=0)

df_fin.info()

添加了第 16 列添加了第 16 列

customer_freq_ltm還展示了客戶過去三個月的購買頻率與其當前月銷售收入之間的正相關關系。過去三個月擁有更多獨立發票的客戶往往能帶來更高的月收入。我也會添加此特征。

圖:過去三個月的月銷售額與客戶頻率圖:過去三個月的月銷售額與客戶頻率

添加customer_freq_ltm:

_df_cus['customer_freq_ltm'] = _df_cus.groupby('customerid')['monthly_unique_invoices'].rolling(window=3, closed='left').sum().reset_index(level=0, drop=True)

df_fin['customer_freq_ltm'] = _df_cus['customer_freq_ltm']
df_fin['customer_freq_ltm'] = df_fin['customer_freq_ltm'].fillna(value=0)

df_fin.info()

添加了第 17 列添加了第 17 列

對缺失值的最終檢查

特征工程完成后,我檢查了剩余的缺失值,在更新后的數據集中的stockcode、quantity、unit_price_bin和country列中發現了五個缺失項:

df_fin.isna().sum ()

我會在編碼過程中處理丟失的客戶 ID)我會在編碼過程中處理丟失的客戶 ID)

我會在編碼過程中處理丟失的客戶 ID)

逐一檢查這些缺失的項目并進行估算。

注意:鑒于 540k+ 個樣本中最多只有 20 個有缺失值,因此可以選擇按行刪除(即從數據集中刪除這些樣本)。

對于stockcode和unit_price_bin,樣本中缺失stockcode或unit_price_bin的其他值看起來是合法的。

我用“unknown”(字符串)和“low”換替換了stockcode和unit_price_bin中的缺失的值:

df_null = df_fin[df_fin['stockcode'].isnull()] 
df_null.head().transpose()

圖片圖片

df_fin['stockcode'] = df_fin['stockcode'].fillna(value='unknown')
df_fin['unit_price_bin'] = df_fin['unit_price_bin'].fillna(value='low')

country采取同樣的過程,和列中的缺失值quantity分別用其眾數值和銷售額/單價值填充:

import numpy as np

df_fin['country'] = df_fin['country'].fillna(value=df_fin['country'].mode().iloc[0]) 
df_fin['quantity'] = df_fin['quantity'].fillna(value=np.floor(df_fin['sales'] / df_fin['unitprice']))

最后,轉換數據類型以最終確定數據集:

df_fin['year_month'] = df_fin['year_month'].dt.month
df_fin['invoicedate'] = df_fin['invoicedate'].astype(int) / 10 ** 9
df_fin = df_fin.drop(columns=['month_name'], axis='columns')

df_fin.info()

最終數據集最終數據集

該數據集的最終版本有541,909 個樣本,包含17 個特征:

cat_cols = [ 
    'invoiceno' , 
    'stockcode' , 
    'quantity' , 
    'customerid' , 
    'country' , 
    'year' , 
    'year_month' , 
    'day_of_week' , 
    'is_registered' , 
    'unit_price_bin' , 
    'customer_recency_days' , 
] 
num_cols = [ 
    'unitprice' , 
    'product_avg_quantity_last_month' , 
    'customer_total_spend_ltm' , 
    'customer_freq_ltm' , 
    'invoicedate'
 ] 

target_col = 'sales'

回顧——第一階段的特征工程

根據 EDA 結果,我添加了 11 個特征:

  • 來自單變量EDA :is_registered,year,year_month,month_name,day_of_week,sales
  • 來自雙變量EDA:unit_price_bin,product_avg_quantity_last_month,customer_recency_days,customer_total_spend_ltm,customer_freq_ltm

并刪除了一個特征:description由于其缺失值量較大且對預測的影響有限。

一文帶你用sklearn做特征工程

一文詳盡特征工程與數據預處理

4. 模型選擇

鑒于數據集復雜且龐大,我選擇了以下三種模型:

  • 彈性網絡:正則化線性回歸模型,適合作為線性可分數據的基線。
  • 隨機森林:一種能夠捕捉復雜、非線性關系的強大機器學習模型。
  • 深度前饋網絡:一種深度學習模型,可作為非線性可分離數據的強大基礎。為了有效地管理大型數據集,我使用了PyTorch庫。

原理+代碼,總結了 11 種回歸模型

萬字長文,演繹八種線性回歸算法最強總結!

總結了九種機器學習集成分類算法(原理+代碼)

理論+股市數據實戰,總結了五種常用聚類分析算法

總結了17個機器學習的常用算法!

5. 在預處理數據上訓練模型

首先,我將數據集分成所有模型的訓練集、驗證集和測試集。

我故意沒有對數據集進行打亂,以保留其時間順序。

from sklearn.model_selection import train_test_split

target_col = 'sales'
 X = df_fin.copy().drop(columns=target_col) 
y = df_fin.copy()[target_col] 

test_size = 50000
 X_tv, X_test, y_tv, y_test = train_test_split(X, y, test_size=test_size, random_state= 42 ) 
X_train, X_val, y_train, y_val = train_test_split(X_tv, y_tv, test_size=test_size, random_state= 42 )

每個模型對預處理的需求不同:

圖:按模型劃分的數據預處理要求圖:按模型劃分的數據預處理要求

因此,我將準備用于分別訓練每個模型的數據集。

彈性網絡

彈性網絡需要在縮放和編碼的數據集上進行訓練。

對于數值特征,我應用RobustScaler來處理我們在 EDA 期間發現的顯著異常值。

對于分類特征,我應用了BinaryEncoder來限制維度的增加,同時用零替換

customerid列中的缺失值:

from sklearn.preprocessing import RobustScaler
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from category_encoders import BinaryEncoder


# num
 num_transformer = Pipeline(steps=[ 
    ( 'scaler' , RobustScaler(with_centering= True , with_scaling= True )) 
]) 

# cat
 cat_transformer = Pipeline(steps=[ 
    ( 'encoder' , BinaryEncoder(cols=cat_cols, handle_missing= '0' )) 
]) 

# 定義一個預處理器
preprocessor_en = ColumnTransformer( 
    transforms=[ 
        ( 'num' , num_transformer, num_cols), 
        ( 'cat' , cat_transformer, cat_cols) 
    ], 
    remainder= 'passthrough' , 
) 

# 變換
X_train_processed = preprocessor_en.fit_transform(X_train) 
X_val_processed = preprocessor_en.transform(X_val) 
X_test_processed = preprocessor_en.transform(X_test) 

# 啟動并訓練模型
from sklearn.linear_model import ElasticNet 
elastic_net = ElasticNet( 
    alpha= 1 ,             # 正則化的總強度
    l1_ratio= 0.5 ,        # l1 到 l2 的比例 = 1:1
     fit_intercept= True , # 通過計算 y 截距進行擬合
    precompute= False ,    # 不使用預先計算的 Gram 矩陣
    max_iter= 5000 ,       # 1,000 個 epochs
     copy_X= True ,         # 擬合前復制 X
     tol= 1e-5 ,            # tol 停止迭代
    random_state= 42 ,     # 隨機數生成器的種子
    warm_start= False ,    # 忽略前一次擬合調用中的解
    positive= False ,      # 可以同時    選擇負系數和正系數"cyclic" # 循環地逐個更新系數(與隨機相比) ).fit(X_train_processed, y_train)

隨機森林

對于隨機森林,我們可以跳過縮放部分:

from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.ensemble import RandomForestRegressor
from category_encoders import BinaryEncoder


# 定義預處理器
cat_transformer = Pipeline(steps=[ 
    ( 'encoder' , BinaryEncoder(cols=cat_cols, handle_missing= '0' )) 
]) 

preprocessor_rf = ColumnTransformer( 
    transforms=[ 
        ( 'cat' , cat_transformer, cat_cols) 
    ], 
    remainder= 'passthrough' , 
) 


# 變換
X_train_processed = preprocessor_rf.fit_transform(X_train) 
X_val_processed = preprocessor_rf.transform(X_val) 
X_test_processed = preprocessor_rf.transform(X_test) 


# 啟動并訓練模型
random_forest = RandomForestRegressor(
    n_estimators=1000,
    criterinotallow="squared_error",
    max_depth=None,
    min_samples_split=2,
    min_samples_leaf=1,
    min_weight_fraction_leaf=0,
    max_features='sqrt',
    max_leaf_nodes=None,
    min_impurity_decrease=1e-10,
    bootstrap=True,
    oob_score=True,
    n_jobs=-1,
    random_state=42,
    verbose=0,
    warm_start=False,
    ccp_alpha=0,
    max_samples=None,
).fit(X_train_processed, y_train)

DFN

DFN 需要縮放和編碼。對于數值特征,我使用了StandardScaler,因為它在處理復雜數據方面具有良好的魯棒性。之后,數據集被轉換為TensorDataset:

import torch
from torch.utils.data import DataLoader, TensorDataset
from sklearn.preprocessing import StandardScaler
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from category_encoders import BinaryEncoder

num_transformer = Pipeline(steps=[('scaler', StandardScaler())])
cat_transformer = Pipeline(steps=[('encoder', BinaryEncoder(cols=cat_cols, handle_missing='0'))])

# 定義一個預處理器
preprocessor_dfn = ColumnTransformer( 
    transforms=[ 
        ( 'num' , num_transformer, num_cols), 
        ( 'cat' , cat_transformer, cat_cols) 
    ], 
    remainder= 'passthrough'
 ) 

# 轉換
X_train_processed_dfn = preprocessor_dfn.fit_transform(X_train) 
X_val_processed_dfn = preprocessor_dfn.transform(X_val) 
X_test_processed_dfn = preprocessor_dfn.transform(X_test) 


# 將 NumPy 數組轉換為 PyTorch 張量
X_train_tensor = torch.tensor(X_train_processed_dfn, dtype=torch.float32) 
X_val_tensor = torch.tensor(X_val_processed_dfn, dtype=torch.float32) 
X_test_tensor = torch.tensor(X_test_processed_dfn, dtype=torch.float32) 

# 轉換為 1D 張量
y_train_tensor = torch.tensor(y_train.values, dtype=torch.float32).view(- 1 , 1 ) 
y_val_tensor = torch.tensor(y_val.values, dtype=torch.float32).view(- 1 , 1 ) 
y_test_tensor = torch.tensor(y_test.values, dtype=torch.float32).view(- 1 , 1 ) 

# 轉換為 TensorDataset
 train_dataset = TensorDataset(X_train_tensor, y_train_tensor) 
val_dataset = TensorDataset(X_val_tensor, y_val_tensor) 
test_dataset = TensorDataset(X_test_tensor, y_test_tensor) 

# 批處理
batch_size = 32
train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=False)
val_loader = DataLoader(dataset=val_dataset, batch_size=batch_size, shuffle=False)
test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=False)

然后,啟動模型:

import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim

classDFN(nn.Module):
    def__init__(self, input_dim):
        super(DFN, self).__init__()
        self.fc1 = nn.Linear(input_dim, 32)
        self.relu1 = nn.ReLU()
        self.dropout1 = nn.Dropout(0.1)
        self.fc2 = nn.Linear(32, 16)
        self.relu2 = nn.ReLU()
        self.dropout2 = nn.Dropout(0.1)
        self.fc3 = nn.Linear(16, 1)
    defforward(self, x):
        x = self.fc1(x)
        x = self.relu1(x)
        x = self.dropout1(x)
        x = self.fc2(x)
        x = self.relu2(x)
        x = self.dropout2(x)
        x = self.fc3(x)
        return x

input_dim = X_train_processed_dfn.shape[1]

device = torch.device('cuda'if torch.cuda.is_available() else'cpu')

model = DFN(input_dim).to(device)
criterion = nn.L1Loss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

訓練模型:

from sklearn.metrics import mean_squared_error, mean_absolute_error

num_epochs = 100
best_val_loss = float('inf')
patience = 10
patience_counter = 0
min_delta = 1e-4
history = {
'train_loss': [],
'val_loss': [], 
'train_mse': [], 
'val_mse': [], 
'train_mae': [], 
'val_mae': []
}

for epoch in range(num_epochs):
    model.train()

    running_train_loss = 0.0
    all_train_preds = []
    all_train_targets = []

    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()
        outputs = model(data)
        loss = criterion(outputs, target)
        loss.backward()
        optimizer.step()
        running_train_loss += loss.item() * data.size(0)
        all_train_preds.extend(outputs.detach().cpu().numpy())
        all_train_targets.extend(target.detach().cpu().numpy())

    epoch_train_loss = running_train_loss / len(train_dataset)
    train_mse = mean_squared_error(np.array(all_train_targets), np.array(all_train_preds))
    train_mae = mean_absolute_error(np.array(all_train_targets), np.array(all_train_preds))
    
    model.eval()
    running_val_loss = 0.0
    all_val_preds = []
    all_val_targets = []

    with torch.no_grad():
        for data, target in val_loader:
            data, target = data.to(device), target.to(device)
            outputs = model(data)
            loss = criterion(outputs, target)
            running_val_loss += loss.item() * data.size(0)
            all_val_preds.extend(outputs.cpu().numpy())
            all_val_targets.extend(target.cpu().numpy())

    epoch_val_loss = running_val_loss / len(val_dataset)
    val_mse = mean_squared_error(np.array(all_val_targets), np.array(all_val_preds))
    val_mae = mean_absolute_error(np.array(all_val_targets), np.array(all_val_preds))

    history['train_loss'].append(epoch_train_loss)
    history['val_loss'].append(epoch_val_loss)
    history['train_mse'].append(train_mse)
    history['val_mse'].append(val_mse)
    history['train_mae'].append(train_mae)
    history['val_mae'].append(val_mae)

結果

平均輔助能量吸收

  • 彈性網絡:訓練:19.773 → 驗證:18.508
  • 隨機森林:訓練:4.147 → 驗證:10.551
  • 深度前饋網絡:訓練:10.570 → 驗證:10.987

Elastic Net 的泛化能力良好(訓練集 19.77,驗證集 18.51),但平均誤差最高。其預測與實際銷售額的偏差約為18.50 美元至 19.77 美元。

隨機森林過擬合嚴重(訓練集 4.15,驗證集 10.55)。平均而言,其對新數據的預測偏差約為10.55 美元。

深度前饋網絡 (DFN)表現出了出色的泛化能力(訓練集 10.57,驗證集 10.99),并且在未見數據上實現了較低的平均誤差。其預測偏差約為10.99 美元。

總而言之,隨機森林是表現最好的模型,但 DFN 在泛化方面也表現出色。

圖片圖片

圖片圖片

圖片圖片

圖:實際銷售額與預測銷售額(左:彈性網絡,中:隨機森林),DFN 的損失歷史記錄(右)

第二階段:迭代改進

第一階段的結果表明,這三個模型的泛化能力仍有提升空間。

我對銷售值應用了對數轉換,以便為模型的目標變量創建更加對稱的分布。

為了區分退款(sales列中的負銷售額)和正銷售額,我創建了一個is_return二分類token(1 表示退款,0 表示銷售額)。這樣一來,sales列就可以只關注正銷售額。

從數學上講,對負值取對數的結果是NaN。因此,我先用零替換負銷售額,然后應用拉普拉斯平滑法。這也能避免對數銷售額中出現負無窮值。

import numpy as np 

# 使用新數據集
df_fin_rev = df_fin.copy() 

# 添加 is_return 標志
df_fin_rev['is_return'] = (df_fin_rev['sales'] < 0).astype(int) 

# sales 列中的零值或正值
df_fin_rev[ 'sales' ] = df_fin_rev[ 'sales' ].apply( lambda x: max (x, 0 )) 

# 在取對數之前應用拉普拉斯平滑
alpha = 1
df_fin_rev['sales'] = np.log(df_fin_rev['sales'] + alpha)

df_fin_rev.info()

添加第 17 列。變換第 11 列。添加第 17 列。變換第 11 列。

在確保數據集中除 customerid 列外不存在缺失值后:

df_fin_rev.isna().sum ()

圖片圖片

我使用相同的預處理步驟和超參數重新訓練了模型:

import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.metrics import mean_squared_error, mean_absolute_error
from category_encoders import BinaryEncoder

# 創建數據集
X = df_fin_rev.copy().drop(columns=target_col)
y = df_fin_rev.copy()[target_col]

test_size = 50000
X_tv, X_test, y_tv, y_test = train_test_split(X, y, test_size=test_size, random_state=42)
X_train, X_val, y_train, y_val = train_test_split(X_tv, y_tv, test_size=test_size, random_state=42)

# 預處理
num_transformer = Pipeline(steps=[('scaler', StandardScaler())])
cat_transformer = Pipeline(steps=[('encoder', BinaryEncoder(cols=cat_cols, handle_missing='0'))])
preprocessor_en = ColumnTransformer(
    transformers=[
        ('num', num_transformer, num_cols),
        ('cat', cat_transformer, cat_cols)
    ],
    remainder='passthrough'
)
X_train_processed_en = preprocessor_en.fit_transform(X_train)
X_val_processed_en = preprocessor_en.transform(X_val)
X_test_processed_en = preprocessor_en.transform(X_test)

# 模型訓練
elastic_net.fit(X_train_processed_en, y_train)

# 預測 (對數銷售額)
y_pred_train = elastic_net.predict(X_train_processed_en) 
y_pred_val = elastic_net.predict(X_val_processed_en)
y_pred_test = elastic_net.predict(X_test_processed_en)

# 評估 - 對數銷售額 - 使用 MSE 進行評估
mse_train = mean_squared_error(y_train, y_pred_train)
mse_val = mean_squared_error(y_val, y_pred_val)
mse_test = mean_squared_error(y_test, y_pred_test)

# 評估 - 實際銷售額 - 使用 MAE 進行評估
mae_train_exp = mean_absolute_error(np.exp(y_train), np.exp(y_pred_train))
mae_val_exp = mean_absolute_error(np.exp(y_val), np.exp(y_pred_val))
mae_test_exp = mean_abolute_error(np.exp(y_test), np.exp(y_pred_test))

結果

使用記錄的銷售數據的MSE和實際值銷售的MAE來評估模型性能:

彈性網絡:

  • 對數銷售的 MSE:訓練集:1.133 → 1.132,泛化集:1.122
  • 實值銷售的 MAE:訓練集:15.825 → 14.714,泛化集:16.509

隨機森林:

  • 對數銷售額的 MSE:訓練集:0.020 → 0.175,泛化集:0.176
  • 實值銷售的 MAE:訓練集:4.135 → 7.187,泛化集:9.041

DFN:

  • 對數銷售額的 MSE:訓練集:1.079 → 0.165 泛化集:0.079
  • 實值銷售的 MAE:訓練集:5.644 → 5.016,泛化集:6.197

(基于 50,000 個測試樣本的概括。)

與第一階段相比,所有模型中實際銷售額的 MAE 都有所提高,這表明目標變量密度的重要性。

其中,DFN 在訓練集(5.64)和泛化集(6.20)中均表現出較低的 MAE,展現出最佳性能,表明其在復雜、大型數據集上的學習和泛化能力較強。其對未見數據的預測偏差約為6.20 美元。

Elastic Net表現出了極好的泛化能力,但其對未見數據的預測偏差為16.51 美元,是所有模型中偏差最大的,這表明其在處理復雜數據集時遇到了困難。

隨機森林表現出嚴重的過擬合,其較低的訓練 MAE(4.14)與較高的泛化 MAE(9.04)之間存在較大差距。該模型的下一步可以進行超參數調整,以收緊正則化變量和樹結構。

實驗總結

實驗表明,PyTorch 上的 DFN 在具有 EDA 期間識別的特征的轉換數據集上表現最佳。

回到業務解決方案的初始假設,我們可以將這一發現直接用于營銷媒體組合優化,例如,使 DFN 能夠預測新客戶的終身價值并優化對高價值客戶渠道的預算分配。

下一步,我們可以在第 2 階段進一步探索特征工程,或者進入第 3 階段調整超參數以完善結果。

寫在最后

特征工程不僅僅是數據操作;它是一種從原始數據中獲取強大洞察力并顯著提高模型解決當前問題的能力的戰略方法。

在我們的實驗中,我們觀察到特征工程顯著提升了模型的性能,尤其是在與 EDA 和業務目標緊密結合的情況下。通過與領域專家和業務利益相關者合作完善假設,我們有望實現進一步的改進。

通過投入時間和精力來制定有效的輸入,我們從根本上增強了模型的學習、概括和提供卓越預測性能的能力。

責任編輯:武曉燕 來源: 數據STUDIO
相關推薦

2021-05-10 16:41:19

機器學習人工智能IT

2024-06-13 09:12:38

2024-10-08 10:16:22

2024-10-28 00:00:10

機器學習模型程度

2024-10-28 15:52:38

機器學習特征工程數據集

2024-10-08 15:09:17

2018-07-23 15:35:17

機器學習特征工程技能數據科學

2016-04-12 17:12:29

機器學習數據清洗美團

2021-04-20 14:18:57

人工智能機器學習

2021-04-01 22:19:54

機器學習模型數據

2014-04-18 10:58:44

AndroidAPI實踐

2024-07-31 15:36:00

2017-02-05 17:10:41

機器學習深度學習框架

2019-06-25 10:09:42

Web攻擊機器學習網絡攻擊

2021-01-26 09:46:59

PythonStacking機器學習

2020-11-26 18:30:33

機器學習Kubernetes開發

2018-10-05 23:26:00

機器學習算法數據

2022-02-16 07:00:00

機器學習特征選擇過濾法

2022-10-08 12:06:52

機器學習特征選擇

2024-12-26 00:34:47

點贊
收藏

51CTO技術棧公眾號

在线 丝袜 欧美 日韩 制服| 国产一区二区在线观看免费| 成人精品鲁一区一区二区| 精品亚洲一区二区三区| 91精品啪在线观看麻豆免费| 99久久国产精| 午夜av在线播放| 精品日韩在线| 天天影视网天天综合色在线播放| 国产在线拍揄自揄视频不卡99| 亚洲最大的黄色网| 中文字幕中文字幕在线十八区| 日产欧产美韩系列久久99| 亚洲精品成人免费| 韩国无码av片在线观看网站| 97超碰人人模人人人爽人人爱| 欧美激情在线精品一区二区三区| 午夜精品一区二区三区三上悠亚| 成人国产一区二区| 久久黄色小视频| 榴莲视频成人app| 国产精品福利影院| 国产日韩欧美夫妻视频在线观看| 青青草原国产视频| 欧美日韩精品一区二区视频| 欧美精品一区二区三区视频| 久久亚洲a v| 精品人妻久久久久一区二区三区| 91精品电影| 日韩欧美中文字幕一区| 4444亚洲人成无码网在线观看 | 精品视频一区三区九区| 精品视频一区二区| 国产一级一级片| 成人香蕉社区| 偷窥国产亚洲免费视频| 中文字幕精品—区二区日日骚| 亚洲视频在线观看免费视频| 欧美成人激情| 欧美一卡二卡在线观看| 日本a级片在线观看| 国产福利资源在线| 亚洲精选久久| 亚洲视频999| 日本三级黄色网址| 亚洲第一图区| 1024国产精品| 国产精品视频免费一区| 日本一区二区网站| 国产成人久久| 欧美日韩夫妻久久| 男女啪啪免费观看| 欧美激情免费| av毛片久久久久**hd| 国产成人精品av在线| 91大神福利视频| 日韩精品三级| 欧美视频在线看| 一区二区成人国产精品| 国产高清视频免费观看| 激情久久五月天| 久久久久久中文| 成人性生交大免费看| 日本免费成人| 午夜在线电影亚洲一区| 男女激情免费视频| 国产精品秘入口| 国产伦精一区二区三区| 欧美在线视频网| 2014亚洲天堂| 日韩在线影视| 91精品综合久久久久久| 亚洲熟女乱色一区二区三区| 久操视频在线| 久久老女人爱爱| 91嫩草国产在线观看| 人妻 日韩精品 中文字幕| 中文字幕免费一区二区| 亚洲午夜精品久久久久久久久久久久| 伦伦影院午夜理论片| 欧美韩国亚洲| 午夜精品福利一区二区蜜股av | 国产在线观看精品一区二区三区| 97超碰人人草| 不卡视频在线观看| 欧美一区二区福利| 国产不卡av在线播放| 高清在线不卡av| 91精品国产综合久久香蕉的用户体验| 97人妻精品一区二区三区动漫| 国产精品外国| 久久久久国产精品一区| 日韩欧美激情视频| 欧美日韩精品一本二本三本| 夜夜躁日日躁狠狠久久88av| 波多野结衣加勒比| 精品国产第一国产综合精品| 亚洲国产精久久久久久 | 亚洲欧美中文在线视频| 日本视频在线免费| 亚洲人成亚洲精品| 亚洲成人在线网| 无码 人妻 在线 视频| 亚洲精品国产九九九| 欧美精品乱码久久久久久按摩| 日韩av在线综合| 在线天堂新版最新版在线8| 亚洲一区二区美女| 欧美狂野激情性xxxx在线观| 日韩伦理福利| 欧美日韩一区二区在线| 奇米影视亚洲色图| 日韩三级影院| 国产精品乱码妇女bbbb| 亚洲第一导航| 在线国产91| 欧美经典一区二区| 天堂资源在线亚洲视频| 国产女人在线视频| 亚洲最新在线观看| av在线播放亚洲| 婷婷精品久久久久久久久久不卡| 亚洲精品福利在线观看| 色欲一区二区三区精品a片| 欧美激情欧美| 热久久这里只有| 囯产精品一品二区三区| 成人免费视频app| 精品国产一二| 在线看福利影| 欧美日韩高清不卡| 国产成人一区二区在线观看| 欧美午夜精彩| 日韩亚洲欧美中文在线| 欧美黑人性猛交xxx| 欧美阿v一级看视频| 久久久久久久一| 国产乱子伦精品无码码专区| 国产日韩欧美精品综合| 伊人久久大香线蕉av一区| 玛雅亚洲电影| 欧美群妇大交群中文字幕| 人人妻人人藻人人爽欧美一区| 午夜精品久久久久99热蜜桃导演| 国产一区视频在线播放| 最新av网站在线观看| 色综合久久久久综合99| 中文字幕精品一区二区三区在线| 麻豆视频久久| 久久久精品亚洲| 久久久久久av无码免费网站| 国产日本精品| 精品久久久久久乱码天堂| 精品精品导航| 在线观看视频欧美| 日韩欧美中文在线视频| 亚洲美女视频| 亚洲在线免费视频| 四虎影视精品成人| 中文字幕一区二区视频| 国产3p在线播放| 91麻豆精品国产91久久久平台 | 精品无人区太爽高潮在线播放| 久久精品女人毛片国产| 成人高清在线视频| 欧美 日韩 国产在线观看| 欧美精品高清| 国产亚洲精品久久久久久牛牛| 国产精品自拍第一页| 国产精品一区二区三区99| 一本色道久久88亚洲精品综合| 另类视频一区二区三区| 久久久久久久国产| 同心难改在线观看| 欧美在线999| 逼特逼视频在线观看| 日韩欧美视频| 欧洲日韩成人av| 国产在线三区| 性久久久久久久久| 中文字幕一区二区三区人妻不卡| 日韩专区在线视频| 国产精品免费在线| 超碰超碰人人人人精品| 中文字幕欧美亚洲| 国产精品va无码一区二区三区| 久久亚洲一区二区三区四区| 午夜免费福利在线| 亚洲精品456| 国产欧美婷婷中文| 波多野结衣在线观看| 91精品国产欧美日韩| 国产在线拍揄自揄拍无码视频| 91原创在线视频| 欧美亚洲黄色片| 极品尤物一区| 国语自产精品视频在线看| 99国产精品久久久久99打野战| 国产女同互慰高潮91漫画| 手机在线视频一区| 日韩一区亚洲二区| 国产v亚洲v天堂无码| 日本中文在线观看| 精品久久久久久久人人人人传媒| 综合五月激情网| 91社区在线播放| 无码aⅴ精品一区二区三区浪潮| 日本黄色精品| 国产在线欧美日韩| 草草影院在线| 日韩中文字幕在线视频播放| 天天色综合av| 精品福利一区二区| 国产免费一区二区三区四区| 91免费在线播放| 宇都宫紫苑在线播放| 日韩精品一级二级 | 51国产成人精品午夜福中文下载| 老司机深夜福利在线观看| 久久久精品国产| 国产视频在线看| 亚洲精品久久久久久久久久久久 | 色戒汤唯在线观看| 美女久久久久久久久久久| 亚洲在线免费观看视频| 欧美丝袜第一区| 久久综合加勒比| 日韩理论片在线| 91亚洲一区二区| 日韩高清不卡一区二区三区| 妞干网在线视频观看| 亚洲美女视频| 大桥未久一区二区三区| 在线综合色站| 91精品美女在线| 亚洲奶水xxxx哺乳期| 在线看欧美日韩| 嫩草在线播放| 欧美日韩国产综合久久| 中文字幕免费观看| 日韩一区在线看| 欧美丰满老妇熟乱xxxxyyy| 91在线观看高清| 内射中出日韩无国产剧情| 成人免费观看视频| 一级黄色片毛片| 日韩1区2区3区| 国产日韩成人内射视频| 亚洲一级淫片| 综合国产精品久久久| 国产精品久久久久蜜臀| 国产精品日韩一区二区免费视频| 成人污污www网站免费丝瓜| 久久久久久久久电影| 欧美黄色视屏| 久久青草福利网站| 欧美13videosex性极品| 77777少妇光屁股久久一区| 欧美高清视频| 久久亚洲精品一区二区| 色哟哟在线观看| 7777精品伊人久久久大香线蕉超级流畅| 欧美男人天堂网| 亚洲国产日韩a在线播放性色| 妺妺窝人体色WWW精品| 国产视频一区二区在线观看| 欧美成人国产精品一区二区| 国产欧美一区二区三区沐欲| 91无套直看片红桃在线观看| 中文字幕一区免费在线观看| 91久久国产综合| 亚洲午夜精品网| 国产原创视频在线| 亚洲乱码国产乱码精品精的特点| 香蕉网在线播放| 欧美激情综合在线| 国产免费一区二区三区四区| 亚洲自拍另类综合| 国产又爽又黄的视频| 亚洲精品中文字幕乱码三区| 精品视频一区二区在线观看| 婷婷中文字幕综合| 亚洲婷婷久久综合| 制服丝袜亚洲网站| 欧美一级视频免费| 91精品综合久久久久久| 成人免费公开视频| 亚洲欧美日韩一区二区三区在线| 高潮一区二区三区乱码| 亚洲精品在线视频| 色综合久久影院| 久久久久久网址| 91成人抖音| 国产不卡视频在线| **日韩最新| 国产欧美日韩中文字幕在线| 成人三级毛片| 五月婷婷综合色| 一区精品久久| 国产性生活免费视频| 午夜一区二区三区不卡视频| 91专区在线观看| 麻豆精品一区二区| 五月婷婷六月合| 成人黄色国产精品网站大全在线免费观看 | 国产欧美日本在线| 成人在线电影在线观看视频| 黄色一级片在线看| 久久99国产精品久久99果冻传媒| 成人性生生活性生交12| 视频一区国产视频| 苍井空浴缸大战猛男120分钟| 国产欧美日韩一区二区三区在线| 三上悠亚在线一区二区| 不卡一区二区在线| 国产精品国产精品88| 91成人在线免费观看| 波多野结衣黄色网址| 欧美变态tickling挠脚心| 二人午夜免费观看在线视频| 97久久精品在线| 麻豆免费版在线观看| 91丝袜美腿美女视频网站| 视频国产一区| 国产h视频在线播放| 国产精品996| 亚洲香蕉中文网| 亚洲人成网站精品片在线观看| 久久久久久久久久成人| 亚洲国产精品女人久久久| av大大超碰在线| 成人欧美一区二区三区在线| 精品毛片免费观看| 日本熟妇人妻xxxxx| 久久综合资源网| 日韩免费不卡视频| 精品国产电影一区二区| 日本三级在线观看网站| 91天堂在线观看| 亚洲国产一区二区在线观看| 女同激情久久av久久| 国产精品青草久久| 中文字幕免费高清在线观看| 欧美一区二区福利视频| 精品美女在线观看视频在线观看| 国产成人一区二区三区小说 | 久久99国产精品免费| 少妇视频在线播放| 亚洲精品乱码久久久久久黑人| 国产一级二级三级| 日韩视频在线你懂得| 182tv在线播放| 亚洲最大av网站| 欧美久久一区| 女性生殖扒开酷刑vk| 亚洲第一综合色| 日韩一级免费视频| 欧美一区二区三区免费视| 日韩毛片网站| 亚洲视频电影| 国产在线乱码一区二区三区| 四虎永久免费在线| 日韩美女视频在线| 国产片在线观看| 国产欧美精品在线| 欧美亚洲国产日韩| 宅男一区二区三区| 国产伦精一区二区三区| 国产精品18p| 亚洲男人天堂手机在线| 欧美日韩激情电影| 致1999电视剧免费观看策驰影院| 国产一区二区三区日韩| 久热精品在线观看| 亚洲精品中文字幕有码专区| 久久99久久久精品欧美| 久久久综合亚洲91久久98| 欧美激情91| 精品少妇人妻av一区二区三区| 欧美性猛xxx| 色大18成网站www在线观看| 国产传媒一区二区三区| 久久婷婷亚洲| 日韩高清dvd碟片| 亚洲国产精品99| 久久久久久久性潮| 亚洲理论电影在线观看| 久久久午夜电影| 在线观看黄网站| 色悠悠久久久久| 91国内外精品自在线播放| 女同性恋一区二区| 91在线免费视频观看| 国产又粗又猛又爽又黄的视频一 | 中文日产幕无线码一区二区| 亚洲欧美99| 成人免费高清视频| 在线观看中文字幕码| 久久免费视频网| 99国内精品久久久久久久|