原数据包含:

['ID', '位置', '出租方式', '区', '卧室数量', '卫的数量', '厅的数量', '地铁站点', '地铁线路', '小区名', '小区房屋出租数量', '居住状态', '总楼层', '房屋朝向', '房屋面积', '时间', '楼层', '装修情况', '距离','Label']

图片1.png

清洗数据源码:
借鉴:

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

#1 熟悉数据集
train = pd.read_csv('train.csv')
train.head()
train.info()
print('\n---------分割线----------\n')

#2 查看缺失值
all_data_na = (train.isnull().sum()/len(train))*100
all_data_na=all_data_na.drop(all_data_na[all_data_na ==0].index).sort_values(ascending=False)
missing_data = pd.DataFrame({'数据缺失率' : all_data_na})
print(missing_data)

plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False

fig, axis = plt.subplots(figsize=(8,5))
plt.xticks(rotation='45')
sns.barplot(x=all_data_na.index, y=all_data_na)
plt.xlabel('Features', fontsize=10)
plt.ylabel('Percent of missing values', fontsize=10)
plt.title('Percent missing data by feature', fontsize=10)
# plt.show()

#3 删除缺失值过多的
train.drop(['装修情况','居住状态','出租方式'],axis=1,inplace=True)
# all_data_na = (train.isnull().sum()/len(train))*100
# all_data_na=all_data_na.drop(all_data_na[all_data_na ==0].index).sort_values(ascending=False)
# missing_data = pd.DataFrame({'数据缺失率' : all_data_na})
# print(missing_data)


#4 查看各特征之间的相关关系
#热力图
colnmns = train.columns.tolist()# 列表头
mcorr = train[colnmns].corr()  # 相关系数矩阵,即给出了任意两个变量之间的相关系数
mask = np.zeros_like(mcorr, dtype=np.bool)  # 构造与mcorr同维数矩阵 为bool型
mask[np.triu_indices_from(mask)] = True  # 角分线右侧为True
plt.figure(figsize=(10, 6))  # 指定绘图对象宽度和高度
cmap = sns.diverging_palette(220, 10, as_cmap=True)  # 返回matplotlib colormap对象
g = sns.heatmap(mcorr, mask=mask, cmap=cmap, square=False, annot=True, fmt='0.2f')  # 热力图(看两两相似度)
plt.show()
# #
# 根据热力度,发现房屋面积、卧室数量、厅的数量、卫的数量与月租金的相关系数较大
# 其次是总楼层、区、地铁线路。其他特征的相关系数则较小。因此,我们着重考虑相关系数较大的特征。


#5 数据清洗

#(1) 房屋面积与月租金的分布
fig, axis = plt.subplots(1,2,sharey=True,figsize=(15,4))
axis[0].scatter(x=train['房屋面积'], y=train['Label'])
#去掉异常值
train2 = train.drop(train[(train['房屋面积']>0.2) & (train['Label']<20)].index)
axis[1].scatter(x=train2['房屋面积'], y=train2['Label'])
# plt.show()
# 去掉异常值后,可以明显看出房屋面积与月租金呈正相关关系。

#卫、卧、厅的数量
# 卫的数量
num = ['卫的数量','卧室数量','厅的数量']
for i in num:
    sns.boxplot(x=train[i],y=train['Label'])
    # plt.show()

# 各个特征的分布曲线如下
train.hist(figsize=(20, 15), bins=50, grid=False)
# plt.show()


#6 特征工程部分

#在大体了解了数据之间的关系及特征分布之后,接下来进入到特征工程部分。
# 去掉缺失值过多的特征后,还有时间、小区名、小区房屋出租数量、楼层、总楼层、房屋面积、房屋朝向、卧室数量、厅的数量、卫的数量、区、位置、地铁线路、地铁站点、距离15个特征变量。 从热力图中我们已经发现,房屋面积、卧室数量、厅的数量、卫的数量这四个特征对租金价格影响较大。
#在现实中,每个房屋的户型也很大程度上影响了房屋的月祖金,比如3室2厅和2室1厅租金是不一样的,所以要构造出卧室数量+厅的数量、卧室数量+卫的数量、厅的数量+卫的数量、及卧室+厅+卫的数量。

