作者 | AJ Gordon
责编 | 李雪敬
出品 | CSDN(ID:CSDNnews)
当你手头有一件搁置的物品时,最好的办法不是放在家里积灰,而是拿到二手网站上进行拍卖,例如淘宝的闲鱼,京东的拍拍等等。有这方面经历的小伙伴都知道,这两个渠道都会主动给出一个最佳的价格。假定我现在有一堆旧手机想二手转让,但又不知道定价多少合当令,最好的办法是上网查查相同装备的二手手机价格后,再进行定价。
京东渠道上有专门的二手手机分类,因而挑选它作为定价参阅。为了便利进行剖析,最省时的办法便是直接把数据都抓取到本地,再进行剖析。下面一同看看如何用程序的办法获取咱们想要的:
数据获取
因为京东的防爬办法,直接用requests去读取链接是不可的,我的抓取办法是这样的:
首要,获取详情页链接前均是选用selenium进行无界面拜访。先获取各手机品牌的ID,再用手机品牌的ID构建二级链接,获取各手机品牌的总页码数Page。再用ID+Page构建三级链接,获取二手手机的详情页链接。最终用requests读取详情页链接,获取详细数据。
# 获取手机类型id
defget_mobile_model_id:
# 浏览器设置
option = webdriver.ChromeOptions
# 防阻拦
option.add_experimental_option( 'excludeSwitches', [ 'enable-automation'])
# 不加载图片
option.add_experimental_option( "prefs", { "profile.managed_default_content_settings.images": 2})
# 无界面
option.add_argument( '--headless')
option.add_argument( '--disable-gpu')
#
browser = webdriver.Chrome(options=option)
browser.get( 'https://list.jd.com/list.html?cat=13765%2C13767')
#获取浏览器当时翻开页面的页面源码数据
page_text = browser.page_source
browser.quit
# 获取手机类型ID
soup = BeautifulSoup(page_text, 'lxml')
model_type = soup.find_all( 'ul',{ 'class': 'J_valueList clearfix'})[ 1].find_all( 'li')
fori inmodel_type:
# 手机类型称号
# type = i.find('a').get_text
# 手机类型id
type_id = i.find( 'a')[ 'href'].split( 'ev=')[ -1].split( '&cid2=')[ 0]
redis_db.sadd( 'jd_mobile_model_id', type_id)
截止至2020年6月22日,一共抓取了2.2万件二手手机产品,27.7万条谈论数据。总体上分为三个部分:产品基本信息,店肆谈论信息和产品谈论信息。
产品基本信息:产品ID,店肆ID,新旧程度,品牌,机型,色彩,内存和单价等等。
店肆谈论信息:店肆ID,好评率,总谈论数,默许好评数和好评数等等。
产品谈论信息:产品ID,用户ID,打分,谈论内容,谈论时刻和下单时刻。
数据 描绘
接下来,对清洗后的数据进行描绘性计算。
图1 日期与出售量的联系
依据前史买家下单时刻,从图1能够看出每年的峰值都是呈现在618,双11,双12这些电商节日,而且每年出售量同比增长了300%。
图2 时刻与出售量的联系
依据前史买家下单时刻,从图2能够看出每天的销量趋势,早上4:00 – 12:00一路飙升,下午12:00 – 16:00坚持陡峭,黄昏16:00 – 19:00有所下降,晚上19:00 – 22:00回到下午水平,22:00 – 4:00逐步下降到最低点。
图3 色彩与销量的联系
依据图3可知,在售的二手手机色彩主要是金色,黑色和银色,而出售出去的色彩主要是金色,黑色和玫瑰金。尽管在售的赤色手机也挺多的,可是销量却很低。
图4 价格与销量的联系
依据图4可知,在售的二手手机价格主要是2000元以下,5000元以上的二手手机也是有不少的。而销量最高的1000元以下的二手手机,价格越高,销量越低。
图5 品牌与销量的联系
从图5能够看出来,京东上的手机品牌有19个。苹果的产品数量和出售量远远超过了其它品牌的总和。国产品牌中主要卖的是华为、小米、OPPO和Vivo。其它牌子的机型产品数量少,出售量就也很少。
图6 各品牌机型销量TOP3
现在二手手机市场上的品牌主要有苹果,OPPO,Vivo,小米,华为和三星,所以能够了解一下每个品牌销量最好的前三名机型别离是什么。苹果主要是iphone 6s、iphone x和iphone 7。华为主要是mate20、p20和p20pro。
图7 差评词云图
图7是将谈论信息中打分分数1和2的归为差评,然后运用jieba分词将文本内容截成若干个词,再用词云图展现。从这个差评词云图能够看出大多数用户对二手手机的不满主要是客服、屏幕和电池这三个原因。首要商家对买家的情绪便是“买前是天主,买后置之脑后”,购买前会很热心地招待,但售后又变成另一副嘴脸。其次,原装屏幕和拼装屏幕的赢利差的是一副二手手机的价格,所以许多二手手机用的都是拼装屏幕,作用天然没有新机好。最终,手机用久了就会呈现电池老化的问题,耗电量特别快,这个也是部分人替换新手机的原因。
数据建模
经过前面的数据获取和数据描绘之后,对二手手机现已大致了解。现在能够开端对这些二手手机数据进行建模,因为现在是需求进行定价,归于回归模型。
1) 导入库和数据
首要,导入需求用到的库和数据。
importpandas aspd
importnumpy asnp
fromscipy.special importboxcox1p,inv_boxcox1p
fromsklearn.preprocessing importMinMaxScaler,StandardScaler,RobustScaler
fromsklearn.model_selection importGridSearchCV,RandomizedSearchCV
fromsklearn.decomposition importPCA
fromsklearn.ensemble importRandomForestRegressor
fromsklearn.metrics importmean_squared_error,r2_score
fromsklearn.metrics importmake_scorer
importseaborn assns
importmatplotlib.pyplot asplt
pd.set_option( 'display.max_columns', None)
pd.set_option( 'display.max_rows', None)
plt.rcParams[ 'font.sans-serif']=[ 'SimHei']
plt.rcParams[ 'axes.unicode_minus'] = False#负号显现
defload_电子游戏网址data:
data = pd.read_csv( 'result.csv',dtype={ 'skuId':str})
data = data[[ 'skuId', 'old_new_degree', 'brand', 'model', 'color', 'version', 'Double_card_machine_type', 'Front_card_machine_type', 'Rear_camera_pixel', 'Battery_capacity', 'Running_memory', 'screen_size', 'price']].drop_duplicates( 'skuId')
returndata
2) 清洗数据对部分字段进行缺失值填充,以及将相似的分类合并为同一个。
def clean_data( data):
# 缺失值填充
data[ 'model'].fillna( 'Missing', inplace=True)
data[ 'color'].fillna( 'Missing', inplace=True)
# 修正字段
data[ 'old_new_degree'] = data.apply(lambda x: str(x[ 'old_new_degree']),axis= 1)
data[ 'version'] = data.apply(lambda x: '0'ifx[ 'version']== 'Missing'elsestr(x[ 'version']),axis= 1)
data[ 'Front_card_machine_type'] = data.apply(lambda x: '0'ifx[ 'Front_card_machine_type']== 'Missing'elsestr(x[ 'Front_card_machine_type'][: 4].replace( '万', '')),axis= 1)
data[ 'Rear_camera_pixel'] = data.apply(lambda x: '0'ifx[ 'Rear_camera_pixel']== 'Missing'elsestr(x[ 'Rear_camera_pixel'][: 4].replace( '万', '')),axis= 1)
data[ 'Battery_capacity'] = data.apply(lambda x: '0'ifx[ 'Battery_capacity']== 'Missing'elsestr(x[ 'Battery_capacity']),axis= 1)
data[ 'Running_memory'] = data.apply(lambda x: '0'ifx[ 'Running_memory']== 'Missing'elsestr(x[ 'Running_memory'].replace( 'GB', '')),axis= 1)
data[ 'screen_size'] = data.apply(lambda x: '0'ifx[ 'screen_size']== 'Missing'elsestr(x[ 'screen_size'].replace( '英寸', '')),axis= 1)
returndata
3) 离散变量-独热编码离散变量分为有序和无序两种变量,例如手机的内存越高越好,归于有序离散变量。 色彩归于无序离散变量。这儿我都是用pandas自带的get_dummy进行独热编码,sklearn也有一个独热编码OnehotEncoder,两者的差异在于get_dummy无法适用于新类别,而且每次都要从头履行,只适用于数据量小的模型。
defget_dummy(df):
cols = [ 'version', 'Front_card_machine_type', 'Rear_camera_pixel', 'Battery_capacity', 'Running_memory', 'screen_size', 'old_new_degree', 'brand', 'model', 'color', 'Double_card_machine_type']
dummy_cols = df[cols].copy
df = df.drop(cols,axis= 1)
dummy_cols = pd.get_dummies(dummy_cols,prefix=cols)
df = pd.concat([df,dummy_cols],axis= 1)
returndf
4) 拆分数据将原始数据集拆分红两部分: 练习集和测验集(后100条),因为回归模型要求标签满意正态分布,所以对练习集的标签进行boxcox1p正态改换,使其满意正态分布。
defcut_data(df):
# 拆分数据
all_rows = df.shape[ 0]
## 练习集
X_train = df[ :all_rows-100]
y_train = X_train[ 'price'].copy
y_train = boxcox1p(y_train, 0)
X_train = X_train.drop([ 'skuId', 'price'],axis= 1)
## 测验集
X_test = df[all_rows- 100:]
y_test = X_test[[ 'skuId', 'price']].copy
X_test = X_test.drop([ 'skuId', 'price'],axis= 1)
returnX_train,y_train,X_test,y_test
5) 数据降维因为独热编码后的特征会添加 许多,所以需求进行降维。
defvalue_pca(X_train,X_test):
pca = PCA(n_components= 0.9)
X_train = pca.fit_transform(X_train)
X_test = pca.transform(X_test)
#variance = pd.DataFrame(pca.explained_variance_ratio_)
#np.cumsum(pca.explained_variance_ratio_)
returnX_train,X_test
6) 数据建模
将特征都处理好之后,就能够套用模型了,这儿我用随机森林回归模型。 而且用GridSearchCV网格查找,自定义RMSE作为其判别规范。最终用最佳参数进行猜测,并用R2比较实在值和猜测值的作用,R2越挨近1作用越好,这次的模型R2值是0.912。
defmodel(X_train,y_train,X_test,y_test):
# 设置自定义评分函数
defmy_custom_loss_func(y_true, y_pred):
returnnp.sqrt(mean_squared_error(y_true, y_pred))
rmse = make_scorer(my_custom_loss_func, greater_is_better= False) # 以_error结束的函数,回来一个最小值,越小越好;假如运用make_scorer来创立scorer时,将greater_is_better设为False
# 设置自定义参数
rfr_param_test = {
'n_estimators': [ 10, 20, 30, 40, 50, 60],
'max_depth': [ 5, 6, 7, 8, 9, 10]}
# 进行网格查找
grid_search = GridSearchCV(estimator=RandomForestRegressor, param_grid=rfr_param_test, cv= 5, scoring=rmse)
grid_search.fit(X_train,y_train)
print(grid_search.best_params_)
# 猜测成果
rft_model = grid_search.best_estimator_
rft_model.fit(X_train, y_train)
y_pred = rft_model.predict(X_test)
y_pred = inv_boxcox1p(y_pred, 0)
# 输出R2值
R2 = r2_score(y_test[ 'price'], y_pred)
print( 'R2:{}'.format(R2))
# 输出成果
result = pd.DataFrame({
'skuID':y_test[ 'skuID'],
'price_old':y_test[ 'price'],
'price_pred':y_pred})
result.to_csv( 'Regress_result.csv',index= False,encoding= 'utf_8_sig')
returnresult
总结
经过上述剖析,我发现现在二手手机市场上,最畅销的是 iphone,尽管国产机近几年的知名度越来越高,可是店家或许顾客都更倾向于iphone。此外,二手手机的价格越低,销量就会越高。但廉价所带来的坏处便是店家的售后差,屏幕作用欠安,电池损耗快等等。当你有二手手机转让的需求时,用数据建模的办法,也能为你供给一个定价的规范。回来,检查更多
责任编辑: