【DCIC】数据分析学习:3.地图数据统计

  • Post author:
  • Post category:其他


目录


学习目标


地图数据统计(基础知识)


GPS经纬度


分组聚合统计


地图数据统计(实践)


统计巡游车与网约车分布


学习资源


任务


学习目标

  • GPS经纬度介绍


  • Pandas


    分组聚合
  • 出租车与网约车经纬度统计

地图数据统计(基础知识)

在任务三,我们希望通过分析和统计能够发现:

  • 巡游车与网约车的空间分布;
  • 上下客点分布密度:上下车位置分布;

GPS经纬度

  • WGS-84原始坐标系,一般用国际GPS记录仪记录下来的经纬度,通过GPS定位拿到的原始经纬度,Google和高德地图定位的的经纬度(国外)都是基于WGS-84坐标系的;但是在国内是不允许直接用WGS84坐标系标注的,必须经过加密后才能使用;
  • GCJ-02坐标系,又名“火星坐标系”,是我国国测局独创的坐标体系,由WGS-84加密而成,在国内,必须至少使用GCJ-02坐标系,或者使用在GCJ-02加密后再进行加密的坐标系,如百度坐标系。高德和Google在国内都是使用GCJ-02坐标系,可以说GCJ-02是国内最广泛使用的坐标系;
  • 百度坐标系BD-09,百度坐标系是在GCJ-02坐标系的基础上再次加密偏移后形成的坐标系,只适用于百度地图;

地图坐标系转换方法:

https://github.com/wandergis/coordTransform_py

分组聚合统计

对数据集进行分组并对各组应用一个函数(无论是聚合还是转换),通常是数据分析工作中的重要环节。在将数据集加载、融合、准备好之后,通常就是计算分组统计或生成透视表。pandas提供了一个灵活高效的gruopby功能,它使你能以一种自然的方式对数据集进行切片、切块、摘要等操作。

关系型数据库和SQL(Structured Query Language,结构化查询语言)能够如此流行的原因之一就是其能够方便地对数据进行连接、过滤、转换和聚合。但是,像SQL这样的查询语言所能执行的分组运算的种类很有限。

通过分组聚合统计,可以完成:

  • 使用一个或多个键(形式可以是函数、数组或DataFrame列名)分割pandas对象。
  • 计算分组的概述统计,比如数量、平均值或标准差,或是用户定义的函数。
  • 应用组内转换或其他运算,如规格化、线性回归、排名或选取子集等。
  • 计算透视表或交叉表。
  • 执行分位数分析以及其它统计分组分析。

Hadley Wickham(许多热门R语言包的作者)创造了一个用于表示分组运算的术语”split-apply-combine”(拆分-应用-合并)。

  • 第一个阶段,pandas对象(无论是Series、DataFrame还是其他的)中的数据会根据你所提供的一个或多个键被拆分(split)为多组。拆分操作是在对象的特定轴上执行的。例如,DataFrame可以在其行(axis=0)或列(axis=1)上进行分组。
  • 将一个函数应用(apply)到各个分组并产生一个新值。
  • 所有这些函数的执行结果会被合并(combine)到最终的结果对象中。结果对象的形式一般取决于数据上所执行的操作。下图大致说明了一个简单的分组聚合过程。

聚合指的是任何能够从数组产生标量值的数据转换过程,比如mean、count、min以及sum等。

地图数据统计(实践)

统计巡游车与网约车分布

下面代码以将以巡游车GPS


taxiGps20190531.csv


为案例进行数据统计:

taxigps2019 = pd.read_csv(INPUT_PATH + 'taxiGps20190531.csv', nrows=MAX_ROWS,
                         dtype = {
                             'DRIVING_DIRECTION': np.uint16,
                             'OPERATING_STATUS': np.uint8,
                             'LONGITUDE': np.float32,
                             'LATITUDE': np.float32,
                             'GPS_SPEED': np.float16 
                         })

