• 关于

    颜色特征可以做什么

    的搜索结果

回答

这周我们将学习神经网络的基础知识,其中需要注意的是,当实现一个神经网络的时候,我们需要知道一些非常重要的技术和技巧。例如有一个包含个样本的训练集,你很可能习惯于用一个for循环来遍历训练集中的每个样本,但是当实现一个神经网络的时候,我们通常不直接使用for循环来遍历整个训练集,所以在这周的课程中你将学会如何处理训练集。 另外在神经网络的计算中,通常先有一个叫做前向暂停(forward pause)或叫做前向传播(foward propagation)的步骤,接着有一个叫做反向暂停(backward pause) 或叫做反向传播(backward propagation)的步骤。所以这周我也会向你介绍为什么神经网络的训练过程可以分为前向传播和反向传播两个独立的部分。 在课程中我将使用逻辑回归(logistic regression)来传达这些想法,以使大家能够更加容易地理解这些概念。即使你之前了解过逻辑回归,我认为这里还是有些新的、有趣的东西等着你去发现和了解,所以现在开始进入正题。 逻辑回归是一个用于二分类(binary classification)的算法。首先我们从一个问题开始说起,这里有一个二分类问题的例子,假如你有一张图片作为输入,比如这只猫,如果识别这张图片为猫,则输出标签1作为结果;如果识别出不是猫,那么输出标签0作为结果。现在我们可以用字母 来 表示输出的结果标签,如下图所示: 我们来看看一张图片在计算机中是如何表示的,为了保存一张图片,需要保存三个矩阵,它们分别对应图片中的红、绿、蓝三种颜色通道,如果你的图片大小为64x64像素,那么你就有三个规模为64x64的矩阵,分别对应图片中红、绿、蓝三种像素的强度值。为了便于表示,这里我画了三个很小的矩阵,注意它们的规模为5x4 而不是64x64,如下图所示: 为了把这些像素值放到一个特征向量中,我们需要把这些像素值提取出来,然后放入一个特征向量。为了把这些像素值转换为特征向量 ,我们需要像下面这样定义一个特征向量 来表示这张图片,我们把所有的像素都取出来,例如255、231等等,直到取完所有的红色像素,接着最后是255、134、…、255、134等等,直到得到一个特征向量,把图片中所有的红、绿、蓝像素值都列出来。如果图片的大小为64x64像素,那么向量 的总维度,将是64乘以64乘以3,这是三个像素矩阵中像素的总量。在这个例子中结果为12,288。现在我们用,来表示输入特征向量的维度,有时候为了简洁,我会直接用小写的来表示输入特征向量的维度。所以在二分类问题中,我们的目标就是习得一个分类器,它以图片的特征向量作为输入,然后预测输出结果为1还是0,也就是预测图片中是否有猫: 最后为了能把训练集表示得更紧凑一点,我们会定义一个矩阵用大写的表示,它由输入向量、等组成,如下图放在矩阵的列中,所以现在我们把作为第一列放在矩阵中,作为第二列,放到第列,然后我们就得到了训练集矩阵。所以这个矩阵有列,是训练集的样本数量,然后这个矩阵的高度记为,注意有时候可能因为其他某些原因,矩阵会由训练样本按照行堆叠起来而不是列,如下图所示:的转置直到的转置,但是在实现神经网络的时候,使用左边的这种形式,会让整个实现的过程变得更加简单: 现在来简单温习一下:是一个规模为乘以的矩阵,当你用Python实现的时候,你会看到X.shape,这是一条Python命令,用于显示矩阵的规模,即X.shape等于,是一个规模为乘以的矩阵。所以综上所述,这就是如何将训练样本(输入向量的集合)表示为一个矩阵。 那么输出标签呢?同样的道理,为了能更加容易地实现一个神经网络,将标签放在列中将会使得后续计算非常方便,所以我们定义大写的等于,所以在这里是一个规模为1乘以的矩阵,同样地使用Python将表示为Y.shape等于,表示这是一个规模为1乘以的矩阵。 当你在后面的课程中实现神经网络的时候,你会发现,一个好的符号约定能够将不同训练样本的数据很好地组织起来。而我所说的数据不仅包括 或者 还包括之后你会看到的其他的量。将不同的训练样本的数据提取出来,然后就像刚刚我们对 或者 所做的那样,将他们堆叠在矩阵的列中,形成我们之后会在逻辑回归和神经网络上要用到的符号表示。如果有时候你忘了这些符号的意思,比如什么是 ,或者什么是 ,或者忘了其他一些东西,我们也会在课程的网站上放上符号说明,然后你可以快速地查阅每个具体的符号代表什么意思,好了,我们接着到下一个视频,在下个视频中,我们将以逻辑回归作为开始。 备注:附录里也写了符号说明。

因为相信,所以看见。 2020-05-20 12:39:45 0 浏览量 回答数 0

问题

我也想写点什么

猥琐屯公爵 2019-12-01 21:55:06 6158 浏览量 回答数 2

问题

【精品问答】Java必备核心知识1000+(附源码)

问问小秘 2019-12-01 22:00:28 870 浏览量 回答数 1

阿里云试用中心,为您提供0门槛上云实践机会!

0元试用32+款产品,最高免费12个月!拨打95187-1,咨询专业上云建议!

问题

Web测试方法

技术小菜鸟 2019-12-01 21:41:32 7022 浏览量 回答数 1

回答

