基于地铁刷卡数据分析与可视化——以杭州市为例(二)

上篇文章提到,由于2019年1月1日正好是元旦,为了消除节假日对数据分析的影响,我们选择了节后的一周来进行详细的客流分析。具体日期选择为2019年1月8日至1月14日。在这段时间内,我们关注的是地铁线路的进站客流情况。数据表中的 'status' 字段表示进出站状态,其中0代表出站,1代表进站。我们的目标是计算这一周内三条地铁线路(A线、B线和C线)的平均进站客流量,以全面了解各线路的客流分布和高峰时段的特点;

完整代码#运行环境Python 3.11

python 复制代码
# -*- coding: utf-8 -*-

import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 使用黑体
plt.rcParams['axes.unicode_minus'] = False  # 正常显示负号

# 文件路径列表
file_paths = [
    'D:\\data\\record_2019-01-08.csv',
    'D:\\data\\record_2019-01-09.csv',
    'D:\\data\\record_2019-01-10.csv',
    'D:\\data\\record_2019-01-11.csv',
    'D:\\data\\record_2019-01-12.csv',
    'D:\\data\\record_2019-01-13.csv',
    'D:\\data\\record_2019-01-14.csv'
]

# 存储每个日期的每小时客流量
daily_hourly_counts = []

# 读取每个CSV文件并计算每小时客流量
for file_path in file_paths:
    df = pd.read_csv(file_path)

    # 确保 'time' 列是 datetime 类型
    df['time'] = pd.to_datetime(df['time'])

    # 筛选条件:'lineID' = 'A' 且 'status' = 1
    filtered_df = df[(df['lineID'] == 'A') & (df['status'] == 1)]

    # 按 'time' 和 'stationID' 分组,并按小时汇总客流量
    hourly_station_customer_count = filtered_df.groupby([filtered_df['time'].dt.hour, 'stationID']).size().unstack(fill_value=0)

    # 将结果存储到列表中
    daily_hourly_counts.append(hourly_station_customer_count)

# 合并所有日期的每小时客流量
combined_hourly_counts = pd.concat(daily_hourly_counts, axis=0)

# 计算每个小时各个 stationID 的平均客流量
average_hourly_station_customer_count = combined_hourly_counts.groupby(combined_hourly_counts.index).mean()

# 打印结果
print("每个小时各个 'stationID' 的平均客流量:")
print(average_hourly_station_customer_count)

# 可视化
plt.figure(figsize=(14, 7))

# 为每个 stationID 绘制折线图
for station in average_hourly_station_customer_count.columns:
    plt.plot(average_hourly_station_customer_count.index, average_hourly_station_customer_count[station], label=f'Station {station}')

# 设置图表标题和标签
plt.title('每个小时各个 stationID 的平均客流量')
plt.xlabel('小时')
plt.ylabel('平均客流量')
plt.legend()
plt.grid(True)

# 显示图表
plt.show()

我们通过编写Python脚本来计算全天24小时内各个站点的进站客流量变化情况,并进一步对一周内的客流量数据求均值,以全面了解各站点的客流量分布特点;

A线路各个站点在全天的平均进站客流量分布情况

B线路各个站点在全天的平均进站客流量分布情况

C线路各个站点在全天的平均进站客流量分布情况

我们把数据的研究尺度进一步缩小,同样的,我们通过python脚本来计算一下,全天24小时的各个站点进站客流的早晚高峰峰值区间分布情况,并对一周的客流量求均值,我们来看各线路早晚高峰的15分钟峰值客流分布情况;

完整代码#运行环境Python 3.11

python 复制代码
# -*- coding: utf-8 -*-

import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 使用黑体
plt.rcParams['axes.unicode_minus'] = False  # 正常显示负号


def read_and_process_file(file_path):
    try:
        df = pd.read_csv(file_path)
        df['time'] = pd.to_datetime(df['time'])
        filtered_df = df[(df['lineID'] == 'A') & (df['status'] == 1)]
        # 按15分钟分组
        fifteen_minute_station_customer_count = filtered_df.groupby(
            [pd.Grouper(key='time', freq='15min'), 'stationID']).size().unstack(fill_value=0)
        return fifteen_minute_station_customer_count
    except Exception as e:
        print(f"Error processing file {file_path}: {e}")
        return None


# 文件路径列表
file_paths = [
    'D:\\data\\record_2019-01-08.csv',
    'D:\\data\\record_2019-01-09.csv',
    'D:\\data\\record_2019-01-10.csv',
    'D:\\data\\record_2019-01-11.csv',
    'D:\\data\\record_2019-01-12.csv',
    'D:\\data\\record_2019-01-13.csv',
    'D:\\data\\record_2019-01-14.csv'
]

