摘要:然而隨機(jī)投放的優(yōu)惠券對(duì)多數(shù)用戶(hù)造成無(wú)意義的干擾。下面我們分別對(duì)訓(xùn)練集中的類(lèi)數(shù)據(jù)對(duì)優(yōu)惠券使用的影響進(jìn)行分析。在里有兩種折扣方法代表折扣率表示滿(mǎn)減。這里我們還要將滿(mǎn)減類(lèi)型用式子轉(zhuǎn)換成折扣率。進(jìn)行預(yù)測(cè)計(jì)算平均得到結(jié)果。
賽題說(shuō)明
應(yīng)用背景:以?xún)?yōu)惠券盤(pán)活老用戶(hù)或吸引新客戶(hù)進(jìn)店消費(fèi)是O2O(Online to Offline)的一種重要營(yíng)銷(xiāo)方式。然而隨機(jī)投放的優(yōu)惠券對(duì)多數(shù)用戶(hù)造成無(wú)意義的干擾。對(duì)商家而言,濫發(fā)的優(yōu)惠券可能降低品牌聲譽(yù),同時(shí)難以估算營(yíng)銷(xiāo)成本。而個(gè)性化投放是提高優(yōu)惠券核銷(xiāo)率的重要技術(shù),它可以讓具有一定偏好的消費(fèi)者得到真正的實(shí)惠,同時(shí)賦予商家更強(qiáng)的營(yíng)銷(xiāo)能力。
目標(biāo):根據(jù)提供的O2O場(chǎng)景相關(guān)的豐富數(shù)據(jù),通過(guò)分析建模,精準(zhǔn)預(yù)測(cè)用戶(hù)是否會(huì)在規(guī)定時(shí)間內(nèi)使用相應(yīng)優(yōu)惠券。
讀取數(shù)據(jù):
我們看到在 offline 訓(xùn)練數(shù)據(jù)集中有以下 7 類(lèi)數(shù)據(jù):
User_id
Merchant_id
Coupon_id
Discount_rate
Distance
Date_received
Date
當(dāng) Coupon_id 為 null 時(shí)表示無(wú)優(yōu)惠券消費(fèi),此時(shí)Discount_rate和Date_received字段無(wú)意義。
具體字段意義請(qǐng)參考賽題鏈接。
根據(jù) Coupon_id 和 Date 是否為 null,可以將數(shù)據(jù)分為四種類(lèi)型:
print("有優(yōu)惠券,購(gòu)買(mǎi)商品條數(shù)", dfoff[(dfoff["Coupon_id"] != "null") & (dfoff["Date"] != "null")].shape[0]) print("無(wú)優(yōu)惠券,購(gòu)買(mǎi)商品條數(shù)", dfoff[(dfoff["Coupon_id"] == "null") & (dfoff["Date"] != "null")].shape[0]) print("有優(yōu)惠券,沒(méi)有購(gòu)買(mǎi)商品條數(shù)", dfoff[(dfoff["Coupon_id"] != "null") & (dfoff["Date"] == "null")].shape[0]) print("無(wú)優(yōu)惠券,也沒(méi)有購(gòu)買(mǎi)商品條數(shù)", dfoff[(dfoff["Coupon_id"] == "null") & (dfoff["Date"] == "null")].shape[0])
得到結(jié)果:
其中,75382 表示用優(yōu)惠券進(jìn)行了消費(fèi)的數(shù)量,即正樣本;977900 表示領(lǐng)取優(yōu)惠券但沒(méi)有使用,這部分優(yōu)惠券就被浪費(fèi)了,即負(fù)樣本;701602 表示沒(méi)有優(yōu)惠券的普通消費(fèi)。
下面我們分別對(duì)訓(xùn)練集中的 7 類(lèi)數(shù)據(jù)對(duì)優(yōu)惠券使用的影響進(jìn)行分析。
1. 優(yōu)惠券和距離
print("Discount_rate 類(lèi)型:",dfoff["Discount_rate"].unique()) print("Distance 類(lèi)型:", dfoff["Distance"].unique())
我們看到輸出的是str類(lèi)型的數(shù)據(jù),需要將它們轉(zhuǎn)換成numeric類(lèi)型。
在Discount_rate里有兩種折扣方法:x in [0,1] 代表折扣率;x : y 表示滿(mǎn) x 減 y。這里我們還要將滿(mǎn) x 減 y 類(lèi)型用式子1-y/x轉(zhuǎn)換成折扣率。并建立折扣券相關(guān)的特征 discount_rate, discount_man, discount_jian, discount_type。代碼如下:
# convert Discount_rate and Distance def getDiscountType(row): if row == "null": return "null" elif ":" in row: return 1 else: return 0 def convertRate(row): """Convert discount to rate""" if row == "null": return 1.0 elif ":" in row: rows = row.split(":") return 1.0 - float(rows[1])/float(rows[0]) else: return float(row) def getDiscountMan(row): if ":" in row: rows = row.split(":") return int(rows[0]) else: return 0 def getDiscountJian(row): if ":" in row: rows = row.split(":") return int(rows[1]) else: return 0 def processData(df): # convert discunt_rate df["discount_rate"] = df["Discount_rate"].apply(convertRate) df["discount_man"] = df["Discount_rate"].apply(getDiscountMan) df["discount_jian"] = df["Discount_rate"].apply(getDiscountJian) df["discount_type"] = df["Discount_rate"].apply(getDiscountType) print(df["discount_rate"].unique()) # convert distance df["distance"] = df["Distance"].replace("null", -1).astype(int) print(df["distance"].unique()) return df dfoff = processData(dfoff) dftest = processData(dftest)
2. 時(shí)間
對(duì)收到優(yōu)惠券的日期date_received和消費(fèi)日期date_buy進(jìn)行處理:
date_received = dfoff["Date_received"].unique() date_received = sorted(date_received[date_received != "null"]) date_buy = dfoff["Date"].unique() date_buy = sorted(date_buy[date_buy != "null"]) date_buy = sorted(dfoff[dfoff["Date"] != "null"]["Date"])
并輸出結(jié)果:
查看顧客每天收到的優(yōu)惠券數(shù)量:
couponbydate = dfoff[dfoff["Date_received"] != "null"][["Date_received", "Date"]].groupby(["Date_received"], as_index=False).count() couponbydate.columns = ["Date_received","count"] couponbydate.head()
查看顧客用這些優(yōu)惠券進(jìn)行了消費(fèi)的數(shù)量:
buybydate = dfoff[(dfoff["Date"] != "null") & (dfoff["Date_received"] != "null")][["Date_received", "Date"]].groupby(["Date_received"], as_index=False).count() buybydate.columns = ["Date_received","count"] buybydate.head()
將以上數(shù)據(jù)可視化:
plt.figure(figsize = (12,8)) date_received_dt = pd.to_datetime(date_received, format="%Y%m%d") plt.subplot(211) plt.bar(date_received_dt, couponbydate["count"], label = "number of coupon received" ) plt.bar(date_received_dt, buybydate["count"], label = "number of coupon used") plt.yscale("log") plt.ylabel("Count") plt.legend() plt.subplot(212) plt.bar(date_received_dt, buybydate["count"]/couponbydate["count"]) plt.ylabel("Ratio(coupon used/coupon received)") plt.tight_layout()提取特征
上面顯示的是多帶帶一天的數(shù)據(jù)量,我們知道人們一般在星期天上街比較多,使用優(yōu)惠券的可能性也增大,所以現(xiàn)在我們以星期為依據(jù)新建特征。
def getWeekday(row): if row == "null": return row else: return date(int(row[0:4]), int(row[4:6]), int(row[6:8])).weekday() + 1 dfoff["weekday"] = dfoff["Date_received"].astype(str).apply(getWeekday) dftest["weekday"] = dftest["Date_received"].astype(str).apply(getWeekday) # weekday_type : 周六和周日為1,工作日為0 dfoff["weekday_type"] = dfoff["weekday"].apply(lambda x : 1 if x in [6,7] else 0 ) dftest["weekday_type"] = dftest["weekday"].apply(lambda x : 1 if x in [6,7] else 0 ) # change weekday to one-hot encoding weekdaycols = ["weekday_" + str(i) for i in range(1,8)] print(weekdaycols) tmpdf = pd.get_dummies(dfoff["weekday"].replace("null", np.nan)) tmpdf.columns = weekdaycols dfoff[weekdaycols] = tmpdf tmpdf = pd.get_dummies(dftest["weekday"].replace("null", np.nan)) tmpdf.columns = weekdaycols dftest[weekdaycols] = tmpdf
得到的tmpdf為以下形式:
對(duì)["date_received"]數(shù)據(jù)進(jìn)行標(biāo)注,轉(zhuǎn)換成numeric:
def label(row): if row["Date_received"] == "null": return -1 if row["Date"] != "null": td = pd.to_datetime(row["Date"], format="%Y%m%d") - pd.to_datetime(row["Date_received"], format="%Y%m%d") if td <= pd.Timedelta(15, "D"): return 1 return 0 dfoff["label"] = dfoff.apply(label, axis = 1)
若 Date_received == "null",則 y = -1;Date != "null" & Date-Date_received <= 15,則 y = 1;否則,y = 0。
此時(shí),這些轉(zhuǎn)換后的數(shù)據(jù)已經(jīng)以0,1,-1的形式存在了label列中。
模型訓(xùn)練在應(yīng)用模型前,首先對(duì)數(shù)據(jù)進(jìn)行劃分。在這里,我們將 20160101 到 20160515 的數(shù)據(jù)用作訓(xùn)練集(train),20160516 到 20160615 的數(shù)據(jù)用作驗(yàn)證集(valid)。
df = dfoff[dfoff["label"] != -1].copy() train = df[(df["Date_received"] < "20160516")].copy() valid = df[(df["Date_received"] >= "20160516") & (df["Date_received"] <= "20160615")].copy() print(train["label"].value_counts()) print(valid["label"].value_counts())
用線(xiàn)性模型 SGDClassifier 進(jìn)行預(yù)測(cè)。
predictors = original_feature print(predictors) def check_model(data, predictors): classifier = lambda: SGDClassifier( loss="log", penalty="elasticnet", fit_intercept=True, max_iter=100, shuffle=True, n_jobs=1, class_weight=None) model = Pipeline(steps=[ ("ss", StandardScaler()), ("en", classifier()) ]) parameters = { "en__alpha": [ 0.001, 0.01, 0.1], "en__l1_ratio": [ 0.001, 0.01, 0.1] } folder = StratifiedKFold(n_splits=3, shuffle=True) grid_search = GridSearchCV( model, parameters, cv=folder, n_jobs=-1, verbose=1) grid_search = grid_search.fit(data[predictors], data["label"]) return grid_search if not os.path.isfile("1_model.pkl"): model = check_model(train, predictors) print(model.best_score_) print(model.best_params_) with open("1_model.pkl", "wb") as f: pickle.dump(model, f) else: with open("1_model.pkl", "rb") as f: model = pickle.load(f)
接下來(lái),對(duì)每個(gè)優(yōu)惠券預(yù)測(cè)的結(jié)果計(jì)算 AUC,再對(duì)所有的取平均。計(jì)算 AUC 的時(shí)候,如果label只有一類(lèi),就直接跳過(guò),因?yàn)?AUC 無(wú)法計(jì)算。
進(jìn)行預(yù)測(cè):
y_valid_pred = model.predict_proba(valid[predictors]) valid1 = valid.copy() valid1["pred_prob"] = y_valid_pred[:, 1]
計(jì)算平均 AUC:
vg = valid1.groupby(["Coupon_id"]) aucs = [] for i in vg: tmpdf = i[1] if len(tmpdf["label"].unique()) != 2: continue fpr, tpr, thresholds = roc_curve(tmpdf["label"], tmpdf["pred_prob"], pos_label=1) aucs.append(auc(fpr, tpr)) print(np.average(aucs))
得到結(jié)果0.5348655160896371。
對(duì)測(cè)試集進(jìn)行預(yù)測(cè)并提交結(jié)果:
y_test_pred = model.predict_proba(dftest[predictors]) dftest1 = dftest[["User_id","Coupon_id","Date_received"]].copy() dftest1["label"] = y_test_pred[:,1] dftest1.to_csv("submit1.csv", index=False, header=False)
至此,我們已經(jīng)得到一個(gè)提交結(jié)果,在這個(gè)過(guò)程中用到的特征是優(yōu)惠券,距離和時(shí)間。預(yù)測(cè)效果較差,還需要進(jìn)行進(jìn)一步的特征工程,來(lái)得到更好的效果。
思路解答總結(jié)以上思路,首先對(duì)數(shù)據(jù)進(jìn)行分析,通過(guò)畫(huà)圖可以更直觀的反映出數(shù)據(jù)的特征;然后根據(jù)對(duì)數(shù)據(jù)對(duì)分析結(jié)果,進(jìn)行特征提取,用這些特征訓(xùn)練所用的模型。在訓(xùn)練過(guò)程中通過(guò)劃分?jǐn)?shù)據(jù)集,分為訓(xùn)練集和驗(yàn)證集兩部分,對(duì)模型進(jìn)行訓(xùn)練;最后,將測(cè)試集的數(shù)據(jù)喂給訓(xùn)練好的模型,得到預(yù)測(cè)結(jié)果,并轉(zhuǎn)換為能提交的.csv格式的文件。
這就是進(jìn)行一次數(shù)據(jù)分析的大致思路,就本題來(lái)說(shuō),在特征工程和模型的選擇上還有更多的思考余地,來(lái)提高準(zhǔn)確率。
用到的知識(shí)點(diǎn)one-hot encoding
AUC
針對(duì)博主的學(xué)習(xí),在這次的賽題總結(jié)中反映出的問(wèn)題有以下 3 點(diǎn):
數(shù)據(jù)可視化的代碼部分,不夠了解,而畫(huà)圖可能為我們提供很多思路
對(duì)各個(gè)模型的參數(shù)有哪些需要深入了解,如果不想做調(diào)包俠客,就更要掌握調(diào)參背后的原理
特征工程是制勝的關(guān)鍵,需要不斷的練習(xí)學(xué)習(xí)
參考鏈接:
https://tianchi.aliyun.com/no...
https://tianchi.aliyun.com/no...
不足之處,歡迎指正。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/41879.html
摘要:這次比賽的題目是給定年月份的用戶(hù)在不同地點(diǎn)口碑購(gòu)買(mǎi)記錄,以及年月淘寶上用戶(hù)的購(gòu)物行為數(shù)據(jù),來(lái)預(yù)測(cè)月這一整月用戶(hù)來(lái)到一個(gè)地點(diǎn)之后會(huì)光顧哪些口碑商鋪。 一直想總結(jié)一下這次的比賽,拖啊拖。。。一直等到現(xiàn)在,趁著現(xiàn)在要找實(shí)習(xí),好好總結(jié)一下。 比賽題目 比賽的官方網(wǎng)站在這,IJCAI SocInf16。 這次比賽的題目是給定 2015 年 7 ~ 11 月份的用戶(hù)在不同地點(diǎn)口碑購(gòu)買(mǎi)記錄,以及 2...
摘要:內(nèi)容來(lái)自,人工智能數(shù)據(jù)科學(xué)比賽整理平臺(tái)。消費(fèi)者人群畫(huà)像信用智能評(píng)分月日月中國(guó)移動(dòng)福建公司提供年月份的樣本數(shù)據(jù)脫敏,包括客戶(hù)的各類(lèi)通信支出欠費(fèi)情況出行情況消費(fèi)場(chǎng)所社交個(gè)人興趣等豐富的多維度數(shù)據(jù)。 內(nèi)容來(lái)自 DataSciComp,人工智能/數(shù)據(jù)科學(xué)比賽整理平臺(tái)。Github:iphysresearch/DataSciComp 本項(xiàng)目由 ApacheCN 強(qiáng)力支持。 微博 | 知乎 | C...
摘要:內(nèi)容來(lái)自,人工智能數(shù)據(jù)科學(xué)比賽整理平臺(tái)。本項(xiàng)目由強(qiáng)力支持。天池閱讀更多 內(nèi)容來(lái)自 DataSciComp,人工智能/數(shù)據(jù)科學(xué)比賽整理平臺(tái)。Github:iphysresearch/DataSciComp 本項(xiàng)目由 ApacheCN 強(qiáng)力支持。 微博 | 知乎 | CSDN | 簡(jiǎn)書(shū) | OSChina | 博客園 全球城市計(jì)算AI挑戰(zhàn)賽 3月19日 - 4月11日, 2019 // ...
閱讀 3579·2023-04-26 02:05
閱讀 2024·2021-11-19 11:30
閱讀 4236·2021-09-30 09:59
閱讀 3190·2021-09-10 10:51
閱讀 2615·2021-09-01 10:30
閱讀 1501·2021-08-11 11:20
閱讀 2629·2019-08-30 15:54
閱讀 575·2019-08-30 10:49