逻辑回归 逻辑回归实际上是一种分类算法。我怀疑它这样命名是因为它与线性回归在学习方法上很相似,但是成本和梯度函数表述不同。特别是,逻辑回归使用了一个sigmoid或“logit”激活函数,而不是线性回归的连续输出。 首先导入和检查我们将要处理的数据集。 import numpy as np import pandas as pd import matplotlib.pyplot as plt %matplotlib inline import os path = os.getcwd() + '\data\ex2data1.txt' data = pd.read_csv(path, header=None, names=['Exam 1', 'Exam 2', 'Admitted']) data.head() 在数据中有两个连续的自变量——“Exam 1”和“Exam 2”。我们的预测目标是“Admitted”的标签。值1表示学生被录取,0表示学生没有被录取。我们看有两科成绩的散点图,并使用颜色编码来表达例子是positive或者negative。 positive = data[data['Admitted'].isin([1])] negative = data[data['Admitted'].isin([0])] fig, ax = plt.subplots(figsize=(12,8)) ax.scatter(positive['Exam 1'], positive['Exam 2'], s=50, c='b', marker='o', label='Admitted') ax.scatter(negative['Exam 1'], negative['Exam 2'], s=50, c='r', marker='x', label='Not Admitted') ax.legend() ax.set_xlabel('Exam 1 Score') ax.set_ylabel('Exam 2 Score') 从这个图中我们可以看到,有一个近似线性的决策边界。它有一点弯曲,所以我们不能使用直线将所有的例子正确地分类,但我们能够很接近。现在我们需要实施逻辑回归,这样我们就可以训练一个模型来找到最优决策边界,并做出分类预测。首先需要实现sigmoid函数。 def sigmoid(z): return 1 / (1 + np.exp(-z)) 这个函数是逻辑回归输出的“激活”函数。它将连续输入转换为0到1之间的值。这个值可以被解释为分类概率,或者输入的例子应该被积极分类的可能性。利用带有界限值的概率,我们可以得到一个离散标签预测。它有助于可视化函数的输出,以了解它真正在做什么。 nums = np.arange(-10, 10, step=1) fig, ax = plt.subplots(figsize=(12,8)) ax.plot(nums, sigmoid(nums), 'r') 我们的下一步是写成本函数。成本函数在给定一组模型参数的训练数据上评估模型的性能。这是逻辑回归的成本函数。 def cost(theta, X, y): theta = np.matrix(theta) X = np.matrix(X) y = np.matrix(y) first = np.multiply(-y, np.log(sigmoid(X * theta.T))) second = np.multiply((1 - y), np.log(1 - sigmoid(X * theta.T))) return np.sum(first - second) / (len(X)) 注意,我们将输出减少到单个标量值,该值是“误差”之和,是模型分配的类概率与示例的真实标签之间差别的量化函数。该实现完全是向量化的——它在语句(sigmoid(X * theta.T))中计算模型对整个数据集的预测。 测试成本函数以确保它在运行,首先需要做一些设置。 # add a ones column - this makes the matrix multiplication work out easier data.insert(0, 'Ones', 1) # set X (training data) and y (target variable) cols = data.shape[1] X = data.iloc[:,0:cols-1] y = data.iloc[:,cols-1:cols] # convert to numpy arrays and initalize the parameter array theta X = np.array(X.values) y = np.array(y.values) theta = np.zeros(3) 检查数据结构的形状,以确保它们的值是合理的。这种技术在实现矩阵乘法时非常有用 X.shape, theta.shape, y.shape ((100L, 3L), (3L,), (100L, 1L)) 现在计算初始解的成本,将模型参数“theta”设置为零。 cost(theta, X, y) 0.69314718055994529 我们已经有了工作成本函数,下一步是编写一个函数,用来计算模型参数的梯度,以找出改变参数来提高训练数据模型的方法。在梯度下降的情况下,我们不只是在参数值周围随机地jigger,看看什么效果最好。并且在每次迭代训练中,我们通过保证将其移动到减少训练误差(即“成本”)的方向来更新参数。我们可以这样做是因为成本函数是可微分的。这是函数。 def gradient(theta, X, y): theta = np.matrix(theta) X = np.matrix(X) y = np.matrix(y) parameters = int(theta.ravel().shape[1]) grad = np.zeros(parameters) error = sigmoid(X * theta.T) - y for i in range(parameters): term = np.multiply(error, X[:,i]) grad[i] = np.sum(term) / len(X) return grad 我们并没有在这个函数中执行梯度下降——我们只计算一个梯度步骤。在练习中,使用“fminunc”的Octave函数优化给定函数的参数,以计算成本和梯度。因为我们使用的是Python,所以我们可以使用SciPy的优化API来做同样的事情。 import scipy.optimize as opt result = opt.fmin_tnc(func=cost, x0=theta, fprime=gradient, args=(X, y)) cost(result[0], X, y) 0.20357134412164668 现在我们的数据集里有了最优模型参数,接下来我们要写一个函数,它使用我们训练过的参数theta来输出数据集X的预测,然后使用这个函数为我们分类器的训练精度打分。 def predict(theta, X): probability = sigmoid(X * theta.T) return [1 if x >= 0.5 else 0 for x in probability] theta_min = np.matrix(result[0]) predictions = predict(theta_min, X) correct = [1 if ((a == 1 and b == 1) or (a == 0 and b == 0)) else 0 for (a, b) in zip(predictions, y)] accuracy = (sum(map(int, correct)) % len(correct)) print 'accuracy = {0}%'.format(accuracy) accuracy = 89% 我们的逻辑回归分类器预测学生是否被录取的准确性可以达到89%,这是在训练集中的精度。我们没有保留一个hold-out set或使用交叉验证来获得准确的近似值,所以这个数字可能高于实际的值。 正则化逻辑回归 既然我们已经有了逻辑回归的工作实现,我们将通过添加正则化来改善算法。正则化是成本函数的一个条件,使算法倾向于更简单的模型(在这种情况下,模型会减小系数),原理就是帮助减少过度拟合和帮助模型提高通用化能力。我们使用逻辑回归的正则化版本去解决稍带挑战性的问题, 想象你是工厂的产品经理,你有一些芯片在两种不同测试上的测试结果。通过两种测试,你将会决定那种芯片被接受或者拒绝。为了帮助你做这个决定,你将会有以往芯片的测试结果数据集,并且通过它建立一个逻辑回归模型。 现在可视化数据。 path = os.getcwd() + '\data\ex2data2.txt' data2 = pd.read_csv(path, header=None, names=['Test 1', 'Test 2', 'Accepted']) positive = data2[data2['Accepted'].isin([1])] negative = data2[data2['Accepted'].isin([0])] fig, ax = plt.subplots(figsize=(12,8)) ax.scatter(positive['Test 1'], positive['Test 2'], s=50, c='b', marker='o', label='Accepted') ax.scatter(negative['Test 1'], negative['Test 2'], s=50, c='r', marker='x', label='Rejected') ax.legend() ax.set_xlabel('Test 1 Score') ax.set_ylabel('Test 2 Score') 这个数据看起来比以前的例子更复杂,你会注意到没有线性决策线,数据也执行的很好,处理这个问题的一种方法是使用像逻辑回归这样的线性技术,就是构造出由原始特征多项式派生出来的特征。我们可以尝试创建一堆多项式特性以提供给分类器。 degree = 5 x1 = data2['Test 1'] x2 = data2['Test 2'] data2.insert(3, 'Ones', 1) for i in range(1, degree): for j in range(0, i): data2['F' + str(i) + str(j)] = np.power(x1, i-j) * np.power(x2, j) data2.drop('Test 1', axis=1, inplace=True) data2.drop('Test 2', axis=1, inplace=True) data2.head() 现在我们需要去修改成本和梯度函数以包含正则项。在这种情况下,将正则化矩阵添加到之前的计算中。这是更新后的成本函数。 def costReg(theta, X, y, learningRate): theta = np.matrix(theta) X = np.matrix(X) y = np.matrix(y) first = np.multiply(-y, np.log(sigmoid(X * theta.T))) second = np.multiply((1 - y), np.log(1 - sigmoid(X * theta.T))) reg = (learningRate / 2 * len(X)) * np.sum(np.power(theta[:,1:theta.shape[1]], 2)) return np.sum(first - second) / (len(X)) + reg 我们添加了一个名为“reg”的新变量,它是参数值的函数。随着参数越来越大,对成本函数的惩罚也越来越大。我们在函数中添加了一个新的“learning rate”参数。 这也是等式中正则项的一部分。 learning rate为我们提供了一个新的超参数,我们可以使用它来调整正则化在成本函数中的权重。 接下来,我们将在梯度函数中添加正则化。 def gradientReg(theta, X, y, learningRate): theta = np.matrix(theta) X = np.matrix(X) y = np.matrix(y) parameters = int(theta.ravel().shape[1]) grad = np.zeros(parameters) error = sigmoid(X * theta.T) - y for i in range(parameters): term = np.multiply(error, X[:,i]) if (i == 0): grad[i] = np.sum(term) / len(X) else: grad[i] = (np.sum(term) / len(X)) + ((learningRate / len(X)) * theta[:,i]) return grad 与成本函数一样,将正则项加到最初的计算中。与成本函数不同的是,我们包含了确保第一个参数不被正则化的逻辑。这个决定背后的直觉是,第一个参数被认为是模型的“bias”或“intercept”,不应该被惩罚。 我们像以前那样测试新函数 # set X and y (remember from above that we moved the label to column 0) cols = data2.shape[1] X2 = data2.iloc[:,1:cols] y2 = data2.iloc[:,0:1] # convert to numpy arrays and initalize the parameter array theta X2 = np.array(X2.values) y2 = np.array(y2.values) theta2 = np.zeros(11) learningRate = 1 costReg(theta2, X2, y2, learningRate) 0.6931471805599454 我们能使用先前的最优代码寻找最优模型参数。 result2 = opt.fmin_tnc(func=costReg, x0=theta2, fprime=gradientReg, args=(X2, y2, learningRate)) result2 (数组([ 0.35872309, -3.22200653, 18.97106363, -4.25297831, 18.23053189, 20.36386672, 8.94114455, -43.77439015, -17.93440473, -50.75071857, -2.84162964]), 110, 1) 最后,我们可以使用前面应用的相同方法,为训练数据创建标签预测,并评估模型的性能。 theta_min = np.matrix(result2[0]) predictions = predict(theta_min, X2) correct = [1 if ((a == 1 and b == 1) or (a == 0 and b == 0)) else 0 for (a, b) in zip(predictions, y2)] accuracy = (sum(map(int, correct)) % len(correct)) print 'accuracy = {0}%'.format(accuracy) 准确度 = 91%

