利用python进行大数据获取与数据预处理

1.概述 

该实例针对北京公交数据进行处理与可视化。数据获取借助get_line_info函数等提取线路详情存为CSV。预处理设置字体、格式化日期后读取数据。清洗时剔除重复、异常、地铁相关数据,填充缺失值并归一化。可视化方面,公交线路上行站点数量分布直方图展现站点分布特点,前10运营公司线路数量柱状图经标签优化,清晰呈现各公司线路数量差异,助力公交运营研究。

2.设计内容

2.1数据获取阶段

  1. 编写函数用于获取单个公交线路的详细信息并整理成字典格式。

  2. 从网页源码中解析出公交线路的基本信息和站点信息。

  3. 存储所有线路信息,并将数据保存为CSV文件。

2.2数据预处理阶段

  1. 设置合适的字体属性以确保中文显示正常。

  2. 定义函数对日期时间列数据进行格式化处理。

  3. 读取CSV文件并处理编码问题,确保日期格式统一。

2.3数据清洗阶段

  1. 去除特定列中的重复数据,保留每个线路对应的最后一行数据。

  2. 检查数据的缺失值和唯一值情况,初步探索数据结构。

  3. 剔除与地铁相关的线路数据,确保数据集的准确性。

  4. 处理异常值,将超出合理范围的数据排除。

  5. 对数据进行归一化处理,提高数据可比性。

2.4数据可视化阶段

  1. 绘制公交线路上行站点数量分布的直方图,以便观察站点数量的分布情况。