taxigps2019 = taxigps2019[taxigps2019.columns[::-1]]
taxigps2019['GPS_TIME'] = pd.to_datetime(taxigps2019['GPS_TIME'])
taxigps2019.sort_values(by=['CARNO','GPS_TIME'], inplace=True)
taxigps2019.reset_index(inplace=True, drop=True)
taxigps2019.head()

  • 统计每辆巡游车最早、最晚出现的记录:
df_first = taxigps2019.groupby(['CARNO']).first()
LATITUDE LONGITUDE GPS_TIME DRIVING_DIRECTION GPS_SPEED OPERATING_STATUS
CARNO
0006d282be70d06881a7513b69fcaa60 24.479755 118.146935 2019-05-31 01:31:20 292 0.000000 1
000e8886a7b27ca761e34d59b1dee35c 24.550379 118.103012 2019-05-31 01:31:38 148 72.187500 6
001df76bfa67259259f596c6dd353e6a 24.499088 118.141182 2019-05-31 01:31:09 278 37.000000 6
001e3756542dc796b402dfd1b56fd4ec 24.471125 118.105560 2019-05-31 01:31:14 346 35.093750 6
002b23a3762ea245f18cc896a55579d2 24.544592 118.102463 2019-05-31 01:31:21 199 0.300049 1
ffe9d9afeabd49c83ef8f7f5f09556cd 24.526094 118.143852 2019-05-31 01:31:50 0 0.000000 1
ffea5e974b86b835b97eea1cd34fe3b8 24.479177 118.150314 2019-05-31 01:31:36 14 0.000000 1
ffedc235a5a3d891139a2d3ec2396b3e 24.482244 118.116447 2019-05-31 01:31:24 32 0.000000 1
fff0bc740b883d541d098f5063e1f43f 24.533218 118.139542 2019-05-31 01:32:01 64 0.000000 1
fff20f025f560278d601b2fd47e1f6b7 24.427284 118.133896 2019-05-31 01:31:26 208 56.812500 1

6768 rows × 6 columns

df_last = taxigps2019.groupby(['CARNO']).last()
LATITUDE LONGITUDE GPS_TIME DRIVING_DIRECTION GPS_SPEED OPERATING_STATUS
CARNO
0006d282be70d06881a7513b69fcaa60 24.498701 118.030182 2019-05-31 23:59:58 54 44.406250 1
000e8886a7b27ca761e34d59b1dee35c 24.538876 118.129890 2019-05-31 23:59:49 232 0.000000 1
001df76bfa67259259f596c6dd353e6a 24.488588 118.157196 2019-05-31 23:59:47 252 30.093750 6
001e3756542dc796b402dfd1b56fd4ec 24.524464 118.147095 2019-05-31 23:59:49 80 12.898438 6
002b23a3762ea245f18cc896a55579d2 24.497768 118.180374 2019-05-31 23:59:45 0 0.000000 1
ffe9d9afeabd49c83ef8f7f5f09556cd 24.526243 118.145790 2019-05-31 23:59:22 275 0.000000 1
ffea5e974b86b835b97eea1cd34fe3b8 24.587500 118.018143 2019-05-31 23:59:19 321 0.000000 1
ffedc235a5a3d891139a2d3ec2396b3e 24.497433 118.136009 2019-05-31 23:59:35 155 0.000000 1
fff0bc740b883d541d098f5063e1f43f 24.533175 118.139519 2019-05-31 23:59:46 61 0.000000 1
fff20f025f560278d601b2fd47e1f6b7 24.457750 118.075989 2019-05-31 23:59:49 334 25.093750 6

6768 rows × 6 columns

  • 统计每辆巡游车最早最晚的时间间隔:
df = df_last['GPS_TIME'] - df_first['GPS_TIME']
df = df.reset_index()