#卧、室、厅
train['卧室厅']=train['卧室数量']+train['厅的数量']
train['卧室卫']=train['卧室数量']+train['卫的数量']
train['房间总数']=train['卫的数量']+train['厅的数量']+train['卧室数量']
train['平均面积'] = train['房屋面积'] / train['房间总数']
train['卫的面积'] = train['房屋面积']*(train['卫的数量']/train['房间总数'])
train['卧室面积'] = train['房屋面积']*(train['卧室数量']/train['房间总数'])
train['厅的面积'] = train['房屋面积']*(train['厅的数量']/train['房间总数'])
#楼层
#原数据给了0、1、2来描述楼的高低程度,首先对其归一化并进行量化,然后与总楼层相乘可以推断出房屋所在的大体楼层
def fun(p):
    if p==0:
        r=0
    elif p==1:
        r=0.3333
    elif p==2:
        r=0.6666
    return  r
train['楼层']=train['楼层'].apply(lambda x:fun(x))
train['总楼层']=(train['总楼层']*100)**2
train['所在楼层']=train['总楼层']*train['楼层']

#地铁路线
#地铁线路存在104761条缺失值,value_counts()以后发现,存在1、2、3、4、5共五组数据,因此我们认为缺失值为没有地铁线路存在,填充0
train['地铁线路'].isnull().sum()
train['地铁线路'].value_counts()
train['地铁线路'] = train['地铁线路'].fillna(0)

#地铁站点
# 地铁站点同样存在104761条缺失值,观察数据发现,其值为1-119之间的整数,但是唯独缺少了60这个数字,其他数字都存在。因此,我们将缺失值填充为60
sub = set(train['地铁站点'].value_counts().index)
sub_a = set(np.arange(1,120))
sub_nan = sub_a - sub
train['地铁站点'] = train['地铁站点'].fillna(60)

#区、位置处理、小区房屋出租数量
# 同样,区的缺失值较少,值为0-14之间的整数,但是也唯独缺少了5,因此填充为5。位置值为0-152,唯独缺少76,填充76。
# 小区房屋出租数量缺失了31条,不多,不影响主要结果,可以删掉这31条,或者拿众数填充,我用众数填充了一下。
# 距离属性缺失太多,104761条缺失,而且不是分类变量,无法填充,删掉
train['区'] = train['区'].fillna(5)
train['位置'] = train['位置'].fillna(76)
train['小区房屋出租数量'] = train['小区房屋出租数量'].fillna(train['小区房屋出租数量'].mode()[0])
train.drop(['距离'], axis=1, inplace=True)

#处理房屋朝向
print('\n---------分割线----------\n')
print('房屋朝向\n',train['房屋朝向'].value_counts())
orientation_headers = ['东', '南', '西', '北',
                       '东南', '西南', '西北', '东北']

def fill_orientation(item, orientation):
    x = item.split(" ")
    return 1 if orientation in x else 0

for i in orientation_headers:
    train[i] = train['房屋朝向'].apply(lambda x: fill_orientation(x, i))
train.drop('房屋朝向', axis=1, inplace=True)


print('\n')
train.head()
train.info()
print(type(train))
print(train.columns)
train.to_csv('train2.csv',index=None,encoding="utf_8_sig")


train1 = pd.read_csv('train2.csv')
train1.head()
train1.info()
print("\n",train1.columns)

通过Excel对月租金label进行分级:

=IFS(LABEL<=10,"Level 1",LABEL<=20,"Level 2",LABEL<=30,"Level 3",LABEL<=40,"Level 4",LABEL<=50,"Level 5",LABEL<=60,"Level 6",LABEL<=70,"Level 7",LABEL<=80,"Level 8",LABEL<=90,"Level 9",LABEL<=100,"Level 10")

-150e49b10a072c57.png

通过spark构建逻辑回归模型,并判断模型准确率:

import os
from pyspark.sql.functions import corr
from pyspark.ml.linalg import Vector,Vectors
from pyspark.sql import Row,functions
from pyspark.ml.evaluation import MulticlassClassificationEvaluator
from pyspark.ml import Pipeline
from pyspark.ml.feature import IndexToString,StringIndexer,VectorIndexer,HashingTF,Tokenizer
from pyspark.ml.classification import LogisticRegression,LogisticRegressionModel,BinaryLogisticRegressionSummary

#本代码在本地pycharm连接远程虚拟机进行操作

#先配置java环境
os.environ["JAVA_HOME"]="/opt/Cluster/jdk1.8.0_162"#这里需要换成自己jdk的路径
os.environ["PYSPARK_PYTHON"]='/usr/bin/python3.6'