珍宝珠 2019-12-02 03:22:33 0 浏览量 回答数 0

回答

有多种方法可以从数据库的多个表中检索数据。在此答案中,我将使用ANSI-92连接语法。这可能与其他使用较旧的ANSI-89语法的其他教程有所不同(如果您习惯使用89,可能看起来不那么直观-但我只能说尝试一下),因为它更容易了解查询何时开始变得更复杂。为什么要使用它?有性能提升吗?在简短的回答是否定的,但它是更易于阅读,一旦你习惯了它。使用此语法更容易读取其他人编写的查询。 我还将使用小型堆场的概念,该堆场具有一个数据库来跟踪其可用的汽车。所有者已将您雇用为他的IT计算机人员,并希望您能够一口气就把他要求的数据丢给他。 我制作了许多最终表将使用的查找表。这将为我们提供一个合理的工作模型。首先,我将对具有以下结构的示例数据库运行查询。我将尝试思考刚开始时所犯的常见错误,并解释错误的根源-以及当然会显示如何纠正错误。 第一张桌子只是一个颜色列表,以便我们知道车场中的颜色。 mysql> create table colors(id int(3) not null auto_increment primary key, -> color varchar(15), paint varchar(10)); Query OK, 0 rows affected (0.01 sec) mysql> show columns from colors; +-------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+----------------+ | id | int(3) | NO | PRI | NULL | auto_increment | | color | varchar(15) | YES | | NULL | | | paint | varchar(10) | YES | | NULL | | +-------+-------------+------+-----+---------+----------------+ 3 rows in set (0.01 sec) mysql> insert into colors (color, paint) values ('Red', 'Metallic'), -> ('Green', 'Gloss'), ('Blue', 'Metallic'), -> ('White' 'Gloss'), ('Black' 'Gloss'); Query OK, 5 rows affected (0.00 sec) Records: 5 Duplicates: 0 Warnings: 0 mysql> select * from colors; +----+-------+----------+ | id | color | paint | +----+-------+----------+ | 1 | Red | Metallic | | 2 | Green | Gloss | | 3 | Blue | Metallic | | 4 | White | Gloss | | 5 | Black | Gloss | +----+-------+----------+ 5 rows in set (0.00 sec) 品牌表标识了车库外可能出售的汽车的不同品牌。 mysql> create table brands (id int(3) not null auto_increment primary key, -> brand varchar(15)); Query OK, 0 rows affected (0.01 sec) mysql> show columns from brands; +-------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+----------------+ | id | int(3) | NO | PRI | NULL | auto_increment | | brand | varchar(15) | YES | | NULL | | +-------+-------------+------+-----+---------+----------------+ 2 rows in set (0.01 sec) mysql> insert into brands (brand) values ('Ford'), ('Toyota'), -> ('Nissan'), ('Smart'), ('BMW'); Query OK, 5 rows affected (0.00 sec) Records: 5 Duplicates: 0 Warnings: 0 mysql> select * from brands; +----+--------+ | id | brand | +----+--------+ | 1 | Ford | | 2 | Toyota | | 3 | Nissan | | 4 | Smart | | 5 | BMW | +----+--------+ 5 rows in set (0.00 sec) 模型表将涵盖不同类型的汽车,使用不同类型的汽车而不是实际的汽车模型会更简单。 mysql> create table models (id int(3) not null auto_increment primary key, -> model varchar(15)); Query OK, 0 rows affected (0.01 sec) mysql> show columns from models; +-------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+----------------+ | id | int(3) | NO | PRI | NULL | auto_increment | | model | varchar(15) | YES | | NULL | | +-------+-------------+------+-----+---------+----------------+ 2 rows in set (0.00 sec) mysql> insert into models (model) values ('Sports'), ('Sedan'), ('4WD'), ('Luxury'); Query OK, 4 rows affected (0.00 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql> select * from models; +----+--------+ | id | model | +----+--------+ | 1 | Sports | | 2 | Sedan | | 3 | 4WD | | 4 | Luxury | +----+--------+ 4 rows in set (0.00 sec) 最后,要捆绑所有其他表,该表将所有内容捆绑在一起。ID字段实际上是用于识别汽车的唯一批号。 mysql> create table cars (id int(3) not null auto_increment primary key, -> color int(3), brand int(3), model int(3)); Query OK, 0 rows affected (0.01 sec) mysql> show columns from cars; +-------+--------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+--------+------+-----+---------+----------------+ | id | int(3) | NO | PRI | NULL | auto_increment | | color | int(3) | YES | | NULL | | | brand | int(3) | YES | | NULL | | | model | int(3) | YES | | NULL | | +-------+--------+------+-----+---------+----------------+ 4 rows in set (0.00 sec) mysql> insert into cars (color, brand, model) values (1,2,1), (3,1,2), (5,3,1), -> (4,4,2), (2,2,3), (3,5,4), (4,1,3), (2,2,1), (5,2,3), (4,5,1); Query OK, 10 rows affected (0.00 sec) Records: 10 Duplicates: 0 Warnings: 0 mysql> select * from cars; +----+-------+-------+-------+ | id | color | brand | model | +----+-------+-------+-------+ | 1 | 1 | 2 | 1 | | 2 | 3 | 1 | 2 | | 3 | 5 | 3 | 1 | | 4 | 4 | 4 | 2 | | 5 | 2 | 2 | 3 | | 6 | 3 | 5 | 4 | | 7 | 4 | 1 | 3 | | 8 | 2 | 2 | 1 | | 9 | 5 | 2 | 3 | | 10 | 4 | 5 | 1 | +----+-------+-------+-------+ 10 rows in set (0.00 sec) 这将为我们提供足够的数据(我希望),以掩盖下面不同类型的联接的示例,并提供足够的数据以使它们值得。 因此,老板想了解这个问题,老板想知道他拥有的所有跑车的ID。 这是一个简单的两张表联接。我们有一个表,用于标识模型以及具有可用库存的表。正如你所看到的,在数据model的列cars表涉及models的列cars,我们有表。现在,我们知道models表的ID为1for,Sports因此让我们编写联接。 select ID, model from cars join models on model=ID 所以这个查询看起来不错吧?我们已经识别了两个表并包含我们需要的信息,并使用一个联接来正确识别要联接的列。 ERROR 1052 (23000): Column 'ID' in field list is ambiguous 哦,不!我们的第一个查询有错误!是的,它是一个李子。您会看到,查询确实有正确的列,但是两个表中都存在一些列,因此数据库对于实际的含义和位置感到困惑。有两种解决方案可以解决此问题。第一个很简单,我们可以用来tableName.columnName准确地告诉数据库我们的意思,就像这样: select cars.ID, models.model from cars join models on cars.model=models.ID +----+--------+ | ID | model | +----+--------+ | 1 | Sports | | 3 | Sports | | 8 | Sports | | 10 | Sports | | 2 | Sedan | | 4 | Sedan | | 5 | 4WD | | 7 | 4WD | | 9 | 4WD | | 6 | Luxury | +----+--------+ 10 rows in set (0.00 sec) 另一个可能更常用,称为表别名。该示例中的表具有简单易用的简单名称,但是键入类似的名称KPI_DAILY_SALES_BY_DEPARTMENT可能很快就会变老,因此一种简单的方法是对表进行昵称,如下所示: select a.ID, b.model from cars a join models b on a.model=b.ID 现在,返回到请求。如您所见,我们拥有所需的信息,但我们也有未要求提供的信息,因此我们需要在语句中包含where子句,以便仅按要求获取跑车。由于我更喜欢​​表别名方法,而不是一遍又一遍地使用表名,因此从现在开始,我将坚持使用它。 显然,我们需要在查询中添加where子句。我们可以通过ID=1或识别跑车model='Sports'。由于ID已被索引并且主键(而且恰好键入的次数较少),因此请在查询中使用它。 select a.ID, b.model from cars a join models b on a.model=b.ID where b.ID=1 +----+--------+ | ID | model | +----+--------+ | 1 | Sports | | 3 | Sports | | 8 | Sports | | 10 | Sports | +----+--------+ 4 rows in set (0.00 sec) 答对了!老板很高兴。当然,作为老板,对自己的要求从不满意,他会查看信息,然后说我也要颜色。 好的,因此我们已经编写了很大一部分查询,但是我们需要使用第三个表颜色。现在,我们的主要信息表cars存储了汽车颜色ID,该链接返回到颜色ID列。因此,以与原始表类似的方式,我们可以连接第三个表: select a.ID, b.model from cars a join models b on a.model=b.ID join colors c on a.color=c.ID where b.ID=1 +----+--------+ | ID | model | +----+--------+ | 1 | Sports | | 3 | Sports | | 8 | Sports | | 10 | Sports | +----+--------+ 4 rows in set (0.00 sec) 该死,尽管表已正确连接并且相关列已链接,但我们忘记从刚链接的新表中提取实际信息。 select a.ID, b.model, c.color from cars a join models b on a.model=b.ID join colors c on a.color=c.ID where b.ID=1 +----+--------+-------+ | ID | model | color | +----+--------+-------+ | 1 | Sports | Red | | 8 | Sports | Green | | 10 | Sports | White | | 3 | Sports | Black | +----+--------+-------+ 4 rows in set (0.00 sec) 是的,那是我们的老板暂时离开了。现在,更详细地解释其中的一些。如您所见,from语句中的子句链接了我们的主表(我经常使用一个包含信息的表,而不是查找表或维度表。该查询在所有被切换的表中也能正常工作,但是当我们会在几个月后回到此查询中进行阅读,因此通常最好尝试编写一个简单易懂的查询-直观地进行排列,使用漂亮的缩进以使所有内容都清晰易懂如果您继续教别人,请尝试在他们的查询中灌输这些特征-尤其是要对它们进行故障排除时。 完全有可能以此方式链接越来越多的表。 select a.ID, b.model, c.color from cars a join models b on a.model=b.ID join colors c on a.color=c.ID join brands d on a.brand=d.ID where b.ID=1 虽然我忘记在表中包含一个我们可能希望在其中联接多个列的join表,但这里有一个示例。如果该models表具有特定于品牌的模型,因此也有一个称为的列brand,该列链接回brands该ID字段中的表,则可以这样进行: select a.ID, b.model, c.color from cars a join models b on a.model=b.ID join colors c on a.color=c.ID join brands d on a.brand=d.ID and b.brand=d.ID where b.ID=1 您可以看到,上面的查询不仅将联接表链接到主cars表,而且还指定了已联接表之间的联接。如果不这样做,结果称为笛卡尔联接-dba不好。笛卡尔联接是返回行的联接,因为该信息不会告诉数据库如何限制结果,因此查询将返回所有符合条件的行。 因此,举一个笛卡尔联接的例子,让我们运行以下查询: select a.ID, b.model from cars a join models b +----+--------+ | ID | model | +----+--------+ | 1 | Sports | | 1 | Sedan | | 1 | 4WD | | 1 | Luxury | | 2 | Sports | | 2 | Sedan | | 2 | 4WD | | 2 | Luxury | | 3 | Sports | | 3 | Sedan | | 3 | 4WD | | 3 | Luxury | | 4 | Sports | | 4 | Sedan | | 4 | 4WD | | 4 | Luxury | | 5 | Sports | | 5 | Sedan | | 5 | 4WD | | 5 | Luxury | | 6 | Sports | | 6 | Sedan | | 6 | 4WD | | 6 | Luxury | | 7 | Sports | | 7 | Sedan | | 7 | 4WD | | 7 | Luxury | | 8 | Sports | | 8 | Sedan | | 8 | 4WD | | 8 | Luxury | | 9 | Sports | | 9 | Sedan | | 9 | 4WD | | 9 | Luxury | | 10 | Sports | | 10 | Sedan | | 10 | 4WD | | 10 | Luxury | +----+--------+ 40 rows in set (0.00 sec) 天哪,这很丑。但是,就数据库而言,正是所要求的。在查询中,我们要求IDfrom cars和modelfrom models。但是,因为我们没有指定如何联接表,数据库匹配了每一个从第一表行与每一从第二表行。 好的,老板回来了,他希望再次提供更多信息。我想要相同的列表,但还要包含4WD。 但是,这为我们提供了一个很好的借口来研究实现此目的的两种不同方法。我们可以向where子句添加另一个条件,如下所示: select a.ID, b.model, c.color from cars a join models b on a.model=b.ID join colors c on a.color=c.ID join brands d on a.brand=d.ID where b.ID=1 or b.ID=3 尽管上面的方法可以很好地工作,但是让我们以不同的方式来看待它,这是一个很好的借口来说明union查询将如何工作。 我们知道以下将返回所有跑车: select a.ID, b.model, c.color from cars a join models b on a.model=b.ID join colors c on a.color=c.ID join brands d on a.brand=d.ID where b.ID=1 以下将返回所有的四轮驱动车: select a.ID, b.model, c.color from cars a join models b on a.model=b.ID join colors c on a.color=c.ID join brands d on a.brand=d.ID where b.ID=3 因此,通过union all在它们之间添加子句,第二个查询的结果将附加到第一个查询的结果。 select a.ID, b.model, c.color from cars a join models b on a.model=b.ID join colors c on a.color=c.ID join brands d on a.brand=d.ID where b.ID=1 union all select a.ID, b.model, c.color from cars a join models b on a.model=b.ID join colors c on a.color=c.ID join brands d on a.brand=d.ID where b.ID=3 +----+--------+-------+ | ID | model | color | +----+--------+-------+ | 1 | Sports | Red | | 8 | Sports | Green | | 10 | Sports | White | | 3 | Sports | Black | | 5 | 4WD | Green | | 7 | 4WD | White | | 9 | 4WD | Black | +----+--------+-------+ 7 rows in set (0.00 sec) 如您所见,首先返回第一个查询的结果,然后返回第二个查询的结果。 在此示例中,简单地使用第一个查询当然会容易得多,但是union查询在特定情况下可能会很好。它们是从不容易连接在一起的表中返回表中特定结果的好方法-或完全无关的表。但是,有一些规则要遵循。 来自第一个查询的列类型必须与下面的每个其他查询的列类型匹配。 第一个查询中的列名称将用于标识整个结果集。 每个查询中的列数必须相同。 现在,您可能想知道使用union和之间有什么区别union all。一个union查询将删除重复,而union all不会。这确实意味着使用union过度时性能会受到较小的影响,union all但结果可能是值得的-尽管我不会在这种情况下进行推测。 关于此注释,在这里可能需要注意一些其他注释。 如果要订购结果,可以使用an,order by但不能再使用别名。在上面的查询中,附加an order by a.ID将导致错误-就结果而言,该列将被调用,ID而不是a.ID-即使两个查询都使用了相同的别名。 我们只能有一个order by声明,并且必须作为最后一个声明。 对于下一个示例,我将向表中添加一些额外的行。 我已添加Holden到品牌表。我还添加了一行,到cars具有color的价值12-它在颜色表中没有提及。 好的,老板又回来了,咆哮着请求-*我想统计一下我们经营的每个品牌以及其中的汽车数量!`-典型的,我们只是进入了一个有趣的讨论部分,老板希望做更多的工作。 Rightyo,所以我们要做的第一件事就是完整列出所有可能的品牌。 select a.brand from brands a +--------+ | brand | +--------+ | Ford | | Toyota | | Nissan | | Smart | | BMW | | Holden | +--------+ 6 rows in set (0.00 sec) 现在,当我们将其连接到汽车表时,将得到以下结果: select a.brand from brands a join cars b on a.ID=b.brand group by a.brand +--------+ | brand | +--------+ | BMW | | Ford | | Nissan | | Smart | | Toyota | +--------+ 5 rows in set (0.00 sec) 这当然是个问题-我们没有提到Holden我添加的可爱品牌。 这是因为联接在两个表中都查找匹配的行。由于汽车中没有任何类型的数据,Holden因此不会返回。这是我们可以使用outer联接的地方。这将返回一个表中的所有结果,无论它们是否与另一表中的结果匹配: select a.brand from brands a left outer join cars b on a.ID=b.brand group by a.brand +--------+ | brand | +--------+ | BMW | | Ford | | Holden | | Nissan | | Smart | | Toyota | +--------+ 6 rows in set (0.00 sec) 现在,有了这个功能,我们可以添加一个可爱的聚合函数来获得计数,并让老板暂时离开。 select a.brand, count(b.id) as countOfBrand from brands a left outer join cars b on a.ID=b.brand group by a.brand +--------+--------------+ | brand | countOfBrand | +--------+--------------+ | BMW | 2 | | Ford | 2 | | Holden | 0 | | Nissan | 1 | | Smart | 1 | | Toyota | 5 | +--------+--------------+ 6 rows in set (0.00 sec) 这样一来,老板就走了。 现在,为了更详细地说明这一点,外部联接可以是left或right类型。左或右定义完全包含哪个表。A left outer join将包括左侧表中的所有行,而(您猜对了)a right outer join将右侧表中的所有结果带入结果中。 某些数据库允许使用a full outer join,这将从两个表中带回结果(无论是否匹配),但是并非所有数据库都支持。 现在,我可能想知道此时,您想知道是否可以在查询中合并联接类型-答案是肯定的,您绝对可以。 select b.brand, c.color, count(a.id) as countOfBrand from cars a right outer join brands b on b.ID=a.brand join colors c on a.color=c.ID group by a.brand, c.color +--------+-------+--------------+ | brand | color | countOfBrand | +--------+-------+--------------+ | Ford | Blue | 1 | | Ford | White | 1 | | Toyota | Black | 1 | | Toyota | Green | 2 | | Toyota | Red | 1 | | Nissan | Black | 1 | | Smart | White | 1 | | BMW | Blue | 1 | | BMW | White | 1 | +--------+-------+--------------+ 9 rows in set (0.00 sec) 那么,为什么不是预期的结果呢?这是因为尽管我们选择了从汽车到品牌的外部联接,但未在颜色联接中指定-因此特定联接只会带回在两个表中都匹配的结果。 这是可以获取我们期望的结果的查询: select a.brand, c.color, count(b.id) as countOfBrand from brands a left outer join cars b on a.ID=b.brand left outer join colors c on b.color=c.ID group by a.brand, c.color +--------+-------+--------------+ | brand | color | countOfBrand | +--------+-------+--------------+ | BMW | Blue | 1 | | BMW | White | 1 | | Ford | Blue | 1 | | Ford | White | 1 | | Holden | NULL | 0 | | Nissan | Black | 1 | | Smart | White | 1 | | Toyota | NULL | 1 | | Toyota | Black | 1 | | Toyota | Green | 2 | | Toyota | Red | 1 | +--------+-------+--------------+ 11 rows in set (0.00 sec) 如我们所见,查询中有两个外部联接,结果按预期进行。 现在,您问这些其他类型的联接如何?那路口呢? 好吧,并非所有数据库都支持,intersection但是几乎所有数据库都将允许您通过联接(或至少结构良好的where语句)创建交集。 Intersection是一种连接类型,与union上述的连接有点类似-但区别在于,它仅返回由联合连接的各个单个查询之间相同(并且我的意思是相同)的数据行。仅返回在各方面相同的行。 一个简单的例子是这样的: select * from colors where ID>2 intersect select * from colors where id<4 虽然普通union查询将返回表的所有行(第一个查询返回,ID>2而第二个返回具有ID<4)将形成一个完整的集合,但相交查询将仅返回id=3符合两个条件的行。 现在,如果您的数据库不支持intersect查询,则可以通过以下查询轻松完成以上操作: select a.ID, a.color, a.paint from colors a join colors b on a.ID=b.ID where a.ID>2 and b.ID<4 +----+-------+----------+ | ID | color | paint | +----+-------+----------+ | 3 | Blue | Metallic | +----+-------+----------+ 1 row in set (0.00 sec) 如果希望使用本身不支持交集查询的数据库在两个不同的表之间执行交集,则需要在表的每一列上创建一个联接。

保持可爱mmm 2020-05-08 11:31:28 0 浏览量 回答数 0

回答

燃财经(ID:rancaijing)原创 作者 | 唐亚华 编辑 | 魏佳 春节临近,一年一度人口大迁移又要来临。 虽然12306近日已经宣称屏蔽了部分抢票软件,并推出官方候补功能,但市面上提供抢票服务的仍然有智行火车票、 高铁管家、携程、美团、飞猪、同程艺龙等60多个软件。 不过,多名用户反馈称“这届抢票软件不行”,即便用了加速包、买了VIP会员还是抢不到票。技术专家告诉燃财经,从原理上来说,抢票软件只是将用户手动购买车票的链路照搬,用机器来操作,利用企业带宽和机器速度来当“代购”。购买了加速包或VIP的不同之处在于,刷新的频率可能会从30秒一次变成10秒一次或5秒一次,或者多个服务器同时抢票。但是,能不能抢到票仍然是概率问题。 即便如此,仍有众多抢票软件在加速包、VIP会员、优先出票权、安心抢等名目上“动脑筋”,燃财经测试发现,如果要一步一步升级到“抢票顶配”,在携程上需要花费138元,在美团上需要花费80元。这也让不少人诟病抢票软件有捆绑、诱导消费之嫌。 事实上,抢票难的根源在于春节这样短期的大规模迁徙带来的巨大需求缺口难以满足,消费者能做的就是谨慎选择、找准时机、注意捡漏及多种方式搭配。在巨大的需求之下,抢票软件和其商机也将长期存在,但套路不是长久之计,真正为用户提供价值才能让人继续买单。 抢票是一门玄学 自2019年12月12日进入春运以来,“我在XX抢票,快来帮我加速。皮皮虾,我们抢”、“为我回家助把力”、“你不点我不点,小X回家有危险”的文案又开始出现在各大微信群,为抢票助力和“砍一刀”都成了大家考验人缘的方式。 尽管不久前12306对外表示已经屏蔽了多个抢票软件,但燃财经了解到,智行火车票、高铁管家、携程、美团、飞猪、去哪儿、同城艺龙等60多家平台仍然推出了抢票功能。 不过,这一次,用户的反馈不同以往,结合论坛中网友的反馈和燃财经的采访情况,大家普遍反映“这届抢票软件不行”,即便用了加速包、买了VIP会员还是抢不到票,这也引发了大家对于春运抢票加速包是“真有用”还是“智商税”的讨论。 用户小黎告诉燃财经,他在智行火车票上预约了春节回家的火车票,放票时间一到,抢票软件一直显示“抢票中”但并没有成功。心急之下,他自己登上12306官网,发现显示还有余票,很顺利就买上了。“我怀疑不买加速包,抢票软件是不是根本就不给抢。” 另一位用户张宇在智行火车票、携程、美团都提交了抢票订单并购买了40元极速抢票服务,连续抢了三天仍然没有抢到北京到日照的车票。她表示,前几年用抢票软件都能挺顺利抢到,这一次有点失望。 “这两天我用飞猪抢票,加了30元手续费。从放票开始,我就一直守在手机、电脑前。结果飞猪软件里一直显示无票。我又去贴吧看,发现有人在12306官网买到票了,但飞猪还是显示无票。花了30元的VIP手续费,自始至终没看见显示有票,还不如免费抢票软件。”某网友感叹。 抢票软件套路多 尽管抢票软件的效果不能保证,但套路还不少。 燃财经体验了智行火车票、携程、美团、飞猪等平台的抢票后发现,各大平台的抢票方式大同小异,总体感受是不用加速包、不买VIP基本抢不到票,但买了也不承诺能抢到。因为各平台的规则不透明,没有一家承诺100%抢到票,只会提供预估成功率,而这个成功率到底是70%还是98%,在用户端感知不到差异。 总结来看,抢票软件大致有以下几种套路。 首先是用不明显的字体颜色诱使用户购买“加速包”或VIP会员。如下图携程和美团的购票页面上,要购买加速包的“极速购票”用红色字体,不用加钱的“低速抢票”则是不明显的浅灰色字体,不仔细看的用户有可能不小心勾选付费极速抢票的选项。燃财经在测试时,就差点没找到免费的抢票选项。 另外,在文案上制造焦虑也是常见的方式。“低速抢票难度很高,很可能失败”、“低速度抢票成功率52.2%,极速抢票成功率68.86”、“52%的加速用户选择光速抢票”等提示,很容易给用户制造出一种不用加速包、不花钱就抢不到票的焦虑。 第三,平台会不断提醒用户升级加速包,用上了抢票软件就开始一步一步走入它们的套路中。 抢票软件的抢票速度分为低速、快速、高速、极速、光速、VIP,如果你先选择了低速的免费抢票,系统会显示“邀请好友来助力,最高升至光速抢票”,此时,邀请好友点击助力、看广告就是平台的用意。 而当票没抢到时,页面上会有多个提示你升级的选项,燃财经尝试在各平台上都选择了40元极速抢票,本以为高枕无忧了,没想到这才是个开始。如携程还设置了“优先出票特权:发现余票将优先为你出票,10元/人”、“开通超级会员,免费升级VIP抢票,88元/年”,燃财经计算发现,如果直接开通超级会员需要88元,而一步一步升级到抢票顶配,预计需要加138元。 在美团上选择了40元极速抢票后,系统提醒还差10分加速包升至光速抢票,成功率59%,10元/人,VIP抢票成功率61%,30元/人,想升级到顶配需要80元。智行火车票显示从低速到中速、快速、高速、极速、VIP分别需要10元、20元、30元、40元、50元。 另外,去哪儿旅行上还有“安心抢”、“请朋友帮我挂机”、“购买抢票年卡,72元享3次VIP抢票”等选项,而邀请朋友助力时,软件会获取用户的位置、手机号等信息。 最后,尽管有一些抢票软件承诺抢不到票全额退款,但抢票软件会提示用户勾选更多车次、更多时间、跨站抢票以提升抢票成功概率,最终用户买到的并不是“最优选”,但也无法退费。 以上这些套路也是用户吐槽投诉的重灾区。黑猫投诉上有152条关于抢票软件的投诉,例如“智行火车票二次收费”、“同城艺龙购票98%的成功率却抢不到票”、“高铁管家强制套餐消费”等,多是抢票软件诱导消费、退费难的问题。 众多抢票软件的存在,事实上提高了所有人的抢票门槛。这些五花八门的加速选项,增加消费者的筛选成本,抢到了是运气,抢不到只好自认倒霉。 另外,不少APP存在个人信息泄露的风险。抢票软件作为一个工具类插件,技术开发上的门槛较低,用户输入12306的网站用户名、密码等个人信息被传到平台服务器后,如果安全保护性太低,个人信息很容易被泄露。 抢票软件等于外挂 能不能抢到是概率 抢票软件的加速包真的有效果吗,背后的技术原理又是什么呢? 径点科技首席架构师张英辉告诉燃财经:“我们去12306买票的时候要输入信息、查询、购买,所有的抢票软件都是基于同一种原理,将这些手动操作的步骤用程序来实现,然后不停重试。在用户手速和刷票频率的局限下,第三方抢票平台利用机器刷票、全自动化处理有其优势。” 他还提到,购买了加速包或VIP的不同之处在于,刷新的频率可能会从30秒一次变成10秒一次或5秒一次,或者多个服务器同时抢票。因为消费者大多使用的是普通4G以及20M光纤宽带,跟平台使用的企业级宽带的网速自然是不能相比的,在这个拼速度的模式里,抢票软件集合了企业宽带和机器速度的“代购”,就相当于打游戏的时候加了外挂。 整体来看,刷得越勤,用的服务器越多,抢中票的概率越大,但在实际操作中能不能刷中,可能要看那一秒的时间窗口。“因为市面上有60多个刷票软件,某一趟车从一个站到另外一个站的余票情况随时都在变,这种情况下,谁能刷中不一定,取决于刚好出票这一秒哪个软件在刷。”张英辉强调,抢票软件并不能增加车票,12306系统上没票的时候,再多的加速包都没用。 这个过程中还有12306和抢票软件之间的攻防博弈战。 张英辉指出,从技术上来说,12306后台能检测出刷票软件,如果刷票带来的负担超过网站的负荷,后台通常会限制这样的账号,同一IP地址刷票过于频繁或同一购买请求提交过于频繁,都有可能被拖入慢速或被屏蔽掉。但至于具体是什么限流规则,是由12306来制定、调整和实施。 当然,被屏蔽后的刷票软件可能会通过更换IP地址、使用多台服务器轮流操作等方式规避检测。刷票软件也在持续研究怎样绕过官方规则,双方在不停地博弈。所以用户用抢票软件没买到票,可能是因为没刷到,也可能是刷票软件被屏蔽了。 中国铁道科学研究院12306技术部主任单杏花在2019年接受媒体采访时表示,12306已经对第三方抢票软件的相关特征进行识别并实施了流量拦截,即使用户花钱购买了第三方抢票平台的加速服务,购票的成功率也会大打折扣。另外,12306已经推出了“官方抢票”的候补功能,如果遇到有旅客退签返回的车票,或者是铁路方面根据列车能力情况加挂而增加的车票,就可以优先配给已经排队等候的人。 “刷票软件本身的技术难度不大,市面上甚至有很多免费刷票程序或源代码,稍微懂点的人自己都能安装刷票,但要想把刷票功能做得强大很难。要支持大量用户的需求,又要避开12306的监管,可能就需要投入更多的服务器、人力。说白了,给一个人低速刷票很容易,给100万人快速刷票就会变得复杂。”另一位技术人士李元表示。 从理论上说,平台需要投入设备、人力,完成抢票工作后,收取额外的资源占用费是合理的。张英辉认为,问题在于抢票软件在提高概率的同时也提高了买票者的心理预期,一些花了钱没有达到目的的人就会有负面反馈。用户期望交了钱就买到票,但这明显是个概率模式,必然会出现有的刷得到、有的没刷到的情况。 抢票难题和抢票软件将长期存在 经常有人说,微信几亿人同时在用,双11的时候淘宝那么大的流量都能正常运转,12306为啥连个买票软件都做不好? 张英辉解释,12306的业务逻辑要远远比微信和淘宝复杂得多,比如一辆列车经过,中间是十几个站,不停地有人下有人上,还有人换乘,之间有几百种可能性,系统库存随时在变。如果微信有一条消息没发出去或者发了两次是小事,但一张票如果卖给了两个人,这是重大失误。 另外,12306的库存变化又受到网站、APP、售票厅、自动售票机等多方的实时变动影响,用户需求又有时间、车次、地点的无数种排列组合情况,且整个路程在短时间内就要完成,还要验证用户身份以排除同一车次同一人的重复购买,市面上的众多抢票软件还增加了12306的数据压力,系统无论从技术的完整性和资源调度上都远远比微信和淘宝的业务复杂得多。 他还指出,12306最开始采购的应用可能能够支撑平时1亿人访问,但是到了春节期间,有几亿人同时访问,后台需要采购的设备也不是一时就能实现的,购买、部署、调试等整个周期环节就很长,但春节以后又没有那么大的流量了,硬件折旧损耗,人力维护成本都会浪费,所以12306如果只是为了春运和几个大的节假日去加技术和硬件,实际上也是不可行的。 说到底,铁路总运力是一定的,春运这个非常态的需求是极其巨大的,抢票软件并不能增加供给,也不会提高整体买到票的概率,抢票难的根本原因是供求关系不平衡。 加入阿里云钉钉群享福利:每周技术直播,定期群内有奖活动、大咖问答 阿里云开发者社区

茶什i 2020-01-08 11:53:49 0 浏览量 回答数 0
阿里云大学 云服务器ECS com域名 网站域名whois查询 开发者平台 小程序定制 小程序开发 国内短信套餐包 开发者技术与产品 云数据库 图像识别 开发者问答 阿里云建站 阿里云备案 云市场 万网 阿里云帮助文档 免费套餐 开发者工具 企业信息查询 小程序开发制作 视频内容分析 企业网站制作 视频集锦 代理记账服务 企业建站模板