df['GPS_HOUR'] = df['GPS_TIME'].dt.seconds / 3600
df['GPS_HOUR'] = df['GPS_HOUR'].astype(int)
df.set_index('CARNO', inplace=True)
GPS_TIME GPS_HOUR
CARNO
0006d282be70d06881a7513b69fcaa60 22:28:38 22
000e8886a7b27ca761e34d59b1dee35c 22:28:11 22
001df76bfa67259259f596c6dd353e6a 22:28:38 22
001e3756542dc796b402dfd1b56fd4ec 22:28:35 22
002b23a3762ea245f18cc896a55579d2 22:28:24 22
ffe9d9afeabd49c83ef8f7f5f09556cd 22:27:32 22
ffea5e974b86b835b97eea1cd34fe3b8 22:27:43 22
ffedc235a5a3d891139a2d3ec2396b3e 22:28:11 22
fff0bc740b883d541d098f5063e1f43f 22:27:45 22
fff20f025f560278d601b2fd47e1f6b7 22:28:23 22

6768 rows × 2 columns

  • 统计每辆巡游车的经纬度和速度极差:
taxigps2019 = taxigps2019[taxigps2019['LATITUDE'] != 0]
taxigps2019 = taxigps2019[taxigps2019['LONGITUDE'] != 0]

df['LATITUDE_PTP'] = taxigps2019.groupby(['CARNO'])['LATITUDE'].apply(np.ptp)
df['LONGITUDE_PTP'] = taxigps2019.groupby(['CARNO'])['LONGITUDE'].apply(np.ptp)
df['GPS_SPEED_PTP'] = taxigps2019.groupby(['CARNO'])['GPS_SPEED'].apply(np.ptp)

df['LATITUDE_PTP']
# CARNO
# 0006d282be70d06881a7513b69fcaa60    0.082424
# 000e8886a7b27ca761e34d59b1dee35c    0.218086
# 001df76bfa67259259f596c6dd353e6a    0.089241
# 001e3756542dc796b402dfd1b56fd4ec    0.208961
# 002b23a3762ea245f18cc896a55579d2    0.113722
#                                       ...   
# ffe9d9afeabd49c83ef8f7f5f09556cd    0.113094
# ffea5e974b86b835b97eea1cd34fe3b8    0.203405
# ffedc235a5a3d891139a2d3ec2396b3e    0.254045
# fff0bc740b883d541d098f5063e1f43f    0.102463
# fff20f025f560278d601b2fd47e1f6b7    0.188639
# Name: LATITUDE_PTP, Length: 6768, dtype: float64

df['LONGITUDE_PTP']
# CARNO
# 0006d282be70d06881a7513b69fcaa60    0.167244
# 000e8886a7b27ca761e34d59b1dee35c    0.228439
# 001df76bfa67259259f596c6dd353e6a    0.111763
# 001e3756542dc796b402dfd1b56fd4ec    0.176155
# 002b23a3762ea245f18cc896a55579d2    0.113892
#                                       ...   
# ffe9d9afeabd49c83ef8f7f5f09556cd    0.082634
# ffea5e974b86b835b97eea1cd34fe3b8    0.204063
# ffedc235a5a3d891139a2d3ec2396b3e    0.160561
# fff0bc740b883d541d098f5063e1f43f    0.118431
# fff20f025f560278d601b2fd47e1f6b7    0.170204
# Name: LONGITUDE_PTP, Length: 6768, dtype: float64

df['GPS_SPEED_PTP']
# CARNO
# 0006d282be70d06881a7513b69fcaa60     79.6250
# 000e8886a7b27ca761e34d59b1dee35c     90.6875
# 001df76bfa67259259f596c6dd353e6a     74.1250
# 001e3756542dc796b402dfd1b56fd4ec     98.1250
# 002b23a3762ea245f18cc896a55579d2     78.1250
#                                       ...   
# ffe9d9afeabd49c83ef8f7f5f09556cd     85.1250
# ffea5e974b86b835b97eea1cd34fe3b8     83.3125
# ffedc235a5a3d891139a2d3ec2396b3e     98.1250
# fff0bc740b883d541d098f5063e1f43f     87.0000
# fff20f025f560278d601b2fd47e1f6b7    100.6875
# Name: GPS_SPEED_PTP, Length: 6768, dtype: float64
  • 通过统计经纬度是不是全天都为0,我们可以剔除58辆全天GPS都异常的车。
  • 计算一下每辆巡游车的平均经纬度(每天运动的中心),并绘制热力度:
