數(shù)據(jù)挖掘入門:從動(dòng)手實(shí)踐開始!
作者:阿水、北航碩士、Datawhale成員
本項(xiàng)目以科大訊飛《智能家居使用場(chǎng)景識(shí)別挑戰(zhàn)賽》為實(shí)踐背景,詳細(xì)講解了數(shù)據(jù)挖掘分類實(shí)踐任務(wù)的解題思路,針對(duì)該項(xiàng)目給出了完整實(shí)踐代碼供大家學(xué)習(xí)實(shí)踐。

項(xiàng)目來源
為了讓用戶切身感受到智能家居產(chǎn)品的智能化和便捷性,每個(gè)代理商均有自己的智能家居體驗(yàn)店和展廳。在智能家居體驗(yàn)過程中,需要針對(duì)展廳類的場(chǎng)景做特殊的場(chǎng)景優(yōu)化。識(shí)別當(dāng)前智能家居產(chǎn)品使用環(huán)境是真實(shí)的家庭還是智能化體驗(yàn)的公共區(qū)域至關(guān)重要。
賽事地址:https://challenge.xfyun.cn/topic/info?type=smart-home-2022&ch=ds22-dw-gy02思路解讀
解題思路
本題的任務(wù)是構(gòu)建一種模型,用于預(yù)測(cè)智能家居產(chǎn)品所處的環(huán)境場(chǎng)景類別。這種類型的任務(wù)是典型的二分類問題(家庭/公共區(qū)域),模型的預(yù)測(cè)輸出為 0 或 1。
機(jī)器學(xué)習(xí)中,關(guān)于分類任務(wù)我們一般會(huì)想到邏輯回歸、決策樹、隨機(jī)森林等算法,在這個(gè) Baseline 中,我們嘗試使用隨機(jī)森林來構(gòu)建我們的模型。我們?cè)诮鉀Q機(jī)器學(xué)習(xí)問題時(shí),一般會(huì)遵循以下流程:

