注:源码在最后,只是一次课堂实验记录。
一 研究背景及意义
在大数据时代,商业领域的数据量迅速增长,如何有效地利用这些数据成为企业决策和优化成为重要的研究课题。单车租赁作为一种新兴的共享经济模式,其运营过程中产生了大量的用户行为和租赁数据。通过对这些数据的可视化分析,企业可以深入了解用户需求和市场动态,从而优化运营策略,提升用户体验和企业效益。
本文基于python语言,对华盛顿的共享单车租赁数据进行全面的可视化分析,旨在揭示数据背后的潜在模式和趋势。通过结合历史使用模式和天气数据,我们可以预测共享单车的租赁需求,识别出影响单车使用的关键因素,如时间、天气、地区差异等,为企业提供科学的决策依据。此外,本研究还探讨了数据可视化在商业分析中的应用价值,展示了如何利用现代技术工具将复杂的数据转化为直观的可视化图表,助力企业在竞争中取得优势,从而提高共享单车的利用率。
二 相关理论基础
大数据技术主要用于处理和分析海量、多样化、高速数据的技术和方法,包括数据存储、数据处理和数据分析等方面。它依赖于分布式计算框架(如Hadoop、Spark)、大规模数据存储解决方案(如HDFS、NoSQL数据库)以及先进的数据分析和挖掘工具(如机器学习、数据可视化)。大数据技术能够高效地从复杂和多源的数据中提取有价值的信息,支持实时处理和决策,广泛被应用于各个领域,推动了数据驱动的创新和商业智能的发展。
三 可视化实验设计
3.1 数据集简介
本文实验数据集采用Kaggle官方的单车租赁数据可视化分析数据集,数据地址:https://www.kaggle.com/c/bike-sharing-demand。
数据集包括两部分,分别为训练集和测试集,训练集由每月前19天的数据组成,测试集是每月第20天到当月底的数据。本文在实验过程中采用了该数据集的训练集作为对单车租赁的数据可视化研究数据。数据相关系数如图所示:
3.2 实验平台搭建
本文在 Windows 11 系统上搭建了机器学习实验环境,主要采用python保存语言及机器学习框架。annaconda集成开发环境和相关的python库(如numpy、pandas、datetime、matplotlib和seaborn等)作为基本开发框架。实验所用的硬件设备和软件配置见表 3-1。
表3-1实验环境的相关系数
|-------|-----------------------------|
| 设备 | 电脑 配置参数 |
| 操作系统 | Windows11 |
| 内存 | 32G |
| CPU型号 | Intel(R) Core(TM) i9-12900H |
| 显卡 | NVIDIA RTX 3060 Laptop |
| 硬盘 | 系统盘:512 GB |
| 开发语言 | Python 3.8 |
| 实验平台 | anaconda |
3.3可视化分析实验设计
3.3.1数据读取
在实验开始之前先导入实验过程中所需使用的python库(library),python库是指一组相关的模块和函数,用于提供特定领域或功能的支持。如图3.2所示:
python
#导入相关包
import numpy as np
import pandas as pd
import datetime
import matplotlib.pyplot as plt
import seaborn as sns
plt.figure(figsize = (10,8))
%matplotlib inline
图3.2导入相关python库
读取实验数据,pandas库提供了特点的csv数据读取功能,并将读取的数据以前5行的结果显示出来,结果如图3.3所示:
python
#用train来分析,导入数据,并且查看前五行信息
train = pd.read_csv(r'C:\Users\leglon\Desktop\自行车\train.csv')
test = pd.read_csv(r'C:\Users\leglon\Desktop\自行车\test.csv')
train.head()
图3.3 读取到的数据集前5行信息
数据检查,数据检查在数据可视化中起着至关重要的作用,它确保数据的准确性、完整性和一致性,从而保证可视化结果的可靠性和可信度。通过数据检查,可以发现并修正数据中的错误、缺失值和异常值,避免误导性的分析结果。数据检查还帮助理解数据的结构和特点,为选择合适的可视化方法和工具奠定基础。数据集缺失值检查如图3.4所示:
python
#查看是否有缺失值
train.isnull().sum()
图3.4数据集缺失值检查结果图
从输出结果来看,没有缺失值,不需要填补。
查看数据类型,在数据可视化分析中帮助选择适当的可视化方法和工具,从而准确地展示数据的特征和关系,避免误导性分析。本文的数据类型如图3.5所示:
python
#查看待处理数据的数据类型
train.info()
图3.5 数据类型结果图
从图3.5中可以看出datetime(时间)类型为objiect,不符合本文的实验需求,因此对datetime进行转换,如图3.6所示:
python
#将datetime转换为日期
dt = pd.DatetimeIndex(train['datetime'])
train.set_index(dt, inplace=True)
dtt = pd.DatetimeIndex(test['datetime'])
test.set_index(dtt, inplace=True)
def get_day(day_start):
day_end = day_start + pd.offsets.DateOffset(hours=23)
return pd.date_range(day_start, day_end, freq="H")
# 纳税日需要工作
train.loc[get_day(pd.datetime(2011, 4, 15)), "workingday"] = 1
train.loc[get_day(pd.datetime(2012, 4, 16)), "workingday"] = 1
# 感恩节不需要工作
test.loc[get_day(pd.datetime(2011, 11, 25)), "workingday"] = 0
test.loc[get_day(pd.datetime(2012, 11, 23)), "workingday"] = 0
# 圣诞节不需要工作
test.loc[get_day(pd.datetime(2011, 12, 24)), "workingday"] = 0
test.loc[get_day(pd.datetime(2011, 12, 31)), "workingday"] = 0
test.loc[get_day(pd.datetime(2012, 12, 26)), "workingday"] = 0
test.loc[get_day(pd.datetime(2012, 12, 31)), "workingday"] = 0
#暴雨
test.loc[get_day(pd.datetime(2012, 5, 21)), "holiday"] = 1
#海啸
train.loc[get_day(pd.datetime(2012, 6, 1)), "holiday"] = 1
图3.6 datetime转换为日期时间图
数据转换成功后,查看相关数据分布,以便后面的步骤快速进行,其结果如图3.7:
python
#提取年份、月份、日期等信息
from datetime import datetime
def time_process(df):
df['year'] = pd.DatetimeIndex(df.index).year
df['month'] = pd.DatetimeIndex(df.index).month
df['day'] = pd.DatetimeIndex(df.index).day
df['hour'] = pd.DatetimeIndex(df.index).hour
df['week'] = pd.DatetimeIndex(df.index).weekofyear
df['weekday'] = pd.DatetimeIndex(df.index).dayofweek
return df
train = time_process(train)
test = time_process(test)
train.head(5)
图3.7 相关数据分布情况图
3.3.2 对count数据可视化
以datetime为索引,查看租赁数据中数值差异的密度分布,如图3.8所示:
python
#以datetime为索引,查看数据
train = train.set_index('datetime')
sns.distplot(train["count"])
# plt.plot(s.index,s.values)#作图
图3.8 数值差异密度分布图
从图3.8中,通过可视化分析得出有长尾现象。显示count字段的描述信息,如图3.9:
python
#出现长尾现象,查看count信息描述
train["count"].describe()
图3.9 count字段的描述信息图
数据处理,将count小于第一四分位数的数据删除,处理结果如图3.10所示:
python
#数据处理,将count小于第一四分位数的数据删除
def Count(x):
if x <42:
return np.nan
else:
return x
bike1 = train
bike1["count"] = bike1["count"].apply(Count)
bike1 = bike1.dropna(axis=0, how='any')
sns.distplot(bike1["count"])
图3.10 删除后的密度分布
从输出结果来看,长尾现象有所改善。
3.3.3 对一天中不同时间段的影响进行可视化分析
对工作日的不同时间段的单车租赁情况进行可视化。其可视化如图3.11所示:
python
# 绘制箱线图
plt.figure(figsize=(12, 8))
sns.boxplot(x='hour', y='count', data=train[train['workingday'] == 1], palette='Set3')
plt.title('Bike Count Distribution by Hour on Working Days')
plt.xlabel('Hour of the Day')
plt.ylabel('Bike Count')
# 旋转 x 轴标签以防止重叠
plt.xticks(rotation=45)
plt.show()
图3.11工作日的不同时间段的单车租赁情况进行可视化图
从工作日的可视化结果图看出租赁数量主要集中在上下班期间。
对非工作日的不同时间段的单车租赁情况进行可视化。其可视化如图3.12所示:
python
# 绘制箱线图
plt.figure(figsize=(12, 8))
sns.boxplot(x='hour', y='count', data=train[train['workingday'] == 0], palette='Set3')
plt.title('Bike Count Distribution by Hour on Non-Working Days')
plt.xlabel('Hour of the Day')
plt.ylabel('Bike Count')
# 旋转 x 轴标签以防止重叠
plt.xticks(rotation=45)
plt.show()
图3.12 非工作日的不同时间段的单车租赁情况进行可视化
从图3.12得出非工作日的单车租赁早上9点到21点。
3.3.4 按月份进行单车租赁数据可视化
按月份进行单车租赁数据可视化分析,可以帮助理解在什么季节单车租赁情况良好,更好的做出单车投放决策。其可视化结果如图3.13所示,随着月份的增加,共享单车的使用量逐渐增加,在5月到10月间租赁数量基本稳定,之后略有下降。这可能是由于季节原因所致,在5-10月气候适宜,人们更愿意使用共享单车出行。
python
# 按月汇总数据
monthly_data = train.groupby('month')['count'].mean().reset_index()
# 绘制折线图
plt.figure(figsize=(12, 8))
sns.lineplot(x='month', y='count', data=monthly_data, marker='o')
for x, y in zip(monthly_data['month'], monthly_data['count']):
plt.text(x, y, f'{y:.0f}', ha='center', va='bottom')
plt.title('Monthly Average Bike Count')
plt.xlabel('Month')
plt.ylabel('Bike Count')
# 旋转 x 轴标签以防止重叠
plt.xticks(rotation=45)
plt.show()
图3.13按月份进行单车租赁数据可视化图
3.3.5 节假日对单车租赁数量可视化
节假日对单车租赁数量的可视化有助于揭示租赁需求的变化模式,帮助企业优化单车投放策略以满足不同时间段的用户需求。其结果如图3.14所示,从图中看出假日和非假日的平均租赁量来看,两者的日租赁量持平。
python
# 按节假日汇总数据
holiday_data = train.groupby('holiday')['count'].mean().reset_index()
# 绘制条形图
plt.figure(figsize=(5, 6))
sns.barplot(x='holiday', y='count', data=holiday_data, palette='viridis')
# 添加数据标签
for index, row in holiday_data.iterrows():
plt.text(row['holiday'], row['count'], f'{row["count"]:.0f}', color='black', ha="center")
plt.xlabel('Holiday')
plt.ylabel('Average Bike Count')
plt.show()
图3.14 节假日对单车租赁数量可视化图
3.3.6天气对单车租赁情况的影响可视化
天气对单车租赁情况的影响可视化能够直观地展示不同天气条件下的租赁需求变化,帮助企业优化调度和资源配置策略。天气可视化如图3.15所示:
python
#查看天气分布
train['weather'].value_counts().plot(kind='bar')
图3.15天气可视化图
从图3.15得出华盛顿的天气主要为晴天,按天气进行单车租赁汇总,其结果如图3.16,从结果上课,人们在晴朗天气选择租赁共享单车的人数最多,在小雨,小雪天的租赁数量最少。企业应根据天气预报和历史数据,优化单车投放和调度策略,在晴天增加投放量,确保供应充足,而在恶劣天气时可以适当减少投放,降低运营成本。
python
# 按天气情况汇总数据
weather_data = train.groupby('weather')['count'].mean().reset_index()
plt.figure(figsize=(10, 8))
plt.pie(weather_data['count'], labels=weather_data['weather'], autopct='%1.1f%%', startangle=140, colors=sns.color_palette('viridis', len(weather_data)))
plt.show()
图3.16 按天气进行单车租赁汇总可视化结果图
3.3.7 温度对租赁数量的影响可视化
python
#按温度进行汇总
temp_data = train.groupby('temp')[['registered', 'casual', 'count']].mean().reset_index()
plt.figure(figsize=(12, 8))
sns.lineplot(x='temp', y='registered', data=temp_data, marker='o', label='Registered')
sns.lineplot(x='temp', y='casual', data=temp_data, marker='o', label='Casual')
sns.lineplot(x='temp', y='count', data=temp_data, marker='o', label='Total Count')
plt.xlabel('Temp')
plt.ylabel('count')
plt.legend()
plt.show()
图3.17 温度对租赁数量的影响可视化图
从图3.17中,依靠温度数据发现,平均租赁数量随温度上升呈现先增加后减少的趋势,在30℃到35℃时达到最大。此结果表明,人们更倾向于在温暖天气租赁共享单车,但当温度过高时,需求量会减少。
3.3.8 从体感温度对租赁数量的影响进行可视化
python
# 按体感温度汇总数据
atemp_data = train.groupby('atemp')[['registered', 'casual', 'count']].mean().reset_index()
plt.figure(figsize=(12, 8))
sns.lineplot(x='atemp', y='registered', data=atemp_data, marker='o', label='Registered')
sns.lineplot(x='atemp', y='casual', data=atemp_data, marker='o', label='Casual')
sns.lineplot(x='atemp', y='count', data=atemp_data, marker='o', label='Total Count')
plt.xlabel('atemp')
plt.ylabel('count')
plt.legend()
plt.show()
图3.18体感温度对租赁数量的影响进行可视化图
如图3.18,体感温度的趋势与气温的趋势基本保持一致,表明人们更倾向于温暖的天气出行。
3.3.9 湿度对租赁数量的影响可视化
如下图3.19所示,湿度在20附件时租赁共享单车的人数最多,湿度超过30后,租赁数量逐渐减少,表明用户租赁情况与空气湿度因素相关。。
python
# 按湿度汇总数据
humidity_data = train.groupby('humidity')[['registered', 'casual', 'count']].mean().reset_index()
plt.figure(figsize=(12, 8))
sns.lineplot(x='humidity', y='registered', data=humidity_data, marker='o', label='Registered')
sns.lineplot(x='humidity', y='casual', data=humidity_data, marker='o', label='Casual')
sns.lineplot(x='humidity', y='count', data=humidity_data, marker='o', label='Total Count')
plt.xlabel('humidity')
plt.ylabel('count')
plt.legend()
plt.show()
图3.19 湿度对租赁数量的影响可视化结果图
3.3.10 风速对租赁数量的影响可视化
python
#按风速进行汇总
fig, ax = plt.subplots(figsize=(16, 6))
sns.pointplot(x='windspeed', y='count', data=train, join=True, ax=ax)
plt.xticks([0, 5, 10, 15, 20, 25])
plt.xlabel('Wind Speed')
plt.ylabel('count')
plt.show()
图3.20 风速对租赁数量的影响可视化结果图
从图3.20中得出,当风速大于45时,共享单车使用人数急剧减少,但当风速超过50后,租赁人数又急剧增加。表明风速正常和大风皆影响用户对单车的租赁意愿。
3.3.11 相关性分析可视化
python
corr = train[['count','temp','atemp','humidity','windspeed']].corr()
mask = np.array(corr)
mask[np.tril_indices_from(mask)] = False
fig,ax = plt.subplots()
fig.set_size_inches(15,8)
sns.heatmap(corr,mask=mask,vmax=.8,square=True,annot=True)
图3.21 相关性分析可视化结果图
从图3.21中得出,体感温度和温度有极大的相关性,在投放单车时要充分考虑各种因素。
四 总结与展望
本文基于Python语言,对华盛顿共享单车租赁数据进行了可视化分析,并且深入探索,揭示了在大数据背景下,数据背后的潜在模式和趋势。通过对历史使用模式、天气、温度、湿度和风速等多种因素的分析,我们发现了这些因素对单车租赁数量的显著影响。例如,人们更倾向于在温暖、晴朗的天气里租赁单车,而在小雨、小雪和极端风速条件下的租赁需求则显著减少。这些洞察为企业优化单车投放策略、提高单车利用率提供了科学依据。
此外,本文的方法和技术可以推广应用到其他城市和共享经济模式中,探索更多影响因素的作用,如社会活动、交通状况等。
综上所述,基于Python语言的数据可视化分析为商业数据分析提供了强大的工具和方法,通过不断创新和优化,我们可以更好地挖掘数据价值,助力商业决策和市场发展。未来,随着技术的进一步进步和应用的不断拓展,我们有望看到更加智能化和精准化的数据驱动决策,为企业带来更大的商业价值和社会效益。
五 源代码
python
#导入相关包
import numpy as np
import pandas as pd
import datetime
import matplotlib.pyplot as plt
import seaborn as sns
plt.figure(figsize = (10,8))
%matplotlib inline
#用train来分析,导入数据,并且查看前五行信息
train = pd.read_csv(r'C:\Users\leglon\Desktop\自行车\train.csv')
test = pd.read_csv(r'C:\Users\leglon\Desktop\自行车\test.csv')
train.head()
#查看是否有缺失值
train.isnull().sum()
#查看待处理数据的数据类型
train.info()
#将datetime转换为日期
dt = pd.DatetimeIndex(train['datetime'])
train.set_index(dt, inplace=True)
dtt = pd.DatetimeIndex(test['datetime'])
test.set_index(dtt, inplace=True)
def get_day(day_start):
day_end = day_start + pd.offsets.DateOffset(hours=23)
return pd.date_range(day_start, day_end, freq="H")
# 纳税日需要工作
train.loc[get_day(pd.datetime(2011, 4, 15)), "workingday"] = 1
train.loc[get_day(pd.datetime(2012, 4, 16)), "workingday"] = 1
# 感恩节不需要工作
test.loc[get_day(pd.datetime(2011, 11, 25)), "workingday"] = 0
test.loc[get_day(pd.datetime(2012, 11, 23)), "workingday"] = 0
# 圣诞节不需要工作
test.loc[get_day(pd.datetime(2011, 12, 24)), "workingday"] = 0
test.loc[get_day(pd.datetime(2011, 12, 31)), "workingday"] = 0
test.loc[get_day(pd.datetime(2012, 12, 26)), "workingday"] = 0
test.loc[get_day(pd.datetime(2012, 12, 31)), "workingday"] = 0
#暴雨
test.loc[get_day(pd.datetime(2012, 5, 21)), "holiday"] = 1
#海啸
train.loc[get_day(pd.datetime(2012, 6, 1)), "holiday"] = 1
#提取年份、月份、日期等信息
from datetime import datetime
def time_process(df):
df['year'] = pd.DatetimeIndex(df.index).year
df['month'] = pd.DatetimeIndex(df.index).month
df['day'] = pd.DatetimeIndex(df.index).day
df['hour'] = pd.DatetimeIndex(df.index).hour
df['week'] = pd.DatetimeIndex(df.index).weekofyear
df['weekday'] = pd.DatetimeIndex(df.index).dayofweek
return df
train = time_process(train)
test = time_process(test)
train.head(5)
#以datetime为索引,查看数据
train = train.set_index('datetime')
sns.distplot(train["count"])
# plt.plot(s.index,s.values)#作图
#出现长尾现象,查看count信息描述
train["count"].describe()
#数据处理,将count小于第一四分位数的数据删除
def Count(x):
if x <42:
return np.nan
else:
return x
bike1 = train
bike1["count"] = bike1["count"].apply(Count)
bike1 = bike1.dropna(axis=0, how='any')
sns.distplot(bike1["count"])
# 绘制箱线图
plt.figure(figsize=(12, 8))
sns.boxplot(x='hour', y='count', data=train[train['workingday'] == 1], palette='Set3')
plt.title('Bike Count Distribution by Hour on Working Days')
plt.xlabel('Hour of the Day')
plt.ylabel('Bike Count')
# 旋转 x 轴标签以防止重叠
plt.xticks(rotation=45)
plt.show()
# 绘制箱线图
plt.figure(figsize=(12, 8))
sns.boxplot(x='hour', y='count', data=train[train['workingday'] == 0], palette='Set3')
plt.title('Bike Count Distribution by Hour on Non-Working Days')
plt.xlabel('Hour of the Day')
plt.ylabel('Bike Count')
# 旋转 x 轴标签以防止重叠
plt.xticks(rotation=45)
plt.show()
# 按月汇总数据
monthly_data = train.groupby('month')['count'].mean().reset_index()
# 绘制折线图
plt.figure(figsize=(12, 8))
sns.lineplot(x='month', y='count', data=monthly_data, marker='o')
for x, y in zip(monthly_data['month'], monthly_data['count']):
plt.text(x, y, f'{y:.0f}', ha='center', va='bottom')
plt.title('Monthly Average Bike Count')
plt.xlabel('Month')
plt.ylabel('Bike Count')
# 旋转 x 轴标签以防止重叠
plt.xticks(rotation=45)
plt.show()
# 按节假日汇总数据
holiday_data = train.groupby('holiday')['count'].mean().reset_index()
# 绘制条形图
plt.figure(figsize=(5, 6))
sns.barplot(x='holiday', y='count', data=holiday_data, palette='viridis')
# 添加数据标签
for index, row in holiday_data.iterrows():
plt.text(row['holiday'], row['count'], f'{row["count"]:.0f}', color='black', ha="center")
plt.xlabel('Holiday')
plt.ylabel('Average Bike Count')
plt.show()
#查看天气分布
train['weather'].value_counts().plot(kind='bar')
# 按天气情况汇总数据
weather_data = train.groupby('weather')['count'].mean().reset_index()
plt.figure(figsize=(10, 8))
plt.pie(weather_data['count'], labels=weather_data['weather'], autopct='%1.1f%%', startangle=140, colors=sns.color_palette('viridis', len(weather_data)))
plt.show()
#按温度进行汇总
temp_data = train.groupby('temp')[['registered', 'casual', 'count']].mean().reset_index()
plt.figure(figsize=(12, 8))
sns.lineplot(x='temp', y='registered', data=temp_data, marker='o', label='Registered')
sns.lineplot(x='temp', y='casual', data=temp_data, marker='o', label='Casual')
sns.lineplot(x='temp', y='count', data=temp_data, marker='o', label='Total Count')
plt.xlabel('Temp')
plt.ylabel('count')
plt.legend()
plt.show()
# 按体感温度汇总数据
atemp_data = train.groupby('atemp')[['registered', 'casual', 'count']].mean().reset_index()
plt.figure(figsize=(12, 8))
sns.lineplot(x='atemp', y='registered', data=atemp_data, marker='o', label='Registered')
sns.lineplot(x='atemp', y='casual', data=atemp_data, marker='o', label='Casual')
sns.lineplot(x='atemp', y='count', data=atemp_data, marker='o', label='Total Count')
plt.xlabel('atemp')
plt.ylabel('count')
plt.legend()
plt.show()
# 按湿度汇总数据
humidity_data = train.groupby('humidity')[['registered', 'casual', 'count']].mean().reset_index()
plt.figure(figsize=(12, 8))
sns.lineplot(x='humidity', y='registered', data=humidity_data, marker='o', label='Registered')
sns.lineplot(x='humidity', y='casual', data=humidity_data, marker='o', label='Casual')
sns.lineplot(x='humidity', y='count', data=humidity_data, marker='o', label='Total Count')
plt.xlabel('humidity')
plt.ylabel('count')
plt.legend()
plt.show()
#按风速进行汇总
fig, ax = plt.subplots(figsize=(16, 6))
sns.pointplot(x='windspeed', y='count', data=train, join=True, ax=ax)
plt.xticks([0, 5, 10, 15, 20, 25])
plt.xlabel('Wind Speed')
plt.ylabel('count')
plt.show()
corr = train[['count','temp','atemp','humidity','windspeed']].corr()
mask = np.array(corr)
mask[np.tril_indices_from(mask)] = False
fig,ax = plt.subplots()
fig.set_size_inches(15,8)
sns.heatmap(corr,mask=mask,vmax=.8,square=True,annot=True)