df['LONGITUDE_MEAN'] = taxigps2019.groupby(['CARNO'])['LONGITUDE'].mean()
df['LATITUDE_MEAN'] = taxigps2019.groupby(['CARNO'])['LATITUDE'].mean()
df = df.dropna()

df['LONGITUDE_MEAN']
# CARNO
# 0006d282be70d06881a7513b69fcaa60    118.136398
# 000e8886a7b27ca761e34d59b1dee35c    118.063110
# 001df76bfa67259259f596c6dd353e6a    118.132309
# 001e3756542dc796b402dfd1b56fd4ec    118.124062
# 002b23a3762ea245f18cc896a55579d2    118.137367
#                                        ...    
# ffe9d9afeabd49c83ef8f7f5f09556cd    118.147385
# ffea5e974b86b835b97eea1cd34fe3b8    118.064346
# ffedc235a5a3d891139a2d3ec2396b3e    118.120026
# fff0bc740b883d541d098f5063e1f43f    118.122116
# fff20f025f560278d601b2fd47e1f6b7    118.128235
# Name: LONGITUDE_MEAN, Length: 6764, dtype: float32

df['LATITUDE_MEAN']
# CARNO
# 0006d282be70d06881a7513b69fcaa60    24.498341
# 000e8886a7b27ca761e34d59b1dee35c    24.573448
# 001df76bfa67259259f596c6dd353e6a    24.480791
# 001e3756542dc796b402dfd1b56fd4ec    24.505524
# 002b23a3762ea245f18cc896a55579d2    24.490599
#                                       ...    
# ffe9d9afeabd49c83ef8f7f5f09556cd    24.519753
# ffea5e974b86b835b97eea1cd34fe3b8    24.537611
# ffedc235a5a3d891139a2d3ec2396b3e    24.519087
# fff0bc740b883d541d098f5063e1f43f    24.505892
# fff20f025f560278d601b2fd47e1f6b7    24.480259
# Name: LATITUDE_MEAN, Length: 6764, dtype: float32

学习资源

学习


Pandas


最好的教程是《利用 Python 进行数据分析》,这本书是


Pandas


作者撰写,非常适合大家进行学习。如何用


Pandas


实现的思路,如何实现的又快又好是需要积累经验的。

任务

  • 统计

    20190531

    出租车在LONGITUDE(118.155060±0.01)、LATITUDE(24.506035±0.01)方位内打车的平均等待时间。
taxiOrder = pd.read_csv(
    'data/taxiOrder20190531.csv', 
    dtype = {
        'GETON_LONGITUDE': np.float32,
        'GETON_LATITUDE': np.float32,
        'GETOFF_LONGITUDE': np.float32,
        'GETOFF_LATITUDE': np.float32,
        'PASS_MILE': np.float32,
        'NOPASS_MILE': np.float32,
        'WAITING_TIME': np.float32,
    }
)
taxiOrder = taxiOrder.rename(columns={'CAR_NO': 'CARNO'})
taxiOrder['GETON_DATE'] = pd.to_datetime(taxiOrder['GETON_DATE'])
taxiOrder['GETOFF_DATE'] = pd.to_datetime(taxiOrder['GETOFF_DATE'])
taxiOrder.sort_values(by=['CARNO', 'GETON_DATE'], inplace=True)
taxiOrder.reset_index(inplace=True, drop=True)