# 存储每个日期的每15分钟客流量
daily_fifteen_minute_counts = []

# 读取每个CSV文件并计算每15分钟客流量
for file_path in file_paths:
    fifteen_minute_station_customer_count = read_and_process_file(file_path)
    if fifteen_minute_station_customer_count is not None:
        daily_fifteen_minute_counts.append(fifteen_minute_station_customer_count)

# 合并所有日期的每15分钟客流量
combined_fifteen_minute_counts = pd.concat(daily_fifteen_minute_counts, axis=0)

# 计算每15分钟各个 stationID 的平均客流量
average_fifteen_minute_station_customer_count = combined_fifteen_minute_counts.groupby(
    combined_fifteen_minute_counts.index.time).mean()

# 将索引转换为 DatetimeIndex
average_fifteen_minute_station_customer_count.index = pd.to_datetime(
    average_fifteen_minute_station_customer_count.index, format='%H:%M:%S')

# 打印结果
print("每15分钟各个 'stationID' 的平均客流量:")
print(average_fifteen_minute_station_customer_count)

# 确定早高峰和晚高峰15分钟区间
peak_intervals = {}
for station in average_fifteen_minute_station_customer_count.columns:
    # 早高峰时间段
    morning_peak = average_fifteen_minute_station_customer_count.between_time('06:00', '10:00')[station].idxmax()
    # 晚高峰时间段
    evening_peak = average_fifteen_minute_station_customer_count.between_time('16:00', '20:00')[station].idxmax()

    formatted_morning_peak = f"{morning_peak.strftime('%H:%M')}-{(morning_peak + pd.Timedelta(minutes=15)).strftime('%H:%M')}"
    formatted_evening_peak = f"{evening_peak.strftime('%H:%M')}-{(evening_peak + pd.Timedelta(minutes=15)).strftime('%H:%M')}"

    peak_intervals[station] = {
        'morning': formatted_morning_peak,
        'evening': formatted_evening_peak
    }

# 输出每个站点的早高峰和晚高峰15分钟区间
print("\n各站点早高峰和晚高峰进站客流的15分钟区间:")
for station, intervals in peak_intervals.items():
    print(f"Station {station}: 早高峰 {intervals['morning']}, 晚高峰 {intervals['evening']}")

# 可视化
fig, ax = plt.subplots(figsize=(14, 8))

# 为每个 stationID 绘制24小时刻度图
cmap = plt.get_cmap('tab10')  # 获取颜色映射
colors = [cmap(i % cmap.N) for i in range(len(peak_intervals))]

for i, (station, intervals) in enumerate(peak_intervals.items()):
    # 早高峰
    start_time, end_time = intervals['morning'].split('-')
    start_hour = int(start_time[:2]) + int(start_time[3:]) / 60
    end_hour = int(end_time[:2]) + int(end_time[3:]) / 60
    ax.axvspan(start_hour, end_hour, alpha=0.3, color=colors[i],
               label=f'Station {station} 早高峰 {intervals["morning"]}')

    # 晚高峰
    start_time, end_time = intervals['evening'].split('-')
    start_hour = int(start_time[:2]) + int(start_time[3:]) / 60
    end_hour = int(end_time[:2]) + int(end_time[3:]) / 60
    ax.axvspan(start_hour, end_hour, alpha=0.3, color=colors[i],
               label=f'Station {station} 晚高峰 {intervals["evening"]}')

# 设置图表标题和标签
ax.set_title('各站点早高峰和晚高峰进站客流的15分钟区间')
ax.set_xlabel('时间 (小时)')
ax.set_ylabel('客流量')
ax.set_xlim(0, 24)
ax.set_xticks(range(25))
ax.set_xticklabels([f'{i}:00' if i % 2 == 0 else '' for i in range(25)])

# 调整图例的位置和大小
ax.legend(loc='upper left', bbox_to_anchor=(1.05, 1), borderaxespad=0., fontsize='small')

# 手动调整子图之间的间距
plt.subplots_adjust(left=0.1, right=0.8, top=0.9, bottom=0.1)

# 显示图表
plt.show()

