SQL,发音为“ sequel”(或SQL,如果愿意的话),是数据科学家的重要工具。实际上,它可以说是获取数据工作中最重要的语言。在共享单车数据分析的SQL设计中,我们将从入门者的角度深入研究SQL基础知识,以使您入门并掌握这一关键技能。
让我们从回答一个简单的问题开始:
什么是SQL?
SQL代表结构化查询语言。查询语言是一种编程语言,旨在促进从数据库中检索特定信息,而这正是SQL所做的。简而言之,SQL是数据库的语言。
这很重要,因为大多数公司将其数据存储在数据库中。尽管数据库类型很多(例如MySQL,PostgreSQL,Microsoft SQL Server),但是大多数数据库都使用SQL,因此一旦掌握了SQL基础知识,便可以使用其中的任何一个。
即使您打算使用Python之类的另一种语言进行分析,在大多数公司中,您仍可能需要使用SQL从公司的数据库中检索所需的数据。在撰写共享单车数据分析的SQL设计时,仅在美国,Indeed上就列出了80,000多个SQL作业。
因此,让我们开始学习SQL!
(如果您希望通过浏览器进行交互学习,编写和运行SQL查询,则应查看我们的SQL基础课程,该课程免费)
为了避免广告的嫌疑,我们选择国外的一个共享单车来举例子,在共享单车数据分析的SQL设计中,我们将使用自行车共享服务Hubway的数据集,其中包括使用该服务进行的超过150万次旅行的数据。
在开始用SQL编写我们自己的一些查询之前,我们将首先看一下数据库,它们是什么以及为什么使用它们。
如果您想继续,可以在这里下载hubway.db文件(130 MB)。
SQL基础:关系数据库
关系数据库是一种数据库,该数据库存储跨多个表的相关信息,并允许您同时查询多个表中的信息。
通过思考一个例子,更容易理解它是如何工作的。假设您是一家企业,并且想要跟踪销售信息。您可以在Excel中设置一个电子表格,在其中您要跟踪的所有信息都以单独的列显示:订单号,日期,到期金额,装运跟踪号,客户名,客户地址和客户电话号码。
此设置可以很好地跟踪所需的信息,但是当您开始从同一位客户那里获得重复订单时,您会发现他们的姓名,地址和电话号码存储在电子表格的多行中。
随着业务的增长和要跟踪的订单数量的增加,这些冗余数据将占用不必要的空间,并通常会降低销售跟踪系统的效率。您可能还会遇到数据完整性问题。例如,不能保证每个字段都将填充正确的数据类型,或者每次都以完全相同的方式输入名称和地址。
与上图中的关系数据库一样,使用关系数据库可以避免所有这些问题。您可以设置两个表,一个用于订单,一个用于客户。“客户”表将包括每个客户的唯一ID号,以及我们已经跟踪的姓名,地址和电话号码。“订单”表将包括您的订单号,日期,应付金额,跟踪号,并且在每个客户数据项中没有一个单独的字段,而是一个客户ID列。
这使我们能够提取任何给定订单的所有客户信息,但是我们只需要在数据库中存储一次即可,而不必为每个订单再次列出它。
我们的数据集
让我们开始看看我们的数据库。该数据库有两个表,trips和stations。首先,我们只看trips表。它包含以下列:
1)id —用作每次旅行的参考的唯一整数
2)duration —行程时间,以秒为单位
3)start_date —旅行开始的日期和时间
4)start_station—一个整数,与该行开始于的车站的表中的id列相对应stations
5)end_date —旅行结束的日期和时间
6)end_station —行程终点站的“ id”
7)bike_number —旅途中所用自行车的Hubway唯一标识符
8)sub_type—用户的订阅类型。"Registered"对于具有成员资格"Casual"的用户,对于没有成员资格的用户
9)zip_code —用户的邮政编码(仅适用于注册会员)
10)birth_date —用户的出生年份(仅适用于注册会员)
11)gender —用户的性别(仅适用于注册会员)
我们的分析
有了这些信息和我们将很快学习的SQL命令,以下是我们在共享单车数据分析的SQL设计中将尝试回答的一些问题:
1)最长旅行的持续时间是多少?
2)“注册”用户进行了多少次旅行?
3)平均旅行时间是多少?
4)注册用户或临时用户旅行更长吗?
5)大多数旅行中使用哪辆自行车?
6)30岁以上的用户平均旅行时间是多少?
我们将用来回答这些问题的SQL命令是:
1)SELECT
2)WHERE
3)LIMIT
4)ORDER BY
5)GROUP BY
6)AND
7)OR
8)MIN
9)MAX
10)AVG
11)SUM
12)COUNT
安装与设定
就共享单车数据分析的SQL设计而言,我们将使用一个名为SQLite3的数据库系统。从2.5版开始,SQLite已经成为Python的一部分,因此,如果您安装了Python,则几乎肯定也会安装SQLite。如果尚未安装Python和SQLite3库,则可以使用Anaconda轻松进行安装和设置。
使用Python运行我们的SQL代码可以使我们将结果导入到Pandas数据框中,从而更易于以易于阅读的格式显示结果。这也意味着我们可以对从数据库中提取的数据进行进一步的分析和可视化,尽管这超出了共享单车数据分析的SQL设计的范围。
另外,如果我们不想使用或安装Python,则可以从命令行运行SQLite3。只需从SQLite3网页下载“预编译的二进制文件”,然后使用以下代码打开数据库:
在这里,我们只需键入要运行的查询,我们将在终端窗口中看到返回的数据。
使用终端的另一种方法是通过Python连接到SQLite数据库。这将使我们能够使用Jupyter笔记本,以便我们可以在格式整齐的表中查看查询的结果。
为此,我们将定义一个函数,该函数将查询(存储为字符串)作为输入并将结果显示为格式化的数据框:
当然,我们不必在SQL中使用Python。如果您已经是R程序员,那么我们的R用户SQL基础知识课程将是一个不错的起点。
选择
我们将使用的第一个命令是SELECT。SELECT将几乎是我们编写的每个查询的基础-它告诉数据库我们要查看哪些列。我们既可以按名称指定列(用逗号分隔),也可以使用通配符*返回表中的每一列。
除了要检索的列之外,我们还必须告诉数据库从哪个表获取它们。为此,我们使用关键字,FROM后跟表名。例如,如果我们想看到的start_date,并bike_number在每行trips表中,我们可以使用下面的查询:
在此示例中,我们从SELECT命令开始,以便数据库知道我们希望它为我们找到一些数据。然后,我们告诉数据库我们对start_date和bike_number列感兴趣。最后,我们过去FROM使数据库知道我们要查看的列是trips表的一部分。
编写SQL查询时要意识到的重要一件事是,我们希望每个查询都以分号(;)结尾。并非每个SQL数据库实际上都需要这样做,但是有些确实需要,所以最好养成这种习惯。
限制
开始在Hubway数据库上运行查询之前,我们需要知道的下一个命令是LIMIT。LIMIT只是告诉数据库您希望它返回多少行。
SELECT我们在上一节中查看的查询将为表中的每一行返回所请求的信息trips,但是有时这可能意味着大量数据。我们可能不想要所有这些。相反,如果我们想看到的start_date,并bike_number在数据库中的第一个五年的旅行,我们可以添加LIMIT到我们的查询,如下所示:
我们仅添加了LIMIT命令,然后添加了一个数字,该数字表示我们要返回的行数。在本例中,我们使用5,但您可以将其替换为任何数字,以获取正在处理的项目的适当数据量。
LIMIT在共享单车数据分析的SQL设计中,我们将在Hubway数据库中的查询中使用很多–该trips表包含超过150万行数据,我们当然不需要显示所有数据!
让我们在Hubway数据库上运行第一个查询。首先,我们将查询存储为字符串,然后使用我们先前定义的函数在数据库上运行它。看下面的例子:
该查询*用作通配符,而不是指定要返回的列。这意味着该SELECT命令已为我们提供了trips表中的每一列。我们还使用该LIMIT函数将输出限制为表的前五行。
您会经常看到人们在查询中使用大写的逗号(这是我们在共享单车数据分析的SQL设计中将遵循的约定),但这主要是优先考虑的问题。大写字母使代码更易于阅读,但实际上丝毫不影响代码的功能。如果您希望使用小写命令编写查询,则查询仍将正确执行。
我们前面的示例返回trips表中的每一列。如果只对duration和start_date列感兴趣,则可以按如下所示用列名替换通配符:
订购
在回答第一个问题之前,我们需要知道的最终命令是ORDER BY。此命令使我们可以对给定列上的数据库进行排序。
要使用它,我们只需指定要排序的列的名称。默认情况下,ORDER BY按升序排序。如果我们想指定数据库应该排序的顺序,我们可以添加关键字ASC以升序或DESC降序。
例如,如果我们想将trips表从最短duration到最长排序,我们可以在查询中添加以下行:
有了SELECT,LIMIT和ORDER BY命令之后,我们现在可以尝试回答第一个问题:最长旅行的持续时间是多少?
要回答这个问题,将其分为几个部分并确定我们需要解决每个部分的命令会很有帮助。
首先,我们需要从表的duration列中提取信息trips。然后,要找出最长的行程,我们可以duration按降序对列进行排序。我们可能会通过以下方式提出一个查询,该查询将获取我们正在寻找的信息:
1)使用SELECT检索duration列FROM的trips表
2)使用ORDER BY排序的duration列,并使用DESC关键字来指定要在降序排序
3)用于LIMIT将输出限制为1行
以这种方式使用这些命令将返回持续时间最长的单行,这将为我们提供问题的答案。
需要注意的另一件事-随着查询添加更多命令并变得更加复杂,如果将它们分成多行,您可能会更容易阅读。就像大写一样,这是个人喜好问题。它不会影响代码的运行方式(系统只是从头开始读取代码,直到到达分号为止),但它可以使您的查询更清晰,更易于理解。在Python中,我们可以使用三引号将字符串分隔为多行。
让我们继续运行此查询,找出最长的旅程持续了多长时间。
现在我们知道最长的旅程持续了9999秒,或者说是166分钟多一点。但是,最大值为9999时,我们不知道这是否真的是最长行程的长度,或者数据库是否仅设置为允许四位数的数字。
如果确实由数据库缩短了特别长的行程,那么我们可能期望在9999秒处看到很多行程,它们达到了极限。让我们尝试运行与之前相同的查询,但是将调整LIMIT为返回10个最长持续时间,以查看是否为这种情况:
我们在这里看到的是,在9999年并没有一整趟旅行,因此看起来我们并没有切断持续时间的高端,但是仍然很难判断这是否是真正的行程跳闸或最大允许值。
Hubway会为30分钟以上的骑行收取额外费用(某人保持9999秒的自行车将不得不支付25美元的额外费用),因此他们认为4位数字足以追踪大多数骑行是合理的。
哪里
前面的命令非常适合提取特定列的排序信息,但是如果我们要查看数据的特定子集,该怎么办?就是这样WHERE。WHERE命令允许我们使用逻辑运算符指定应返回的行。例如,您可以使用以下命令返回bike的每次旅行B00400:
您还会注意到,我们在此查询中使用引号。那是因为bike_number储存为字串。如果该列包含数字数据类型,则不需要引号。
让我们编写一个查询,该查询WHERE用于返回trips表中每一行的每一列,这些查询的duration时间超过9990秒:
如我们所见,此查询返回了14个不同的行程,每个行程持续9990秒或更长。关于此查询的突出之处是,除一个结果外,所有结果都具有sub_type的"Casual"。也许这表明"Registered"用户更了解长途旅行的额外费用。也许Hubway可以更好地向休闲用户传达其价格结构,以帮助他们避免超额收费。
我们已经知道,即使是SQL的初学者级命令也可以如何帮助我们回答业务问题并在数据中寻找见解。
返回到WHERE,我们也可以WHERE使用AND或在子句中组合多个逻辑测试OR。例如,如果在我们之前的查询中,共享单车数据分析的SQL数据库设计https://www.aaa-cg.com.cn/data/2586.html我们只想返回duration超过9990秒的行程,并且还具有已sub_type注册的行程,则可以AND用来指定这两个条件。
这是另一个个人喜好建议:使用括号分隔每个逻辑测试,如下面的代码块所示。这不是代码正常运行所必需的,但是括号会随着您增加复杂性而使您的查询更容易理解。
现在运行该查询。我们已经知道它只能返回一个结果,因此应该容易检查我们是否正确:
我们在帖子开头提出的下一个问题是“'注册'用户进行了多少次旅行?” 为了回答这个问题,我们可以运行与上面相同的查询,并修改WHERE表达式以返回sub_type等于的所有行,'Registered'然后对它们进行递增计数。
但是,SQL实际上有一个内置命令来为我们进行计数COUNT。
COUNT使我们可以将计算转移到数据库,从而省去了编写额外脚本来计算结果的麻烦。要使用它,我们只需要添加(COUNT(column_name)而不是添加)您想要的列即可SELECT,如下所示:
在这种情况下,我们选择对哪一列进行计数都没有关系,因为每一列都应该有查询中每一行的数据。但是有时查询可能缺少某些行的值(或“空”)。如果不确定一列是否包含空值,则可以COUNT在该id列上运行-该id列永远不会为空,因此我们可以确保计数不会遗漏任何内容。
我们还可以使用COUNT(1)或COUNT(*)来计数查询中的每一行。值得注意的是,有时我们实际上可能想COUNT在具有空值的列上运行。例如,我们可能想知道数据库中有多少行缺少一列的值。
让我们看一个查询来回答我们的问题。我们可以SELECT COUNT(*)用来计算返回的总行数,并WHERE sub_type="Registered"确保只计算注册用户的旅行次数。
该查询有效,并且已返回我们问题的答案。但是列标题不是特别描述性的。如果其他人看这张桌子,他们将无法理解它的含义。如果我们想使结果更具可读性,可以使用AS别名(或昵称)作为输出。让我们重新运行上一个查询,但给我们的列标题加上别名Total Trips by Registered Users:
汇总功能
COUNT这不是SQL掌握的唯一数学技巧。我们也可以使用SUM,AVG,MIN和MAX分别返回列的求和,平均值,最小值和最大值。这些与COUNT一起被称为集合函数。
因此,要回答我们的第三个问题,“平均旅行持续时间是多少?” ,我们可以使用列AVG上的函数duration(再次使用AS,为输出列起一个更具描述性的名称):
事实证明,平均旅行持续时间是912秒,大约是15分钟。这是有道理的,因为我们知道Hubway会对30分钟以上的行程收取额外费用。该服务是为骑手短途单程旅行而设计的。
接下来的问题是,注册用户或临时用户旅行更长的时间呢?我们已经知道一种解决此问题的方法-我们可以SELECT AVG(duration) FROM trips使用WHERE子句运行两个查询,这些子句将一个限制到"Registered"一个,一个限制到"Casual"用户。
不过,让我们以不同的方式来做。SQL还包括使用GROUP BY命令在单个查询中回答此问题的方法。
通过...分组
GROUP BY 根据特定列的内容将行分为几组,并允许我们在每个组上执行聚合函数。
为了更好地了解其工作原理,让我们看一下该gender专栏。每行可以有三个可能的值一个gender列,"Male","Female"或Null(丢失;我们没有gender对普通用户的数据)。
当使用时GROUP BY,数据库将根据gender列中的值将每一行分成不同的组,就像我们将一副纸牌分成不同的花色一样。我们可以想象制造两堆,所有雄性之一,所有雌性之一。
一旦我们拥有两个独立的堆,数据库将依次对它们中的每一个执行查询中的任何聚合函数。COUNT例如,如果使用,则查询将计算每个堆中的行数,并分别返回每个堆的值。
让我们详细介绍如何编写查询来回答我们的问题,即注册用户或临时用户是否需要更长的行程。
1)与到目前为止的每个查询一样,我们将从SELECT告诉数据库想要查看哪些信息开始。在这种情况下,我们需要sub_type和AVG(duration)。
2)我们还将包括GROUP BY sub_type按订阅类型分离数据,并分别计算注册用户和临时用户的平均值。
当我们将它们放在一起时,代码如下所示:
完全不同!平均而言,注册用户的出行时间约为11分钟,而休闲用户每次出行的时间则接近25分钟。注册用户可能会进行更短,更频繁的旅行,这可能是他们上下班的一部分。另一方面,休闲用户每次旅行花费的时间大约是两倍。
休闲用户可能来自人口统计学(例如旅游者),他们更倾向于长途旅行,以确保他们四处逛逛并看到所有景点。一旦我们发现了数据的差异,公司便可以通过多种方式对其进行调查,以更好地了解造成这种情况的原因。
但是,出于共享单车数据分析的SQL设计的目的,让我们继续。我们的下一个问题是旅行次数最多的是哪辆自行车?我们可以使用非常相似的查询来回答这个问题。看下面的示例,看看是否可以弄清楚每行的内容-我们将逐步进行操作,以便检查是否正确:
从输出中可以看到,自行车B00490出行最多。让我们来看看如何到达那里:
1)第一行是一个SELECT子句,告诉数据库我们要查看bike_number列和每行的计数。它还AS用于告诉数据库以更有用的名称显示每一列。
2)第二行用于FROM指定我们要查找的数据在trips表中。
3)第三行是开始有些棘手的地方。我们GROUP BY用来告诉第COUNT1行的函数分别计算每个值bike_number。
4)在第四行,我们有一个ORDER BY子句对表格进行降序排序,并确保最常用的自行车在顶部。
5)最后,我们LIMIT将输出限制为第一行,因为我们如何对第四行的数据进行排序,所以我们知道这将是旅行次数最多的自行车。
算术运算符
我们的最后一个问题比其他问题更加棘手。我们想知道30岁以上注册会员的平均旅行时间。
我们可以算出30岁以下的人出生的那一年,然后再插入,但是一个更优雅的解决方案是直接在查询中使用算术运算。SQL允许我们使用+,-,*和/在一次对整个列执行运算。
加入
到目前为止,我们一直在研究仅从trips表中提取数据的查询。但是,SQL之所以如此强大是因为它使我们能够从同一查询中的多个表中提取数据。
我们的自行车共享数据库包含第二个表stations。该stations表包含有关Hubway网络中每个站点的信息,并包括id该trips表引用的列。
不过,在开始研究该数据库中的一些实际示例之前,让我们回顾一下较早的假设订单跟踪数据库。在该数据库中,我们有两个表orders和customers,它们通过customer_id列连接。
假设我们要编写一个查询,该查询返回数据库中的每个订单的order_number和name。如果它们都存储在同一个表中,则可以使用以下查询:
不幸的是,order_number列和name列存储在两个不同的表中,因此我们必须添加一些额外的步骤。让我们花一点时间考虑一下数据库在返回所需信息之前需要了解的其他事项:
1)该order_number列在哪个表中?
2)该name列在哪个表中?
3)orders表中的信息如何与表中的信息连接customers?
要回答这些问题中的前两个,我们可以在SELECT命令中包括每列的表名。我们这样做的方法就是简单地写一个表名和列名,用.。分隔。例如,代替SELECT order_number, name我们会写SELECT orders.order_number, customers.name。在此处添加表名称可以通过告诉数据库要查找的表来帮助数据库查找我们要查找的列。
为了告诉数据库orders和customers表如何连接,我们使用JOIN和ON。JOIN指定应该连接的表,并ON指定每个表中的哪些列相关。
我们将使用内部联接,这意味着将仅在中指定的列匹配的地方返回行ON。在此示例中,我们将要JOIN在FROM命令中未包含的任何表上使用。因此,我们可以使用FROM orders INNER JOIN customers或FROM customers INNER JOIN orders。
如前所述,这些表连接customer_id在每个表的列上。因此,我们将要用来ON告诉数据库,这两列引用的是这样的东西:
我们再次使用.来确保数据库知道这些列中的每一个都在哪个表中。因此,当我们将所有这些放在一起时,我们得到的查询如下所示:
该查询将返回数据库中每个订单的订单号以及与每个订单相关联的客户名称。
回到我们的Hubway数据库,我们现在可以编写一些查询以JOIN进行实际操作。
在开始之前,我们应该看一下表中的其余列stations。这是一个查询,向我们显示了前5行,因此我们可以看到stations表的外观:
1)id—每个工作站的唯一标识符(对应于表中的start_station和end_station列trips)
2)station —站名
3)municipality —车站所在的城市(波士顿,布鲁克林,剑桥或萨默维尔)
4)lat —车站的纬度
5)lng —车站的经度
6)哪些车站最经常往返?
7)在不同的城市中有多少次旅行开始和结束?
与以前一样,我们将尝试回答数据中的一些问题,从哪个站是最频繁的起点开始?让我们逐步进行操作:
1)首先,我们要使用SELECT返回表中的station列stations和COUNT行数。
2)接下来,我们指定我们想要的表JOIN并告诉数据库连接它们ON的start_station列trips表和id列stations的表。
3)然后我们进入查询的内容-我们在表格中GROUP BY的station列,stations以便我们COUNT将分别计算每个车站的行程次数
4)最后,我们可以ORDER BY我们COUNT并LIMIT输出到结果的管理的数量
如果您熟悉波士顿,您将了解为什么这些是最受欢迎的电台。南站是该市主要的通勤火车站之一,查尔斯街沿河延伸,靠近一些风景优美的路线,博伊尔斯顿和信标街就在市中心,靠近许多办公大楼。
我们要看的下一个问题是往返最常用的车站是?我们可以使用与以前几乎相同的查询。我们将以相同的方式SELECT使用相同的输出列和JOIN表,但是这次我们将添加一个WHERE子句以限制我们COUNT的行程start_station与相同end_station。
我们可以看到,这些站点的数量与上一个问题相同,但数量要低得多。最繁忙的站点仍然是最繁忙的站点,但是总体而言,较低的站点表明人们通常在使用Hubway自行车从A点到达B点,而不是在返回起点之前先骑自行车一会儿。
这里有一个明显的不同-Esplande并不是我们第一个查询中总体上最繁忙的车站之一,它似乎是往返行程中最繁忙的车站。为什么?好吧,一张图片值一千个字。当然,这看起来像是骑自行车的好地方:
接下来的问题是:在不同的城市开始和结束多少次旅行?这个问题使事情更进一步。我们想知道在不同的地方开始和结束了多少次旅行municipality。为了实现这一目标,我们需要JOIN的trips表到stations表的两倍。一旦ON该start_station列,然后ON在end_station列。
为此,我们必须为该stations表创建一个别名,以便能够区分与关联的start_station数据和与关联的数据end_station。我们可以使用与为各个列创建别名以使其更直观地显示名称的方式完全相同AS。
例如,我们可以使用下面的代码JOIN的stations表到trips使用的“开始”别名表。然后,我们可以将“开始”与我们的列名称结合使用,.以引用来自此特定对象的数据JOIN(而不是第二个,JOIN我们将处理ON该end_station列):
这是我们运行最终查询时的样子。请注意,我们曾经<>表示“不等于”,但!=也可以使用。
这表明,在150万次旅行中,大约有300,000次(或20%)在与开始的城市不同的地方结束–进一步的证据表明,人们大多使用Hubway自行车进行相对较短的旅行,而不是在城镇之间进行较长的旅行。
如果您已经做到了,那么恭喜!您已经开始掌握SQL的基础知识。我们已经讨论了许多重要的命令,SELECT,LIMIT,WHERE,ORDER BY,GROUP BY和JOIN,以及骨料和算术功能。这些将为您继续SQL之旅提供坚实的基础。
下一步
在完成本入门SQL教程之后,您现在应该能够找到自己感兴趣的数据库并编写查询以提取信息。好的第一步可能是继续使用Hubway数据库,以了解您还能找到什么。以下是您可能想尝试回答的其他一些问题:
1)有多少趟旅程产生了额外的费用(持续时间超过30分钟)?
2)哪辆自行车使用的时间最长?
3)注册用户或临时用户是否往返更多?
4)哪个城市的平均停留时间最长?
如果您想更进一步,请查看我们的交互式SQL课程,该课程涵盖了您从入门到高级SQL所需的一切知识,适用于数据分析师和数据科学家的工作。在数据科学课程页面上的SQL菜单下查找所有交互式SQL课程产品的完整列表。
相关推荐
言
对于Redis而言,很多小伙伴只关注其关键的五大基础类型:string、hash、list、set、sorted set(有序集合),其实还有三种特殊类型在很多应用场景也比较适合使用,分别是:bitmap、geospatial、hyperloglog;上一篇(跟我一起学Redis之五种基本类型及其应用场景举例(干了6个小时))对五种类型进行分享,接下来结合应用场景来说说三种特殊类型的使用方式;
正文
geospatial(地理空间)
该类型在Redis3.2.0版本中加入,其本质是将经纬度通过geohash技术转换成一个值,使用sorted set将其存储;具体内部实现在这里不进行研究,这次主要说应用。
经度(longitude)、维度(latitude)小伙伴肯定不陌生(流泪,当初地理差的一批):
该类型只有六个命令,先简单介绍一下各命令的功能和关键参数:
GEOADD key 经度1 维度1 member1 [经度2 维度2 member2 ...]
GEODIST key member1 member2 [单位]
单位可以指定,如下几种:
m:指定单位为米;
km:指定单位为千米;
mi:指定单位为英里;
ft:指定单位为英尺;
GEOHASH key member1 [member2 ...]
GEOPOS key member1 [member2 ...]
GEORADIUS key 经度 维度 半径 m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
半径后面指定一个单位,m|km|ft|mi指定其中一个;
WITHDIST:在返回查找到位置元素, 同时对应位置元素与中心之间的距离也一并返回。
WITHCOORD:将位置元素的经度和维度也一并返回。
WITHHASH:以 52 位有符号整数的形式返回, 返回位置元素经过原始 geohash 编码的有序集合分值,即一串字符串;
COUNT:代表返回位置信息的条数,类似于分页条数;
GEORADIUSBYMEMBER key member 半径 m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
命令功能及参数说明就简单说这么多(我怕说理论),欲知详情,请小伙伴去官网瞅瞅;
接下来结合应用场景进行命令实战,不然小伙伴要忍不住啦↓↓↓
应用场景实战1
绿色出行,小黄、小蓝、青桔、哈罗各种共享自行车应该已经是很多小伙伴们出行必用了吧,来,先截个哈罗的图看看:
图中显示定位附近的小车,小伙伴可以先想想,如果这个需求给自己,怎么实现?
如果用Redis,这样搞试试:
每一辆共享单车肯定有定位功能,将其定位信息(经纬度)存储到后台管理系统中,这里我们模拟定位信息存储,我们用百度地图坐标拾取器可以取得地图上任意一点的经纬度信息,如下图:
网页地址为:http://api.map.baidu.com/lbsapi/getpoint/index.html
模拟共享单车定位信息存储到后台Redis:
当我们打开手机时,App同样会通过手机进行定位,比如得到对应位置的经纬度信息为:113.768365(经度),34.724814(纬度),这样就可以指定用户的定位信息为中心,去查找附近指定半径的单车,然后将其标注在地图上:
应用场景实战2
再来一个需求,比如说微信附近的人,直播APP附近直播的播友,还有某陌附近的美女,如下图:
如果用Redis实现,同样是通过APP(比如微信)将用户的定位信息保存到后台Redis中,这里还是使用百度地图拾取器的方式取得位置信息模拟将定位信息保存在Redis:
附近餐馆、附近加油站、附近酒店同样的原理,最后关于具体的信息可以通过得到信息(比如说用户ID、共享单车标识等)去存储详细信息的数据库中查询。
bitmap
bitmap在Redis2.2.0版本加入,其并不是一种实际的数据类型,而是在字符串类型基础上定义的一组面向位的操作。因为字符串是二进制安全的blob,对应value能存储的最大长度是512 MB,即可以设置2^32个不同的位;大概的结构如下:
实践出真理,看看其类型到底是不是string类型:
常用命令如下:
SETBIT key offset value
GETBIT key offset
BITCOUNT key [start end]
BITOP operation destkey key [key ...]
operation 可以指定对应的运算方式,运算的结果存入destkey中;
BITPOS key bit [start] [end]
模拟应用场景实战:
bitmap由于存储的值只能是0或1,所以很适合两种状态的数据记录和分析,比如说是否签到,是否登录,然后通过签到记录的数据可以统计周、月、年签到数,通过登录的数据可以分析用户是否活跃;
应用场景用户签到
比如某多多连续签到送现金、运动打卡App(比如Keep)、学习打卡App或者小程序,都会有对打卡数据的统计,如下图某音极速版连续签到送积分:
如果用Redis实现,如下:
应用场景用户登录即用户活跃分析:
如下统计逻辑:
bitmap适合数据量比较大的场景,如果数据几十上千,用bitmap反而相对比较占空间,直接使用用户ID作为Key使用set存储,但是如果数据量大时,Key值所占空间比较大,比较浪费,而bitmap用512M内存就能标识40亿数据状态;当然,不介意bitmap的位数很大,设置或分析数据的时候可能会导致堵塞,所以当位数很大时,建议将其拆分为多个Key,保证分析的高效。
先休息一下,晃晃头,眨巴眨巴眼睛,然后继续往下↓↓↓
hyperloglog
先说说什么是基数?
基数(cardinal number)在数学上,是集合论中刻画任意集合大小的一个概念。两个能够建立元素间一一对应的集合称为互相对等集合。例如3个人的集合和3匹马的集合可以建立一一对应,是两个对等的集合。 百度百科 比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。 基数估计就是在误差可接受的范围内,快速计算基数。 菜鸟教程
通俗一点就是不重复元素的个数(这是个人通俗的理解),先到这,实战再来回顾这句话;
hyperloglog是一种概率数据统计结构,适合超大数据量的基数统计,速度快,而且空间占用小,;但是统计的结果存在低于1%的误差,如果需要的是精确统计的话,使用基础类型set进行统计也不错,但当统计元素比较多时,内存占用空间会增大,毕竟用空间换精确度嘛。
和bitmap感觉很像,都适合大数据量的统计,但是bitmap还关注统计对象,比如说谁签到多少次,而hyperloglog只进行基数统计,不关注是谁进行签到;比如常听到UV统计场景,即一个页面,一个用户访问多次,也只算一次,最后只关注这个页面被多少用户访问,而不在乎是谁访问;微信公众号文章的统计也是针对用户统计的,同一个用户不管访问几次,只算一次阅读;
常用命令:
PFADD key element [element ...]
PFCOUNT key [key ...]
如果指定多个HyperLogLog ,返回它们并集近似基数,存在低于1%的误差;
PFMERGE destkey sourcekey [sourcekey ...]
模拟应用场景
模拟页面UV统计,即用户访问数,不注重是谁访问:
模拟App应用市场下载数,比如某音下载量都好几亿了,这个肯定不关心是谁下载吧,只关心下载数量来衡量应用参数;
总结
先到这吧,这篇总耗时又搞了几个小时,上文中应用场景模拟只是给小伙伴提供思路,小伙伴可以根据需求进行设计;下一遍说说配置文件;
一个被程序搞丑的帅小伙,关注"Code综艺圈",识别关注跟我一起学~~~
目前最新的共享单车公开数据可能只有深圳市政府数据开放平台[1]发布的共享单车企业每日订单表了,数据量包含2017-04-03到2021-08-30的 2.4 亿条数据,总计约 24G 大小:
《深圳共享单车企业每日订单表》在数据库中情况
深圳真不愧是改革先行者,公开的数据量如此庞大。
如此大量的数据,肯定不能直接下载。直接下载的文件仅包含本数据集的前 10 万条数据。
每条数据包含的字段:
USER_ID用户 idCOM_ID企业 idSTART_TIME开始时间START_LNG开始经度START_LAT开始纬度END_TIME结束时间END_LNG结束经度END_LAT结束纬度
深圳数据开放平台也提供调用数据接口的方式进行下载:
数据接口(APIs) 是现代编程的基础,可以通过多种编程语言和工具实现。JavaScript、Python等多种编程语言和工具都可以调用 Api。
每种方法都有其特定的使用场景和优势。选择哪种方法取决于你的项目需求、所用技术栈以及个人或团队的熟悉程度。例如,如果你正在开发一个 Web 应用,JavaScript 可能是最直接的选择;如果是企业级后端系统,Java 或 C#可能更合适。对于脚本或自动化任务,Python 或 Shell 命令可能是最简单的方法。
我们选用简洁性、受欢迎的 Python 来进行数据获取,使用的方法是requests库,或者可以使用http.client或第三方库如aiohttp(异步请求)。
具体调用说明见网站[2]上的【调用说明】。
如此庞大的数据我们肯定不能全保存在 Json 或者 csv 文件中,对于共享单车订单分析这样的大数据量场景(2.7 亿条数据),我们需要选择合适的数据库。
订单数据包括时间序列和地理空间数据,因此需要一个既能高效处理大规模数据集,又支持时间和空间查询的数据库。
以下是一些推荐的数据库选项:
另外根据我对数据库的熟悉情况,我选择MongoDB来储存我的数据库。
所以我们只需要用 Python 写一个requests请求,然后将数据储存到数据库。
花了一点时间(实际在我的树莓派上静静地跑了一天程序)之后,获取了全部 24G 的数据。
若有按时间获取数据的需求,可通过增加 startDate 和 endDate 参数对数据进行筛选。你可以
接下来简单来探索下深圳市共享单车服务的使用情况。
这次先取一天——2021 年 8 月 5 号的数据。
将坐标统一为 GPS 坐标后我们进行简单的可视化,如下图,每个红色点代表一个共享单车的出发点:
这天的订单数据共计超过一百万条,并且每条数据包含订单的开始和结束的时间以及经纬度信息,当然其中有很多离群值,需要进一步筛选,也就是数据清洗。
由于没有提供开关锁的状态,无法从订单状态筛选数据,通过观察发现可以从订单的距离、平均速度、起终点是否在深圳市进行数据清洗。
我直接删除了订单距离为 0 米以及订单距离大于 40km 的数据,总的数据量从 1158199 减少到 1132736。
我们用这部分数据进行共享单车的使用模式分析,还能结合空间分布,进行一定程度的空间数据分析。
所以,我们的先对数据进行描述,可以重点关注了骑行时间、骑行次数、以及骑行距离的分布情况。
观察共享单车的使用时间,我们发现了城市生活的节奏。早晚高峰时段的数据高峰,不仅反映了上下班的人潮,还揭示了车辆分配和维护的最佳时机。
这张图是一个柱状图,显示了 2021 年 8 月 5 日深圳市共享单车订单在 24 小时内的分布情况。横轴代表一天中的小时(从 0 点到 23 点),纵轴代表订单数量。
从图中可以观察到,在早上的某个时段(8 点左右)有一个明显的订单数量峰值,大家开始上班了。随后的几个小时内,订单数量逐渐下降,直到下午时段(16 点到 17 点之间)订单数量再次上升,形成第二个高峰,这可能与人们下班的时间相对应。到了晚上,订单数量逐渐减少,直到深夜时段达到最低点。
这样的分析有助于共享单车运营商了解用户的使用模式,从而更有效地调配车辆,确保在需求高峰时有足够的车辆可供使用。
通过统计不同区域的骑行次数,我们绘制出了城市的热力图。
将热力图保存为 html 网页,此网页有 30M 大小,在线访问速度可能很慢,想要的可以关注微信公众号“renhai-lab”发送“深圳共享单车热力图 1”获取网页的下载链接。
热力图演示
3.出行距离分布
出行距离分布
这张图包含了四个子图,它们显示了不同规模的数据分布情况。每个子图都有一个 X 轴,表示“骑行距离(米)”,和一个 Y 轴,表示“概率”。这些图似乎是概率密度函数(PDF)的图形表示,每个子图覆盖不同的骑行距离范围,展示了共享单车骑行距离的分布情况。
在这些子图中,可以观察到随着骑行距离的增加,概率逐渐下降,这表明短距离骑行的频率较高。这是符合预期的,因为人们通常倾向于使用共享单车进行短途出行。随着距离的增加,选择骑行的用户可能会减少,从而导致概率下降。这些图可能用于分析骑行距离的典型值,从而帮助共享单车公司优化他们的车辆分布和调度策略。
以上仅为一部分数据分析工作,我们还可以绘制平均出行时间图、交通小区之间的出行量、共享单车的起点-终点图(OD 图),例如绘制全市 OD 图获取、单个站点的 OD 图,例如下图是上海某日共享单车到达某地铁站点衔接图——图源自《交通时空大数据分析、挖掘与可视化(Python版)[15],描述的是同济大学地铁站周边共享单车换乘地铁的分布图。
今天先写到这,此文章会在我的博客[16]更新,可以点击阅读原文[17]访问。
如果你对本文章有什么意见、对如何制作文中的图表感兴趣、或者有其它任何问题可以在博客的评论区留言,或者通过微信公众号发送私信给我。
renhailab
1.深圳市共享单车企业每日订单表
数据简介:深圳市政府数据开放平台[22]发布的共享单车企业每日订单表了,数据量包含 2.4 亿条数据。
时间:2017-04-03到2021-08-30
链接:https://opendata.sz.gov.cn/data/dataSet/toDataDetails/29200_00403627
数据预览:
搜索数据的时候发现有人已经整合过了:以内容下由微信公众号【立方数据学社】发表在【数据分享】8 个城市的共享单车数据(数据量约 10 亿条\免费获取),本文选了国内的城市,国外的数据可以访问原文查看。
时间: 2016年8月
数据简介: 和鲸社区用户分享的共享单车数据,包括上海市2016年8月的摩拜单车数据,共十万余条。
数据字段: 订单编号、车辆编号、用户编号、起始时间、起始位置、结束时间、结束位置、轨迹。
数据简介:2017 摩拜算法挑战赛公布的共享单车数据,包括北京市 2017 年 5 月两周之内 40 余万共享单车被 30 多万用户使用的情况,包括 300 余万条出行记录。
数据字段:订单号、用户 ID、车辆 ID、车辆类型、骑行起始日期时间、骑行起始区块位置、骑行目的地区块位置
数据简介:2021 数字中国创新大赛公布的厦门市 2020 年 12 月 21 日-2020 年 12 月 25 日五天的共享单车轨迹数据。
数据字段:共享单车 ID、定位时间、经度(WGS84 坐标)、纬度(WGS84 坐标)、共享单车来源
*请认真填写需求信息,我们会在24小时内与您取得联系。