精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

最近2019年手机中文字幕| 色哟哟亚洲精品| 国产精品一区二区三区不卡 | 91精品久久久久久久蜜月| 日韩欧美国产三级电影视频| 日本福利视频在线| 日本免费视频在线观看| 国产99久久久国产精品| 国产不卡av在线免费观看| 中文字幕av播放| 亚洲免费福利一区| 欧美一级片免费看| 精品www久久久久奶水| 97caopron在线视频| 久久网这里都是精品| 7777精品伊久久久大香线蕉语言| 国产精品久久久久久久久久久久久久久久久 | 久做在线视频免费观看| 91偷拍与自偷拍精品| 91免费人成网站在线观看18| 久久久久久在线观看| 欧美精品一级| 久久深夜福利免费观看| 国产黄色网址在线观看| 一区二区中文字幕在线观看| 欧美片网站yy| 白嫩少妇丰满一区二区| 久久不射影院| 亚洲欧洲日韩在线| 色之综合天天综合色天天棕色 | 成人黄色理论片| 色天使色偷偷av一区二区| 国产日本在线播放| 超碰在线观看免费版| 国产精品午夜在线观看| 老牛影视免费一区二区| 亚洲精品国产av| 狠狠网亚洲精品| 国产日韩精品在线播放| 久草热在线观看| 久久激情久久| 茄子视频成人在线| 制服.丝袜.亚洲.中文.综合懂色| 欧美午夜在线| 久久999免费视频| 国产一二三四区| 欧美成人milf| 中文字幕日韩综合av| 精品人妻无码一区| 国产伦精品一区二区三区视频| 亚洲精品乱码久久久久久按摩观| 精品久久久久久无码人妻| 日本精品在线播放| 日韩一级片网站| 韩国三级在线看| 亚洲国产aⅴ精品一区二区| 欧美一区二区视频免费观看| 亚洲理论中文字幕| 天堂va在线高清一区| 精品久久久久久无| yy6080午夜| 国产91一区| 国产亚洲欧洲高清| 欧美激情久久久久久久| 偷拍欧美精品| 欧美高清视频在线| 国产奶水涨喷在线播放| 亚洲专区免费| 国产精品一区二区久久久| 国产精品久久免费| 国产成人亚洲综合a∨婷婷图片| 91成人在线看| 亚洲欧洲综合在线| 日本一区二区动态图| 亚洲 欧洲 日韩| 欧洲在线视频| 色综合色狠狠天天综合色| 91色国产在线| 欧美日韩中出| 亚洲精品资源在线| 成人精品一二三区| 午夜日韩在线| 日本老师69xxx| 国产精品久久欧美久久一区| 成人h动漫精品| 日本视频精品一区| 国产精品久久久久久福利| 一区二区三区在线看| 成人综合视频在线| 久久久加勒比| 精品捆绑美女sm三区| 亚洲黄色小说视频| 欧美黄色一区二区| 国产成人精品一区| 国产精品久久久久久免费免熟| 成人免费不卡视频| 婷婷久久五月天| 肉肉视频在线观看| 欧美性xxxxxx少妇| 熟妇高潮一区二区| 色综合咪咪久久网| 97国产一区二区精品久久呦| 中文字幕理论片| 成人精品国产福利| 亚洲精品一区二区三区av| 蜜桃传媒在线观看免费进入 | 欧美日韩一区二区综合| 另类视频在线观看| 波多野结衣在线观看视频| 国产高清久久久久| 亚洲一区二区三区免费看| av在线加勒比| 欧美一级在线观看| 亚洲一二三精品| 性色一区二区| 国产99午夜精品一区二区三区| 搞黄视频免费在线观看| 午夜精品一区在线观看| 国产欧美精品一二三| 精品视频久久| 国产999精品久久久| 亚洲欧美另类综合| 亚洲色图制服丝袜| 欧美一级特黄a| 日韩在线麻豆| 久久免费视频在线| 国产夫妻性生活视频| 国产精品五月天| 欧洲av无码放荡人妇网站| 国内自拍欧美| 欧美激情xxxxx| 国产三级午夜理伦三级| 中文欧美字幕免费| 蜜臀视频一区二区三区| 婷婷综合一区| 欧美在线视频播放| 婷婷久久久久久| 亚洲第一综合色| 欧美熟妇另类久久久久久多毛| 无码一区二区三区视频| 国产精品一区二区三| porn亚洲| 欧美另类高清zo欧美| 国产又黄又粗又猛又爽的| 日韩高清在线一区| 日本不卡在线观看| 蜜桃精品在线| 最近2019年日本中文免费字幕| 男操女视频网站| 国产亚洲综合av| youjizzxxxx18| 操欧美老女人| 91精品国产综合久久香蕉922| 婷婷激情在线| 日韩一二三区不卡| 国产亚洲精品av| 成人v精品蜜桃久久一区| jizzjizz国产精品喷水| 先锋影音国产精品| 国产91热爆ts人妖在线| 成人高清网站| 7777女厕盗摄久久久| 懂色av懂色av粉嫩av| 国产aⅴ精品一区二区三区色成熟| 毛片在线视频观看| 国产精品中文字幕制服诱惑| 51久久精品夜色国产麻豆| 欧美色图另类| 欧美日韩免费一区二区三区| 国产中文av在线| 国产高清不卡一区| 日韩欧美一区三区| 欧美精品乱码| 亚洲一区亚洲二区亚洲三区| 国精一区二区三区| 精品视频偷偷看在线观看| 91丨九色丨海角社区| 亚洲欧美一区二区不卡| 国产精品成人99一区无码 | 毛片免费在线播放| 欧美日韩国产在线观看| 免费一级黄色大片| 99久久99久久综合| 日本高清久久久| 亚洲天堂黄色| 日韩国产美国| 亚洲精品一二三**| 日韩av成人在线| 91麻豆免费在线视频| 日韩精品视频在线免费观看| 一级成人免费视频| 亚洲成a人片在线观看中文| xxxxx99| 成人一道本在线| xx欧美撒尿嘘撒尿xx| 影音先锋一区| 一区二区三区av| 日本一区福利在线| 成人欧美一区二区三区黑人| 男人天堂视频在线观看| 尤物精品国产第一福利三区| 蜜臀av午夜精品| 欧美老人xxxx18| 国产免费一级视频| 亚洲高清视频中文字幕| 国精产品久拍自产在线网站| 91视频一区二区三区| 日本在线视频播放| 蜜桃视频一区二区| 日日摸日日碰夜夜爽av| 午夜激情一区| 中文字幕在线亚洲三区| 你懂的一区二区三区| 国产一级特黄a大片99| 亚洲精品大片| 国产精品久在线观看| av资源网在线播放| 欧美成人免费全部| 日本高清视频在线观看| 亚洲欧美福利视频| 午夜国产在线视频| 日韩女优av电影在线观看| 中文字幕在线视频免费| 一本久道久久综合中文字幕| 日本一区二区网站| 亚洲综合999| 亚洲av无码一区二区三区在线| 欧美激情一区二区三区全黄| 蜜桃传媒一区二区亚洲av| 成人18视频在线播放| 国产免费无码一区二区| 国产乱人伦精品一区二区在线观看 | a级影片在线| 日韩在线免费观看视频| 第一页在线观看| 国产一区二区日韩| 黄色电影免费在线看| 国产视频在线一区二区| 天天摸天天碰天天爽天天弄| 精品成人a区在线观看| 亚洲黄色一级大片| 日韩欧美国产精品| 成人h动漫精品一区二区无码| 91精品国产色综合久久不卡电影| 91av国产精品| 91精品国产欧美一区二区18| 国产精品无码天天爽视频| 欧美高清你懂得| 亚洲在线免费观看视频| 91精品国产综合久久精品性色| 97精品久久人人爽人人爽| 91精品欧美福利在线观看| 国产美女主播在线观看| 日韩欧美成人激情| 日韩中文字幕免费观看| 日韩经典中文字幕| 黄色av网站在线| 中文字幕日韩欧美在线视频| 免费av在线网址| 欧美黑人性生活视频| 蜜桃视频在线观看免费视频| 日本亚洲欧洲色α| 成人日韩av| 91手机视频在线观看| 亚洲精品一区二区三区在线| 黄色小网站91| 精品久久视频| 黄色网址在线免费看| 欧美日韩影院| 成人黄色片视频| 免费精品视频最新在线| 久久精品无码一区二区三区毛片| 成人精品视频.| 日本性高潮视频| 亚洲欧美区自拍先锋| 日本中文字幕在线免费观看| 91福利国产精品| www.超碰在线.com| 亚洲欧美精品一区| huan性巨大欧美| 欧美一级视频免费在线观看| 青青草国产一区二区三区| 超碰97人人人人人蜜桃| 精品久久成人| 久青草视频在线播放| 日韩电影在线观看网站| 黑人巨大猛交丰满少妇| 国产日韩欧美一区二区三区综合| 无码黑人精品一区二区| 好吊成人免视频| 精品国产av一区二区| 亚洲伦理中文字幕| 成人看片免费| 国产精品 欧美在线| 日本免费精品| 亚洲 国产 日韩 综合一区| 亚洲成人中文| 亚洲精品国产一区二区三区| 久久久一区二区| 久久久国产精品黄毛片| 欧美影片第一页| 四虎影视精品成人| 蜜月aⅴ免费一区二区三区| 免费成人美女女| 国产精品美女久久久久av福利| 欧美色蜜桃97| 91九色在线观看视频| 国产成人综合亚洲91猫咪| 欧日韩不卡视频| 日韩欧美一区二区在线| 性少妇videosexfreexxx片| 在线不卡国产精品| 少妇视频在线观看| 91文字幕巨乱亚洲香蕉| 性欧美欧美巨大69| 我看黄色一级片| 91色综合久久久久婷婷| 久久国产精品二区| 制服丝袜在线91| 国产爆初菊在线观看免费视频网站| 午夜精品久久久久久久99黑人| 精品一区视频| 国产高清免费在线| 另类小说综合欧美亚洲| 中文字幕人妻一区二区三区在线视频| 亚洲国产欧美另类丝袜| 精品国产av 无码一区二区三区| 在线日韩第一页| 日日av拍夜夜添久久免费| 麻豆传媒一区二区| 在线视频免费在线观看一区二区| 久久久久久久久久久久国产精品| ㊣最新国产の精品bt伙计久久| 亚洲天堂国产精品| 在线电影欧美日韩一区二区私密| 亚洲精品mv| 狼狼综合久久久久综合网| 国产农村妇女精品一二区| 精品无码国产一区二区三区51安| 亚洲国产另类av| 欧美一级片免费| 性欧美在线看片a免费观看| 精品国产午夜肉伦伦影院| 国产九九九九九| 91婷婷韩国欧美一区二区| 六月丁香婷婷综合| 亚洲欧美国产另类| 日韩电影免费观| 日韩色妇久久av| 久久99国产精品免费| 日韩av网站在线播放| 欧美高清激情brazzers| 成人免费视屏| 国产精品久久7| 国产精品毛片| 亚洲欧美va天堂人熟伦| 欧美日韩一区成人| 中文字幕在线观看网站| 国产成人看片| 性欧美videos另类喷潮| 男人的天堂官网| 91精品婷婷国产综合久久性色 | 色综合久久久久综合99| 青青草娱乐在线| 国产精品一区二区女厕厕| 亚洲天天综合| 精品人妻一区二区三区日产| 欧美日在线观看| 欧美性videos| 国产精品免费一区二区三区观看| 一区二区三区四区五区精品视频| 国产精品免费无码| 欧美精品久久一区| 成人av影院在线观看| 欧美精品一区二区三区久久| 男女激情视频一区| 亚洲人与黑人屁股眼交| 亚洲国产欧美在线成人app | 一本色道久久综合| 级毛片内射视频| 欧美一区二区视频在线观看2020 | 欧美日韩精品综合| 久久成人免费日本黄色| 国产精品第九页| 这里只有精品在线播放| 91蝌蚪精品视频| 黄色在线视频网| 亚洲成人av一区二区| 午夜视频在线| 鲁鲁视频www一区二区| 精东粉嫩av免费一区二区三区| www.av视频在线观看| 中文字幕一精品亚洲无线一区| 国产精品18hdxxxⅹ在线| 成人性生生活性生交12| 亚洲国产精品久久人人爱蜜臀| 成人免费在线视频网| 精品国产综合| 国产精品影视在线观看| 国产偷人爽久久久久久老妇app|