整体来说,这些线路的早高峰时间段: 大多数站点的早高峰集中在08:00-08:30之间,特别是08:00-08:15和08:15-08:30两个时间段。 个别站点的早高峰时间较晚,如Station 76(09:45-10:00)和Station 77(09:30-09:45);我们可以看到,晚高峰的分布时刻带更宽,根据站点的分布情况和地理位置等情况,个站点晚高峰到来的时刻更早或晚,大多数站点的晚高峰集中在17:15-18:00之间,特别是17:15-17:30和17:30-17:45两个时间段;

A线路各个站点在全天的进站客流量中,早晚高峰15分钟的最大客流时刻分布情况

B线路各个站点在全天的进站客流量中,早晚高峰15分钟的最大客流时刻分布情况

C线路各个站点在全天的进站客流量中,早晚高峰15分钟的最大客流时刻分布情况

我们使用Python脚本再来探究一下地铁各线路的进站客流数据进行分析,找出各线路进站客流前10名的站点客流分布情况和特征;

完整代码#运行环境Python 3.11

python 复制代码
# -*- coding: utf-8 -*-

import pandas as pd

def read_and_process_file(file_path):
    try:
        df = pd.read_csv(file_path)
        df['time'] = pd.to_datetime(df['time'])
        return df
    except Exception as e:
        print(f"Error processing file {file_path}: {e}")
        return None

# 文件路径列表
file_paths = [
    'D:\\data\\record_2019-01-08.csv',
    'D:\\data\\record_2019-01-09.csv',
    'D:\\data\\record_2019-01-10.csv',
    'D:\\data\\record_2019-01-11.csv',
    'D:\\data\\record_2019-01-12.csv',
    'D:\\data\\record_2019-01-13.csv',
    'D:\\data\\record_2019-01-14.csv'
]

# 读取并处理所有文件
dfs = [read_and_process_file(file_path) for file_path in file_paths]
df = pd.concat(dfs, ignore_index=True)

# 过滤 A 线的数据
a_line_data = df[df['lineID'] == 'A']

# 提取进站数据
inbound_data = a_line_data[a_line_data['status'] == 1]

# 计算每天的平均进站客流
daily_inbound_flow = inbound_data.groupby([inbound_data['time'].dt.date, 'stationID'])['userID'].count().reset_index()
daily_inbound_flow.columns = ['date', 'stationID', 'inbound_count']

# 计算每个站点的平均进站客流
average_inbound_flow = daily_inbound_flow.groupby('stationID')['inbound_count'].mean().reset_index()
average_inbound_flow.columns = ['stationID', 'average_inbound_count']

# 按平均进站客流排序并取前10名
top_10_inbound_stations = average_inbound_flow.sort_values(by='average_inbound_count', ascending=False).head(10)

# 输出前10名站点的平均进站客流到 CSV 文件
output_file_path = 'D:\\data\\top_10_inbound_stations.csv'
top_10_inbound_stations.to_csv(output_file_path, index=False)
print(f"Top 10 inbound stations data saved to {output_file_path}")

我们可以看到A线路每天平均进站客流前10名站点客流呈阶梯式递减,B线路每天平均进站客流前10名站点中编码15的站点客流占大头,其他客流呈较为相似状态,差别不大,C线路每天平均进站客流前10名站点中,客流客流较为均衡,线路整体各站点进站客流较为平稳;

A线路每天平均进站客流前10名站点

B线路每天平均进站客流前10名站点

C线路每天平均进站客流前10名站点

文章仅用于分享个人学习成果与个人存档之用,分享知识,如有侵权,请联系作者进行删除。所有信息均基于作者的个人理解和经验,不代表任何官方立场或权威解读。

相关推荐
2401_857439692 小时前
SSM 架构下 Vue 电脑测评系统:为电脑性能评估赋能
开发语言·php
SoraLuna3 小时前
「Mac畅玩鸿蒙与硬件47」UI互动应用篇24 - 虚拟音乐控制台
开发语言·macos·ui·华为·harmonyos
xlsw_3 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
梧桐树04293 小时前
python常用内建模块:collections
python
Dream_Snowar4 小时前
速通Python 第三节
开发语言·python
Data跳动4 小时前
Spark内存都消耗在哪里了?
大数据·分布式·spark
高山我梦口香糖5 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
落魄君子5 小时前
GA-BP分类-遗传算法(Genetic Algorithm)和反向传播算法(Backpropagation)
算法·分类·数据挖掘
落魄君子5 小时前
ELM分类-单隐藏层前馈神经网络(Single Hidden Layer Feedforward Neural Network, SLFN)
神经网络·分类·数据挖掘
woshiabc1115 小时前
windows安装Elasticsearch及增删改查操作
大数据·elasticsearch·搜索引擎