3.设计方案

    4.具体实现

    4.1 数据获取

    4.1.1 获取部分

    定义get_line_info函数:该函数用于获取单个线路的详细信息并整理成字典格式。

    (1)获取页面内容并解析

    用requests获取页面文本,etree.HTML解析,xpath找相关div元素准备提取信息。

    (2)提取线路基本信息并处理可能为空的值

    初始化列表存字典,xpath提取起始站等信息,为空的运营时间设默认值。

    (3)提取上下行站点信息

    xpath找ul元素,初始化空列表遍历li提取站点名,获取上下行站点信息。

    (4)整理信息为字典并添加到列表

    4.1.2 数据抽取阶段

    (1)获取网页源码:

    (2)解析网页获取线路名称和url:

    (3)存储所有线路信息:

    (4)保存数据为CSV文件:

    4.1.3 运行结果

    4.2数据预处理部分

  1. 设置中文字体:为了在后续绘制的图表中正确显示中文,代码会查找系统中的SimHei(黑体)字体,并将其设置为全局字体。

  2. 日期时间格式化:定义了一个函数format_date_column,用于将数据中line_up_times列的日期时间格式统一转换为"%Y-%m-%d %H:%M:%S"

  3. 读取数据:定义了一个函数read_data,该函数会自动检测BeiJin_Bus_Line.csv文件的编码,并尝试使用检测到的编码读取文件。如果自动检测失败,会依次尝试gbkgb2312latin1编码。读取文件后,会调用format_date_column函数对日期时间列进行格式化处理。

  4.  

    import pandas as pd
    import chardet
    import matplotlib.font_manager as fm
    import matplotlib.pyplot as plt
    import matplotlib as mpl

    # 查找系统中SimHei字体的路径(你也可以手动查找后直接填写准确路径)
    font_path = fm.findfont(fm.FontProperties(family='SimHei'))

    # 设置字体属性,用于后续图表显示中文
    font_prop = mpl.font_manager.FontProperties(fname=font_path)

    # 设置全局字体
    mpl.rcParams['font.family'] = font_prop.get_name()

    # 定义函数用于格式化日期时间列数据,将可能不规范的格式严格统一为 "%Y-%m-%d %H:%M:%S"
    def format_date_column(data):
        # 先替换分隔符
        data['line_up_times'] = data['line_up_times'].str.replace('/', '-')
        # 再补全时间部分缺少的前导0等,确保格式符合 "%Y-%m-%d %H:%M:%S"
        data['line_up_times'] = data['line_up_times'].apply(
            lambda x: pd.to_datetime(x, format='%Y-%m-%d %H:%M', errors='coerce').strftime(
                '%Y-%m-%d %H:%M:%S') if pd.notnull(x) else x)
        return data

    # 读取数据,先尝试检测文件编码并读取
    def read_data():
        try:
            with open('BeiJin_Bus_Line.csv', 'rb') as f:
                result = chardet.detect(f.read())
                encoding = result['encoding']
            ori_data = pd.read_csv('BeiJin_Bus_Line.csv', encoding=encoding)
        except UnicodeDecodeError:
            # 如果自动检测编码失败,尝试几种常见编码格式读取
            encodings = ['gbk', 'gb2312', 'latin1']
            for encoding in encodings:
                try:
                    ori_data = pd.read_csv('BeiJin_Bus_Line.csv', encoding=encoding)
                    break
                except UnicodeDecodeError:
                    continue
            if 'ori_data' not in locals():
                print("无法正确读取文件,请检查文件编码情况。")
                raise
        # 对日期时间列数据进行格式统一处理
        ori_data = format_date_column(ori_data)
        return ori_data

    4.3数据清洗

  5. 重复数据剔除:提供两种方法剔除数据中的重复线路数据。

  6. 数据检查:查看数据的缺失值情况和每列的唯一值个数。

  7. 地铁线路删除:从数据中删除地铁线路相关数据。

  8. 异常值处理:通过分位数确定上下限,处理上行站点数量列的异常值。

  9. 数据归一化:对上行站点数量列进行归一化处理。

  10. 数据格式处理:统一线路名称为大写,去除运营公司列的前后空格。

  11. 特征提取:从日期时间列中提取年份和月份信息作为新列。

  12. 缺失值填充:使用众数填充线路价格列的缺失值。

  13.  

    import pandas as pd
    from sklearn.preprocessing import MinMaxScaler

    # 定义函数用于处理重复数据剔除(公共逻辑提取)
    def remove_duplicates(data):
        data['line_up_times'] = pd.to_datetime(data['line_up_times'], format='%Y-%m-%d %H:%M:%S')
        # 使用.loc进行索引,确保操作的是原始数据本身,而不是副本
        data = data.sort_values(by=['line_name', 'line_up_times'], ascending=[True, True])
        return data.drop_duplicates(subset=['line_name'], keep='last')

    # 执行数据清洗与特征工程操作
    def process_data(ori_data):
        # 查看数据的缺失值情况
        print(ori_data.isnull().sum())

        # 查看每一列数据的唯一值个数
        print(ori_data.nunique())

        # 对原数据剔除重复的值 – 方法1
        drop_dup_line1 = remove_duplicates(ori_data)

        # 对原数据剔除重复的值 – 方法2
        dup_data_all = ori_data[ori_data.duplicated(subset=['line_name'], keep=False)]
        dup_data_all = remove_duplicates(dup_data_all)
        other_data = ori_data[~ori_data['line_name'].isin(dup_data_all['line_name'])]
        drop_dup_line2 = pd.concat([other_data, dup_data_all])

        # 比较两种方法获得的结果线路是否一致
        drop_dup_line2 = drop_dup_line2.sort_values(by=['line_name', 'line_up_times'], ascending=[True, True])
        res = (drop_dup_line1['line_name'].values == drop_dup_line2['line_name'].values).sum()
        print(res)

        # 删除地铁线路
        is_subway = drop_dup_line1['line_name'].str.contains('地铁', case=False) | drop_dup_line1['line_company'].str.contains(
            '地铁', case=False)
        subway_data = drop_dup_line1[is_subway]

        # 获取删除地铁数据之后的全部数据
        clean_data = drop_dup_line1[~drop_dup_line1['line_name'].isin(subway_data['line_name'])]

        # 更合理地处理上行站点数量列的异常值,通过分位数确定上下限(示例,可根据实际调整)
        q1 = clean_data['line_station_up_len'].quantile(0.05)
        q3 = clean_data['line_station_up_len'].quantile(0.95)
        iqr = q3 – q1
        lower_bound = q1 – 1.5 * iqr
        upper_bound = q3 + 1.5 * iqr
        clean_data = clean_data[
            (clean_data['line_station_up_len'] > lower_bound) & (clean_data['line_station_up_len'] < upper_bound)]

        # 提取要归一化的列数据
        station_up_len_data = clean_data[['line_station_up_len']].values
        # 创建归一化对象并进行归一化
        scaler = MinMaxScaler()
        normalized_station_up_len = scaler.fit_transform(station_up_len_data)
        # 将归一化后的数据替换原列数据
        clean_data['line_station_up_len'] = normalized_station_up_len

        # 统一线路名称为大写
        clean_data['line_name'] = clean_data['line_name'].str.upper()
        # 去除运营公司列的前后空格
        clean_data['line_company'] = clean_data['line_company'].str.strip()

        # 提取年份和月份信息作为新列
        clean_data['year'] = clean_data['line_up_times'].dt.year
        clean_data['month'] = clean_data['line_up_times'].dt.month

        print(len(clean_data))

        # 查看数据集中的缺失值情况并填充
        price_mode = clean_data['line_price'].mode()
        if len(price_mode) > 0:
            fill_value = price_mode[0]
            # 使用.loc明确操作原始.data,避免SettingWithCopyWarning警告
            clean_data.loc[:, 'line_price'] = clean_data['line_price'].fillna(fill_value)

        print(clean_data.isnull().sum())

        return clean_data

     

    4.4 数据可视化

    import pandas as pd
    import matplotlib.pyplot as plt

    # 执行数据可视化操作
    def visualize_data(clean_data):
        # 1. 绘制公交线路上行站点数量分布直方图
        plt.figure(figsize=(10, 6))
        clean_data['line_station_up_len'].hist(bins=20, color='skyblue', alpha=0.7)  # 设置颜色和透明度
        plt.xlabel('上行站点数量')
        plt.ylabel('线路数量')
        plt.title('北京公交线网上行站点数量分布情况')
        plt.grid(axis='y', linestyle='–', alpha=0.7)  # 添加y轴方向的网格线
        plt.show()

        # 2. 绘制不同运营公司的线路数量柱状图(只显示关键数据,取前10名运营公司)
        company_counts = clean_data['line_company'].value_counts()
        top_10_companies = company_counts.head(10)  # 获取线路数量排名前10的运营公司数据
        plt.figure(figsize=(10, 6))
        ax = top_10_companies.plot(kind='bar', color='orange')  # 设置柱状图颜色
        ax.set_xlabel('运营公司')
        ax.set_ylabel('线路数量')
        ax.set_title('北京公交部分关键运营公司的线路数量分布')
        ax.set_xticklabels(ax.get_xticklabels(), rotation=45, ha='right')  # 调整x轴标签旋转及对齐方式
        ax.grid(axis='y', linestyle='–', alpha=0.7)  # 添加y轴方向的网格线
        plt.show()

    5.总结

    数据获取阶段包括页面内容解析和信息提取,数据预处理阶段包括字体设置和数据格式化,数据清洗阶段包括重复值处理和异常值处理。最终,成功存储并清洗了公交线路数据,并展示了上行站点数量的数据分布。

    作者:WWWxxx0424

    物联沃分享整理
    物联沃-IOTWORD物联网 » 利用python进行大数据获取与数据预处理

    发表回复