代碼實(shí)現(xiàn)
以下代碼,請(qǐng)?jiān)趈upyter notbook或python編譯器環(huán)境中實(shí)現(xiàn)。
完成實(shí)踐文檔:https://xj15uxcopw.feishu.cn/docx/doxcn1OvgxBzjpx2Ggh2p5umVEh
導(dǎo)入模塊
#安裝相關(guān)依賴庫?如果是windows系統(tǒng),cmd命令框中輸入pip安裝,參考上述環(huán)境配置
#!pip?install?sklearn
#!pip?install?pandas
#!pip?install?numpy
#!pip?install?codecs
#導(dǎo)入庫
#----------------數(shù)據(jù)探索----------------
import?pandas?as?pd
import?numpy?as?np
import?codecs
#----------------核心模型----------------
from?sklearn.ensemble?import?RandomForestClassifier
#----------------忽略報(bào)警----------------
import?warnings
warnings.filterwarnings('ignore')
數(shù)據(jù)預(yù)處理
本次比賽為參賽選手提供了4類數(shù)據(jù):賬號(hào)信息、設(shè)備列表、控制操作日志、設(shè)備上報(bào)日志。其中賬號(hào)基礎(chǔ)數(shù)據(jù)的訓(xùn)練集我們會(huì)打上使用場(chǎng)景是家庭用戶還是體驗(yàn)廳的標(biāo)簽。
比賽賽題是一個(gè)典型的多表建模任務(wù),我們需要考慮:
- 如何對(duì)單張表提取特征
- 如何將多張表特征聚合到一起
數(shù)據(jù)預(yù)處理后會(huì)發(fā)現(xiàn),本賽題數(shù)據(jù)比較干凈,不存在缺失值和異常值。
#?讀取訓(xùn)練數(shù)據(jù)和測(cè)試數(shù)據(jù)
#?由于原始數(shù)據(jù)包含的格式不對(duì),這里自行定義了數(shù)據(jù)讀取
def?robust_readcsv(path,?sep=','):
????try:
????????lines?=?codecs.open(path).readlines()
????except:
????????lines?=?codecs.open(path,?encoding='latin-1').readlines()
????header?=?lines[0].strip().split(sep)
????content?=?[]
????for?line?in?lines[1:]:
????????line?=?line.strip()
????????try:
????????????index?=?[i?for?i,?x?in?enumerate(line)?if?x?==?',']
????????????if?len(index)?==?len(header)?-?1:
????????????????content.append(line.split(sep))
????????????else:
????????????????line_content?=?[]
????????????????index?=?[0]?+?index
????????????????for?idx?in?range(len(header)-1):
????????????????????line_content.append(line[index[idx]:index[idx+1]].strip(sep))
????????????????line_content.append(line[index[len(header)-1]:].strip(sep))
????????????????content.append(line_content)
????????except:
????????????pass
????
????return?pd.DataFrame(content,?columns=header)
#?主表:訓(xùn)練集和測(cè)試集
train_cus?=?pd.read_csv('智能家居使用場(chǎng)景識(shí)別挑戰(zhàn)賽數(shù)據(jù)集/訓(xùn)練集/cus.csv',?sep=',')
test_cus?=?pd.read_csv('智能家居使用場(chǎng)景識(shí)別挑戰(zhàn)賽數(shù)據(jù)集/測(cè)試集/cus.csv',?sep=',')
#?其他表:設(shè)備列表
train_devupdate?=?robust_readcsv('智能家居使用場(chǎng)景識(shí)別挑戰(zhàn)賽數(shù)據(jù)集/訓(xùn)練集/devUpdata.csv',?sep=',')
test_devupdate?=?robust_readcsv('智能家居使用場(chǎng)景識(shí)別挑戰(zhàn)賽數(shù)據(jù)集/測(cè)試集/devUpdata.csv',?sep=',')
#?其他表:操作表
train_control?=?robust_readcsv('智能家居使用場(chǎng)景識(shí)別挑戰(zhàn)賽數(shù)據(jù)集/訓(xùn)練集/control.csv',?sep=',')
test_control?=?robust_readcsv('智能家居使用場(chǎng)景識(shí)別挑戰(zhàn)賽數(shù)據(jù)集/測(cè)試集/control.csv',?sep=',')
#?其他表:設(shè)備更新表
train_devlist?=?robust_readcsv('智能家居使用場(chǎng)景識(shí)別挑戰(zhàn)賽數(shù)據(jù)集/訓(xùn)練集/devList.csv',?sep=',')
test_devlist?=?robust_readcsv('智能家居使用場(chǎng)景識(shí)別挑戰(zhàn)賽數(shù)據(jù)集/測(cè)試集/devList.csv',?sep=',')
#?數(shù)據(jù)集shape信息,快速了解數(shù)據(jù)基本情況
train_cus.shape,?test_cus.shape
train_devupdate.shape,?test_devupdate.shape
train_control.shape,?test_control.shape
train_devlist.shape,?test_devlist.shape
特征工程
將多個(gè)表的字段進(jìn)行合并,然后和主表進(jìn)行merge得到可以訓(xùn)練的數(shù)據(jù)。這里對(duì)單張表的數(shù)據(jù)特征提取可以自行選擇,下面的代碼只進(jìn)行了基礎(chǔ)的數(shù)據(jù)統(tǒng)計(jì)。
#不同數(shù)據(jù)集中以u(píng)id做分組,不同維度唯一值的統(tǒng)計(jì)次數(shù)
train_devupdate_feat?=?train_devupdate.groupby('uid').agg({
????'did':?'nunique',
????'data':?'nunique',
})
train_devupdate_feat.reset_index(inplace=True)
train_devupdate_feat.columns?=?['uid',?'devupdate_did_count',?'devupdate_data_count']
test_devupdate_feat?=?test_devupdate.groupby('uid').agg({
????'did':?'nunique',
????'data':?'nunique',
})
test_devupdate_feat.reset_index(inplace=True)
test_devupdate_feat.columns?=?['uid',?'devupdate_did_count',?'devupdate_data_count']
train_control_feat?=?train_control.groupby('uid').agg({
????'did':?'nunique',
????'form':?'nunique',
????'data':?'nunique',
})
train_control_feat.reset_index(inplace=True)
train_control_feat.columns?=?['uid',?'devcontrol_did_count',?
??????????????????????????????'devcontrol_form_count',?'devcontrol_data_count']
test_control_feat?=?test_control.groupby('uid').agg({
????'did':?'nunique',
????'form':?'nunique',
????'data':?'nunique',
})
test_control_feat.reset_index(inplace=True)
test_control_feat.columns?=?['uid',?'devcontrol_did_count',?
??????????????????????????????'devcontrol_form_count',?'devcontrol_data_count']
train_devlist_feat?=?train_devlist.groupby('uid').agg({
????'did':?'nunique',
????'type':?'nunique',
????'area':?['unique',?'nunique',?'count']
})
train_devlist_feat.reset_index(inplace=True)
train_devlist_feat.columns?=?[x[0]?+?x[1]?for?x?in?train_devlist_feat.columns]
test_devlist_feat?=?test_devlist.groupby('uid').agg({
????'did':?'nunique',
????'type':?'nunique',
????'area':?['unique',?'nunique',?'count']
})
test_devlist_feat.reset_index(inplace=True)
test_devlist_feat.columns?=?[x[0]?+?x[1]?for?x?in?test_devlist_feat.columns]
#所有訓(xùn)練集的表組合為train_feat
train_feat?=?train_cus.merge(train_devlist_feat,?on='uid')
train_feat?=?train_feat.merge(train_control_feat,?on='uid',?how='left')
train_feat?=?train_feat.merge(train_devupdate_feat,?on='uid',?how='left')
train_feat.fillna(0,?inplace=True)
#所有測(cè)試集的表組合為test_feat
test_feat?=?test_cus.merge(test_devlist_feat,?on='uid')
test_feat?=?test_feat.merge(test_control_feat,?on='uid',?how='left')
test_feat?=?test_feat.merge(test_devupdate_feat,?on='uid',?how='left')
test_feat.fillna(0,?inplace=True)
#使用tfidf算法做文本特征提取
from?sklearn.feature_extraction.text?import?TfidfVectorizer
tfidf?=?TfidfVectorizer(max_features=400)
train_dev_tfidf?=?tfidf.fit_transform(train_feat['areaunique'].apply(lambda?x:?'?'.join(x)))
test_dev_tfidf?=?tfidf.transform(test_feat['areaunique'].apply(lambda?x:?'?'.join(x)))
train_dev_tfidf?=?pd.DataFrame(train_dev_tfidf.toarray(),?columns=tfidf.get_feature_names())
test_dev_tfidf?=?pd.DataFrame(test_dev_tfidf.toarray(),?columns=tfidf.get_feature_names())
train_feat?=?pd.concat([train_dev_tfidf,?train_feat],?axis=1)
test_feat?=?pd.concat([test_dev_tfidf,?test_feat],?axis=1)
訓(xùn)練模型
作為基線方案將選擇經(jīng)典的隨機(jī)森林分類器作為模型。
clf?=?RandomForestClssifier()
clf.fit(train_feat.drop(['uid',?'label',?'areaunique'],?axis=1),?train_feat['label'])
test_cus['label']?=?clf.predict(test_feat.drop(['uid','areaunique'],?axis=1),)
結(jié)果保存
test_cus.to_csv('result.csv',?index=None)
整理不易, 點(diǎn) 贊 三連 ↓