df = taxiOrder.loc[
    (taxiOrder['GETON_LONGITUDE'] > (118.155060 - 0.01)) & 
    (taxiOrder['GETON_LONGITUDE'] < (118.155060 + 0.01)) &
    (taxiOrder['GETON_LATITUDE'] > (24.506035 - 0.01)) &
    (taxiOrder['GETON_LATITUDE'] < (24.506035 + 0.01))
]

df['WAITING_TIME'].mean()
# 276.4931945800781
  • 统计

    20190531



    20190609

    期间出租订单经纬度上平均等待时间长的位置(且位置出现评率大于5)。
taxiOrder = []
filenames = [
    'data/taxiOrder20190531.csv', 'data/taxiOrder20190601.csv', 'data/taxiOrder20190602.csv',
    'data/taxiOrder20190603.csv', 'data/taxiOrder20190604.csv', 'data/taxiOrder20190605.csv',
    'data/taxiOrder20190606.csv', 'data/taxiOrder20190607.csv', 'data/taxiOrder20190608.csv',
    'data/taxiOrder20190609.csv'
]
for filename in filenames:
    taxiOrder.append(
        pd.read_csv(
            filename, 
            dtype = {
                'GETON_LONGITUDE': np.float32,
                'GETON_LATITUDE': np.float32,
                'GETOFF_LONGITUDE': np.float32,
                'GETOFF_LATITUDE': np.float32,
                'PASS_MILE': np.float32,
                'NOPASS_MILE': np.float32,
                'WAITING_TIME': np.float32,
            })
    )
taxiOrder = pd.concat(taxiOrder, ignore_index=True)

se_time = taxiOrder.groupby(['GETON_LONGITUDE', 'GETON_LATITUDE'])['WAITING_TIME'].mean().sort_values(ascending=False)
se = taxiOrder.groupby(['GETON_LONGITUDE', 'GETON_LATITUDE']).count()['CAR_NO'].sort_values(ascending=False)

for i, j in enumerate(se_time.index):
    if se[j] > 5:
        print(j, se[j], se_time[j])
        break

# (118.16363525390625, 24.511585235595703) 6 32906.0
  • 对比2019年和2020年出租车端午节订单的平均等待时间,是如何变化的(上升、下降还是不变)?
taxiOrder_2019 = []
taxiOrder_2020 = []
filenames_2019 = [
    'data/taxiOrder20190607.csv', 'data/taxiOrder20190608.csv', 'data/taxiOrder20190609.csv'
]
filenames_2020 = [
    'data/taxiOrder20200625.csv', 'data/taxiOrder20200626.csv', 'data/taxiOrder20200627.csv',
]

for filename in filenames_2019:
    taxiOrder_2019.append(
        pd.read_csv(
            filename, 
            dtype = {
                'GETON_LONGITUDE': np.float32,
                'GETON_LATITUDE': np.float32,
                'GETOFF_LONGITUDE': np.float32,
                'GETOFF_LATITUDE': np.float32,
                'PASS_MILE': np.float32,
                'NOPASS_MILE': np.float32,
                'WAITING_TIME': np.float32,
            })
    )
taxiOrder_2019 = pd.concat(taxiOrder_2019, ignore_index=True)

for filename in filenames_2020:
    taxiOrder_2020.append(
        pd.read_csv(
            filename, 
            dtype = {
                'GETON_LONGITUDE': np.float32,
                'GETON_LATITUDE': np.float32,
                'GETOFF_LONGITUDE': np.float32,
                'GETOFF_LATITUDE': np.float32,
                'PASS_MILE': np.float32,
                'NOPASS_MILE': np.float32,
                'WAITING_TIME': np.float32,
            })
    )
taxiOrder_2020 = pd.concat(taxiOrder_2020, ignore_index=True)

taxiOrder_2019['WAITING_TIME'].mean()
# 243.95602416992188

taxiOrder_2020['WAITING_TIME'].mean()
# 215.83151245117188