#create sparksession object
from pyspark.sql import SparkSession
spark=SparkSession.builder.appName('Logistic').getOrCreate()

#1 第一步,看数据
#Load the dataset
filename = r"file:///home/work/data/train2.csv"
df=spark.read.csv(filename,inferSchema=True,header=True)


#explore the data
df.printSchema()

#view statistical measures of data
df.describe().show(5,False)

#sneak into the dataset
print(df.head(3))

#查看相关性
data1 = ['ID', '位置', '区', '卧室数量', '卫的数量', '厅的数量', '地铁站点', '地铁线路', '小区名',
       '小区房屋出租数量', '总楼层', '房屋面积', '时间', '楼层', '卧室厅', '卧室卫',
       '房间总数', '平均面积', '卫的面积', '卧室面积', '厅的面积', '所在楼层', '东', '南', '西', '北',
       '东南', '西南', '西北', '东北']
for i in data1:
    df.select(corr(i,'Label')).show()

#查看有多少列
print(df.columns)

#2 构建向量
#依据之前的相关性:
def f(x):
    rel = {}
    rel['features'] = Vectors.dense(float(x[16]),float(x[17]),float(x[18]),float(x[19]),float(x[20]),float(x[21]),float(x[22]),float(x[23]),float(x[24]),float(x[25]),float(x[26]),float(x[27]),float(x[28]),float(x[29]),float(x[30]),float(x[31]),float(x[6]),float(x[7]))
    rel['Label'] = str(x[15])
    return rel

df.select('Label_d').show(5,False)
data = spark.sparkContext.textFile("file:///home/work/data/train3.csv").map(lambda line: line.split(',')).map(lambda p: Row(**f(p))).toDF()
data.show()

#3 分别获取标签列和特征列,进行索引后,再进行重命名
labelIndexer = StringIndexer().setInputCol('Label').setOutputCol('IndexedLabel').fit(data)
featureIndexer = VectorIndexer().setInputCol('features').setOutputCol('indexedFeatures').fit(data)

#4 设置LogisticRegression 算法的参数,循环次数100,规范化项为0.3,具体可由方法explainParams()获取
rent = LogisticRegression().setLabelCol('IndexedLabel').setFeaturesCol('indexedFeatures').setMaxIter(100).setRegParam(0.3).setElasticNetParam(0.8)
print('逻辑回归参数:\n',rent.explainParams())

#5 设置一个IndexToString转换器,把预测的类别重新转化为字符串,构建一个机器学习流水线(设置各阶段,使上一个阶段的输出作为本阶段的输入)
labelConverter = IndexToString().setInputCol('prediction').setOutputCol('predicteLabel').setLabels(labelIndexer.labels)
rentPipeline = Pipeline().setStages([labelIndexer,featureIndexer,rent,labelConverter])

#6 把数据集随机分成训练集和测试集,其中训练集占70%,Pipeline调用fit()时候产生一个PipelineModel转换器,调用transform()来进行预测,生成新DataFrame
trainData,testData = data.randomSplit([0.7,0.3])
rentPipelineModel = rentPipeline.fit(trainData)
rentPredictions = rentPipelineModel.transform(testData)

#7 输出预测的结果,select选择要输出的列,collect获取所有行数据,并用foreach每行打印下来
preRel = rentPredictions.select('predicteLabel','Label','features','probability').collect()
print('预测')
# for item in preRel:
#     print(str(item['Label'])+','+str(item['features'])+'-->prob='+str(item['probability'])+',预测结果为:'+str(item['predicteLabel']))

#8 对训练的模型进行评估,创建MuliticlassificationEvaluator实例,用setter方法设置预测分类的列名和真实列名,然后计算预测准确率
evaluator = MulticlassClassificationEvaluator().setLabelCol('IndexedLabel').setPredictionCol('prediction')
rentAccuracy = evaluator.evaluate(rentPredictions)
print('模型准确率',rentAccuracy)

#9 获取模型
rentModel = rentPipelineModel.stages[2]
print('\nCoefficients:'+str(rentModel.coefficientMatrix)+'\nIntercept:'+str(rentModel.interceptVector)+'\nnumClasses:'+str(rentModel.numClasses)+'\nnumFeatures:'+str(rentModel.numFeatures))

print('运行结束!')

结果:模型准确率 0.7187818071178854