"
293 | ]
294 | },
295 | "metadata": {},
296 | "output_type": "display_data"
297 | }
298 | ],
299 | "source": [
300 | "# 欧式距离,n可扩展,适合大数据集,大n\n",
301 | "predict_cluster(data, 'Birch', n_clusters=2)"
302 | ]
303 | },
304 | {
305 | "cell_type": "markdown",
306 | "metadata": {},
307 | "source": [
308 | "## 3. 参考文档\n",
309 | "\n",
310 | "- [sklearn 聚类官方文档](http://sklearn.apachecn.org/cn/0.19.0/modules/clustering.html)"
311 | ]
312 | }
313 | ],
314 | "metadata": {
315 | "kernelspec": {
316 | "display_name": "Python 3",
317 | "language": "python",
318 | "name": "python3"
319 | },
320 | "language_info": {
321 | "codemirror_mode": {
322 | "name": "ipython",
323 | "version": 3
324 | },
325 | "file_extension": ".py",
326 | "mimetype": "text/x-python",
327 | "name": "python",
328 | "nbconvert_exporter": "python",
329 | "pygments_lexer": "ipython3",
330 | "version": "3.6.2"
331 | }
332 | },
333 | "nbformat": 4,
334 | "nbformat_minor": 2
335 | }
336 |
--------------------------------------------------------------------------------
/ml/1.md:
--------------------------------------------------------------------------------
1 | # 1. 如何处理特征向量的缺失值
2 |
3 |
4 |
5 | ## 1) 缺失值较多
6 |
7 | 缺失值较多.直接将该特征舍弃掉,否则可能反倒会带入较大的噪声,对结果造成不良影响。
8 |
9 | ## 2) 缺失值较少
10 |
11 | 缺失值较少,其余的特征缺失值都在10%以内,我们可以采取很多的方式来处理:
12 |
13 | - 方式1: 把NaN直接作为一个特征,假设用0表示;
14 |
15 | ```python
16 | data_train.fillna(0)
17 | ```
18 | - 方式2: 用均值填充;
19 |
20 | > 均值填充可能需要取条件均值,例如某训练集中患癌症和不患癌症的数据中,该值的差距很大,那么就应当填充label相同的数据的均值。
21 |
22 | ```python
23 | data_train.fillna(data_train.mean())
24 | ```
25 |
26 | - 方式3:用上下数据进行填充;
27 |
28 | ```python
29 | # 上一个数据填充
30 | data_train.fillna(method='pad')
31 | # 下一个数据填充
32 | data_train.fillna(method='bfill')
33 | ```
34 |
35 | - 方式4:插值法
36 |
37 | ```python
38 | # 即估计中间点的值
39 | data_train.interpolate()
40 | ```
41 | - 方式5:用随机森林等算法拟合
42 |
43 | > 将数据分为有值和缺失值2份,对有值的数据采用随机森林拟合,然后对有缺失值的数据进行预测,用预测的值来填充。
--------------------------------------------------------------------------------
/ml/10.md:
--------------------------------------------------------------------------------
1 | # 10. 支持向量机(SVM)中的支持向量是什么意思
2 |
3 |
4 |
5 | ## 题目
6 |
7 | 我们在下面的二元标签的数据集上训练一个线性SVM模型
8 |
9 | ```python
10 | +:(−1,1),(1,−1),(−1,−1)
11 | −:(1,1),(2,0),(2,1)
12 | ```
13 |
14 | 这个模型中的支持向量是哪些?
15 |
16 | A. (−1,1),(1,1),(2,1)
17 | B. (−1,1),(−1,−1),(2,1)
18 | C. (−1,1),(1,−1),(1,1),(2,0)
19 |
20 | ## 解析
21 |
22 | 
23 |
24 | 在画分割线区分红绿两类点的时候,可以问自己一个问题,你认不认为所有的点对于分割线的位置都是起决定性作用的?
25 |
26 | 其实在特别远的区域,哪怕你增加10000个样本点,对于分割线的位置,也是没有作用的,因为分割线是由几个关键点决定的(图上三个),这几个关键点支撑起了一个分割超平面,所以这些关键点,就是支持向量。
27 |
28 | ## 参考文档
29 |
30 | - [支持向量机(SVM)里的支持向量是什么意思 - sofasofa](http://sofasofa.io/forum_main_post.php?postid=1000255)
31 | - [支持向量机(SVM)是什么意思?- 知乎](https://www.zhihu.com/question/21094489)
32 |
33 | ## 答案
34 |
35 | 在坐标系中画一下,即可知道C是正确答案
--------------------------------------------------------------------------------
/ml/11.md:
--------------------------------------------------------------------------------
1 | # 11. 精确率(precision)和召回率(recall)
2 |
3 |
4 |
5 | 混淆矩阵
6 |
7 | - True Positive(真正, TP):将正类预测为正类数.
8 | - True Negative(真负 , TN):将负类预测为负类数.
9 | - False Positive(假正, FP):将负类预测为正类数 → 误报 (Type I error).
10 | - False Negative(假负 , FN):将正类预测为负类数 → 漏报 (Type II error).
11 |
12 | 
13 |
14 | 精确率(precision)定义为:
15 |
16 | 
17 |
18 | 需要注意的是精确率(precision)和准确率(accuracy)是不一样的,
19 |
20 | 
21 |
22 | 在正负样本不平衡的情况下,准确率这个评价指标有很大的缺陷。比如在互联网广告里面,点击的数量是很少的,一般只有千分之几,如果用acc,即使全部预测成负类(不点击)acc 也有 99% 以上,没有意义。
23 |
24 | 召回率(recall,sensitivity,true positive rate)定义为:
25 |
26 | 
27 |
28 | 此外,还有`F1`值,是精确率和召回率的调和均值,
29 |
30 | 
31 |
32 | 精确率和准确率都高的情况下,`F1`值也会高。
--------------------------------------------------------------------------------
/ml/12.md:
--------------------------------------------------------------------------------
1 | # 12. 数据挖掘中如何判断关联规则有效性
2 |
3 |
4 |
5 | ## 关联规则的三个度
6 |
7 | ### 1.支持度(Support)
8 |
9 | > Support(X→Y) = P(X,Y) / P(I) = P(X∪Y) / P(I) = num(XUY) / num(I)
10 |
11 | 支持度表示项集{X,Y}在总项集里出现的概率。
12 |
13 | 其中,I表示总事务集。num()表示求事务集里特定项集出现的次数。
14 |
15 | 比如,num(I)表示总事务集的个数,num(X∪Y)表示含有{X,Y}的事务集的个数(个数也叫次数)。
16 |
17 | ### 2.置信度 (Confidence)
18 |
19 | > Confidence(X→Y) = P(Y|X) = P(X,Y) / P(X) = P(XUY) / P(X)
20 |
21 | 置信度表示在先决条件X发生的情况下,由关联规则”X→Y“推出Y的概率。即在含有X的项集中,含有Y的可能性。
22 |
23 | ### 3.提升度(Lift)
24 |
25 | > Lift(X→Y) = P(Y|X) / P(Y)
26 |
27 | 提升度表示含有X的条件下,同时含有Y的概率,与Y总体发生的概率之比。
28 |
29 | 满足最小支持度和最小置信度的规则,叫做“强关联规则”。
30 |
31 | - Lift(X→Y)>1,“X→Y”是有效的强关联规则。
32 | - Lift(X→Y) <=1,“X→Y”是无效的强关联规则。
33 | - 特别地,Lift(X→Y) =1,X与Y相互独立。
34 |
35 | ## 判断规则的有效性
36 |
37 | ### 题目
38 |
39 | 已知有1000名顾客买年货,分为甲乙两组,每组各500人,其中甲组有500人买了茶叶,同时又有450人买了咖啡;乙组有450人买了咖啡,如表所示,**题目:茶叶→咖啡是一条有效的关联规则吗?**
40 |
41 | 组次|买茶叶的人数|买咖啡的人数|
42 | ---|---|---|
43 | 甲组(500人)|500|450|
44 | 已组(500人)|0|450|
45 |
46 | ### 答案
47 |
48 | - ”茶叶→咖啡“的支持度: Support(X→Y) = 450 / 500 = 90%
49 | - "茶叶→咖啡"的置信度为:Confidence(X→Y) = 450 / 500 = 90%
50 | - ”茶叶→咖啡“的提升度为:Lift(X→Y) = Confidence(X→Y) / P(Y) = 90% / ((450+450)/1000) = 1
51 |
52 | 由于提升度Lift(X→Y) =1,表示X与Y相互独立,即是否有X,对于Y的出现无影响。也就是说,是否购买咖啡,与有没有购买茶叶无关联。即规则”茶叶→咖啡“不成立,或者说关联性很小,几乎没有,虽然它的支持度和置信度都高达90%,但它不是一条有效的关联规则。
--------------------------------------------------------------------------------
/ml/13.md:
--------------------------------------------------------------------------------
1 | # 13. 朴素贝叶斯分类某个类别概率为0怎么办
2 |
3 |
4 |
5 | ## 题目
6 |
7 | A1,A2,A3是三个特征,Y是分类结果。A1,A2,A3和Y 均只有0和1两种情况。
8 |
9 | |A1|A2|A3|Y|
10 | |:---:|:---:|:---:|:---:|
11 | |1|1|0|1|
12 | |0|1|1|1|
13 | |1|0|1|0|
14 | |0|1|0|0|
15 | |0|0|1|0|
16 |
17 | ### 1. 朴素贝叶斯(Naive Bayes)为什么朴素?
18 |
19 | 朴素贝叶斯中的“朴素”二字突出了这个算法的简易性。
20 |
21 | 朴素贝叶斯的简易性表现该算法基于一个很朴素的假设:所有的变量都是相互独立的。用贝叶斯定理可以写成
22 |
23 | 
24 |
25 | 但是在很多情况下,所有变量两两之间独立,这几乎是不可能的。
26 |
27 | > 举个例子:
28 | > Y = 这个人是否是举重运动员。
29 | > X1 = 性别,X2 = 这个人能否举起100公斤的箱子。
30 | > 变量X1和X2显然不是独立的。
31 |
32 | 换句话说,朴素贝叶斯的独立性假设很傻很天真,所以预测精度往往不是很高。
33 |
34 | ### 2. `1,0,0` 的分类结果是什么?
35 |
36 | 
37 |
38 | > 分母都是相同,所以只计算分子即可。
39 |
40 | ```python
41 | P(Y=0) = 3/5
42 | P(Y=1) = 2/5
43 | P(Y=0|A1=1,A2=0,A3=0) = 3/5 * 1/3 * 2/3 * 1/3 = 2/45
44 | P(Y=1|A1=1,A2=0,A3=0) = 2/5 * 1/2 * 1/4 * 1/2 = 1/40
45 | ```
46 |
47 | > 答: **分类结果为0**
48 |
49 | ## 结论
50 |
51 | 从上题可以看出,当每个类别未出现导致概率为0时,可以采用贝叶斯估计的方式来解决。当训练集较多的情况下,可以生成一个接近于0的概率代替0,接近于p的概率代替p,几乎不影响原有的先验概率分布。
52 |
53 | 贝叶斯估计公式中,常取λ为1,这时称之为拉普拉斯平滑(Laplace smoothing)。
54 |
55 | 上例仅对先验概率为0的特征采用了贝叶斯估计,一般情况下会对所有参与训练的特征都采用贝叶斯估计。
--------------------------------------------------------------------------------
/ml/14.md:
--------------------------------------------------------------------------------
1 | # 14. 决策树
2 |
3 |
4 |
5 | ## 什么是决策树
6 |
7 | 决策树(decision tree)是一种基本的分类与回归方法。决策树是用样本的属性作为结点,用属性的取值作为分支的树结构。
8 |
9 |
10 | 决策树的根结点是所有样本中信息量最大的属性。树的中间结点是该结点为根的子树所包含的样本子集中信息量最大的属性。决策树的叶结点是样本的类别值。决策树是一种知识表示形式,它是对所有样本数据的高度概括决策树能准确地识别所有样本的类别,也能有效地识别新样本的类别。
11 |
12 |
13 | 
14 |
15 | ## 特征选择
16 |
17 | |ID|年龄|有工作|有自己的房子|信贷情况|类别(是否个给贷款)|
18 | |:---:|:---:|:---:|:---:|:---:|:---:|
19 | |1|青年|否|否|一般|否|
20 | |2|青年|否|否|好|否|
21 | |3|青年|是|否|好|是|
22 | |4|青年|是|是|一般|是|
23 | |5|青年|否|否|一般|否|
24 | |6|中年|否|否|一般|否|
25 | |7|中年|否|否|好|否|
26 | |8|中年|是|是|好|是|
27 | |9|中年|否|是|非常好|是|
28 | |10|中年|否|是|非常好|是|
29 | |11|老年|否|是|非常好|是|
30 | |12|老年|否|是|好|是|
31 | |13|老年|是|否|好|是|
32 | |14|老年|是|否|非常好|是|
33 | |15|老年|否|否|一般|否|
34 |
35 | 信息熵(entropy)是用来衡量一个随机变量出现的期望值。如果信息的不确定性越大,熵的值也就越大,出现的各种情况也就越多。
36 | 
37 |
38 | 信息增益(information gain)是指信息划分前后的熵的变化,也就是说由于使用这个属性分割样例而导致的期望熵降低。也就是说,信息增益就是原有信息熵与属性划分后信息熵(需要对划分后的信息熵取期望值)的差值,具体计算法如下:
39 | 
40 | ## ID3算法
41 |
42 | 决策树算法ID3的基本思想:
43 |
44 | 首先找出最有判别力的属性,把样例分成多个子集,每个子集又选择最有判别力的属性进行划分,一直进行到所有子集仅包含同一类型的数据为止。最后得到一棵决策树。
45 |
46 | J.R.Quinlan的工作主要是引进了信息论中的信息增益,他将其称为信息增益(information gain),作为属性判别能力的度量,设计了构造决策树的递归算法。
47 |
48 |
49 | ID3算法:
50 |
51 | 1.对当前例子集合,计算各属性的信息增益;
52 | 2.选择信息增益最大的属性Ak;
53 | 3.把在Ak处取值相同的例子归于同一子集,Ak取几个值就得几个子集;
54 | 4.对既含正例又含反例的子集,递归调用建树算法;
55 | 5.若子集仅含正例或反例,对应分枝标上P或N,返回调用处。
56 |
57 | ## C4.5算法
58 | C4.5算法是ID3算法的一种改进。
59 |
60 | 改进
61 | - 用信息增益率来选择属性,克服了用信息增益选择属性偏向选择多值属性的不足
62 | - 在构造树的过程中进行剪枝
63 | - 对连续属性进行离散化
64 | - 能够对不完整的数据进行处理
65 |
66 | 信息增益率
67 |
68 | 设样本集S按离散属性F的c个不同的取值划分为c个子集,则这c个子集的信息熵为:
69 | 
70 | 信息增益率是信息增益与信息熵的比例,如下:
71 | 
72 | ## CART
--------------------------------------------------------------------------------
/ml/2.md:
--------------------------------------------------------------------------------
1 | # 2. 请简要说说一个完整机器学习项目的流程
2 |
3 |
4 |
5 | ## 1 抽象成数学问题
6 |
7 | 明确问题是进行机器学习的第一步。机器学习的训练过程通常都是一件非常耗时的事情,胡乱尝试时间成本是非常高的。
8 | 这里的抽象成数学问题,指的我们明确我们可以获得什么样的数据,目标是一个分类还是回归或者是聚类的问题,如果都不是的话,如果划归为其中的某类问题。
9 |
10 | ## 2 获取数据
11 |
12 | 数据决定了机器学习结果的上限,而算法只是尽可能逼近这个上限。
13 | 数据要有代表性,否则必然会过拟合。
14 | 而且对于分类问题,数据偏斜不能过于严重,不同类别的数据数量不要有数个数量级的差距。
15 | 而且还要对数据的量级有一个评估,多少个样本,多少个特征,可以估算出其对内存的消耗程度,判断训练过程中内存是否能够放得下。如果放不下就得考虑改进算法或者使用一些降维的技巧了。如果数据量实在太大,那就要考虑分布式了。
16 |
17 | ## 3 特征预处理与特征选择
18 |
19 | 良好的数据要能够提取出良好的特征才能真正发挥效力。
20 | 特征预处理、数据清洗是很关键的步骤,往往能够使得算法的效果和性能得到显著提高。归一化、离散化、因子化、缺失值处理、去除共线性等,数据挖掘过程中很多时间就花在它们上面。这些工作简单可复制,收益稳定可预期,是机器学习的基础必备步骤。
21 | 筛选出显著特征、摒弃非显著特征,需要机器学习工程师反复理解业务。这对很多结果有决定性的影响。特征选择好了,非常简单的算法也能得出良好、稳定的结果。这需要运用特征有效性分析的相关技术,如相关系数、卡方检验、平均互信息、条件熵、后验概率、逻辑回归权重等方法。
22 |
23 | ## 4 训练模型与调优
24 |
25 | 直到这一步才用到我们上面说的算法进行训练。现在很多算法都能够封装成黑盒供人使用。但是真正考验水平的是调整这些算法的(超)参数,使得结果变得更加优良。这需要我们对算法的原理有深入的理解。理解越深入,就越能发现问题的症结,提出良好的调优方案。
26 |
27 | ## 5 模型诊断
28 |
29 | 如何确定模型调优的方向与思路呢?这就需要对模型进行诊断的技术。
30 | 过拟合、欠拟合 判断是模型诊断中至关重要的一步。常见的方法如交叉验证,绘制学习曲线等。过拟合的基本调优思路是增加数据量,降低模型复杂度。欠拟合的基本调优思路是提高特征数量和质量,增加模型复杂度。
31 | 误差分析 也是机器学习至关重要的步骤。通过观察误差样本,全面分析误差产生误差的原因:是参数的问题还是算法选择的问题,是特征的问题还是数据本身的问题……
32 | 诊断后的模型需要进行调优,调优后的新模型需要重新进行诊断,这是一个反复迭代不断逼近的过程,需要不断地尝试, 进而达到最优状态。
33 |
34 | ## 6 模型融合
35 |
36 | 一般来说,模型融合后都能使得效果有一定提升。而且效果很好。
37 | 工程上,主要提升算法准确度的方法是分别在模型的前端(特征清洗和预处理,不同的采样模式)与后端(模型融合)上下功夫。因为他们比较标准可复制,效果比较稳定。而直接调参的工作不会很多,毕竟大量数据训练起来太慢了,而且效果难以保证。
38 |
39 | ## 7 上线运行
40 |
41 | 这一部分内容主要跟工程实现的相关性比较大。工程上是结果导向,模型在线上运行的效果直接决定模型的成败。 不单纯包括其准确程度、误差等情况,还包括其运行的速度(时间复杂度)、资源消耗程度(空间复杂度)、稳定性是否可接受。
42 | 这些工作流程主要是工程实践上总结出的一些经验。并不是每个项目都包含完整的一个流程。这里的部分只是一个指导性的说明,只有大家自己多实践,多积累项目经验,才会有自己更深刻的认识。
43 |
--------------------------------------------------------------------------------
/ml/3.md:
--------------------------------------------------------------------------------
1 | # 3. 某超市研究销售记录发现买啤酒的人很大概率也会买尿布,这属于数据挖掘的哪类问题?
2 |
3 |
4 |
5 | - A 关联规则发现
6 | - B 聚类
7 | - C 分类
8 | - D 自然语言处理
9 |
10 | ## A 关联规则发现
11 |
12 | 关联规则就是有关联的规则,形式是这样定义的:两个不相交的非空集合X、Y,如果有X-->Y,就说X-->Y是一条关联规则。在题目的例子中,我们发现购买啤酒就一定会购买尿布,{啤酒}-->{尿布}就是一条关联规则。关联规则的强度用支持度(support)和自信度(confidence)来描述。
13 | 支持度的定义:support(X-->Y) = |X交Y|/N=集合X与集合Y中的项在一条记录中同时出现的次数/数据记录的个数。例如:support({啤酒}-->{尿布}) = 啤酒和尿布同时出现的次数/数据记录数
14 | 自信度的定义:confidence(X-->Y) = |X交Y|/|X| = 集合X与集合Y中的项在一条记录中同时出现的次数/集合X出现的个数 。例如:confidence({啤酒}-->{尿布}) = 啤酒和尿布同时出现的次数/啤酒出现的次数。 confidence({尿布}-->{啤酒}) = 啤酒和尿布同时出现的次数/尿布出现的次数。
15 | 这里定义的支持度和自信度都是相对的支持度和自信度,不是绝对支持度,绝对支持度abs_support = 数据记录数N*support。
16 | 支持度和自信度越高,说明规则越强,关联规则挖掘就是挖掘出满足一定强度的规则。
17 |
18 | ## B 聚类
19 |
20 | Clustering(聚类):
21 | 简单地说就是把相似的东西分到一组,聚类的时候,我们并不关心某一类是什么,我们需要实现的目标只是把相似的东西聚到一起,因此,一个聚类算法通常只需要知道如何计算相似度就可以开始工作了,因此 clustering 通常并不需要使用训练数据进行学习,这在Machine Learning中被称作unsupervised learning (无监督学习)。聚类分析目的在于将相似的事物归类,同一类中的个体有较大的相似性,不同类的个体差异性很大。
22 |
23 | ## C 分类
24 |
25 | Classification (分类):
26 | 一个 classifier会从它得到的训练集中进行“学习”,从而具备对未知数据进行分类的能力,这种提供训练数据的过程通常叫做 supervised learning (监督学习)。所谓分类,简单来说,就是根据文本的特征或属性,划分到已有的类别中。
27 | 常用的分类算法包括:决策树分类法,朴素的贝叶斯分类算法(native Bayesian classifier)、基于支持向量机(SVM)的分类器,神经网络法,k-最近邻法(k-nearest neighbor,kNN),模糊分类法等。分类作为一种监督学习方法,要求必须事先明确知道各个类别的信息,并且断言所有待分类项都有一个类别与之对应。但是很多时候上述条件得不到满足,尤其是在处理海量数据的时候,如果通过预处理使得数据满足分类算法的要求,则代价非常大,这时候可以考虑使用聚类算法。
28 |
29 | ## D 自然语言处理
30 |
31 | 自然语言处理的主要应用范畴包括:文本朗读(Text to speech)/语音合成(Speech synthesis)
32 | 语音识别(Speech recognition)
33 | 中文自动分词(Chinese word segmentation)
34 | 词性标注(Part-of-speech tagging)
35 | 句法分析(Parsing)
36 | 自然语言生成(Natural language generation)
37 | 文本分类(Text categorization)
38 | 信息检索(Information retrieval)
39 | 信息抽取(Information extraction)
40 | 文字校对(Text-proofing)
41 | 问答系统(Question answering)等
42 |
43 | > 选择A,关联规则发现
--------------------------------------------------------------------------------
/ml/4.md:
--------------------------------------------------------------------------------
1 | # 4. 余弦相似与欧氏距离有什么区别和联系
2 |
3 |
4 |
5 | ## 1)区别
6 |
7 | 假设 2人对三部电影的评分分别是 `A = [3, 3, 3]` 和 `B = [5, 5, 5]`
8 |
9 | 那么2人的欧式距离是 根号12 = 3.46, A、B的余弦相似度是1(方向完全一致)。
10 |
11 | > 余弦值的范围是[-1, 1], 越接近于1,说明2个向量的方向越相近
12 |
13 | 欧式距离和余弦相似度都能度量2个向量之间的相似度,但是欧式距离从2点之间的距离去考量,余弦相似从2个向量之间的夹角去考量。
14 | 从上例可以发出,2人对三部电影的评价趋势是一致的,但是欧式距离并不能反映出这一点,余弦相似则能够很好地反应。余弦相似可以很好地规避指标刻度的差异,最常见的应用是计算 **文本的相似度** 。
15 |
16 | ## 2)联系
17 | 从下图的公式可以看出,归一化后计算的欧式距离是关于余弦相似的单调函数,可以认为归一化后,余弦相似与欧式距离效果是一致的(欧式距离越小等价于余弦相似度越大)。
18 |
19 | 因此可以将 **求余弦相似转为求欧式距离** ,余弦相似的计算复杂度过高,转为求欧式距离后,可以借助`KDTree`(KNN算法用到)或者`BallTree`(对高维向量友好)来降低复杂度。
20 |
21 | 
22 |
23 |
24 | ## 3)参考链接
25 |
26 | [知乎:欧氏距离和余弦相似度的区别是什么?](https://www.zhihu.com/question/19640394)
27 |
28 |
--------------------------------------------------------------------------------
/ml/5.md:
--------------------------------------------------------------------------------
1 | # 5. 下面哪个不属于数据的属性类别
2 |
3 |
4 |
5 | - A 标称
6 | - B 序数
7 | - C 区间
8 | - D 相异
9 |
10 | ## 关于数据的属性类别的介绍
11 |
12 |
13 | 数据集由数据对象组成,一个数据对象代表一个实体。数据对象又称样本、实例、数据点或对象。属性(attribute)是一个数据字段,表示数据对象的一个特征。属性向量(或特征向量)是用来描述一个给定对象的一组属性。属性有不同类型:标称属性(nominal attribute)、二元属性(binary attribute)、序数属性(ordinal attribute)、 数值属性(numerical attribute)、离散属性与连续属性。
14 |
15 | ### A、标称属性(nominal attribute)
16 |
17 | 标称属性的值是一些符号或实物的名称,每个值代表某种类别、编码或状态,所以标称属性又被看做是分类型的属性(categorical)。这些值不必具有有意义的序,并且不是定量的。
18 |
19 | ### B、二元属性(binary attribute)
20 |
21 | 二元属性是一种标称属性,只有两个类别或状态:0或1,其中0常表示不出现,1表示出现。如果将0和1对应于false和true,二元属性则为布尔属性。
22 |
23 | ### C、序数属性(ordinal attribute)
24 |
25 | 序数属性可能的取值之间具有有意义的序或秩评定,但相继值之间的差是未知的。例如,学生的成绩属性可以分为优、良、中、差四个等级;某快餐店的饮料杯具有大、中、小三个可能值。然而,具体“大”比“中”大多少是未知的。
26 |
27 | 序数属性可用于记录不能客观度量的主观质量评估。因此,序数属性常用于等级评定调查。如某销售部门客户服务质量的评估,0表示很不满意,1不太满意,2表示中性,3表示满意,4表示非常满意。
28 |
29 | 通过数据预处理中的数据规约,序数属性可以通过将数据的值域划分成有限个有序类别,将数值属性离散化而得到。应注意的是,标称、二元和序数属性都是定性的,只描述样本的特征,而不给出实际大小或数量。下面介绍提供样本定量度量的数值属性。
30 |
31 | ### D、数值属性(numerical attribute)
32 |
33 | 数值属性是可度量的量,用整数或实数值表示,有区间标度和比率标度两种类型。
34 |
35 | #### a) 区间标度(interval-scaled)属性
36 |
37 | 区间标度属性用相等的单位尺度度量。区间属性的值有序。所以,除了秩评定之外,这种属性允许比较和定量评估值之间的差。例如,身高属性是区间标度的。假设我们有一个班学生的身高统计值,将每一个人视为一个样本,将这些学生身高值排序,可以量化不同值之间的差。A同学身高170cm比B同学165cm高出5cm。
38 |
39 | 对于没有真正零点的摄氏温度和华氏温度,其零值不表示没有温度。例如,摄氏温度的度量单位是水在标准大气压下沸点温度与冰点温度之差的1/100。尽管可以计算温度之差,但因没有真正的零值,因此不能说10℃比5℃温暖2倍,不能用比率描述这些值。但比率标度属性存在真正的零点。
40 |
41 | #### b) 比率标度(ratio-scaled)属性
42 |
43 | 比率标度属性的度量是比率的,可以用比率来描述两个值,即一个值是另一个值的倍数,也可以计算值之间的差。例如,不同于摄氏和华氏温度,开氏温度具有绝对零点。在零点,构成物质的粒子具有零动能。比率标度属性的例子还包括字数和工龄等计数属性,以及度量重量、高度、速度的属性。
44 |
45 |
46 | ## E、离散属性与连续属性
47 |
48 |
49 | 前面介绍的四种属性类型之间不是互斥的。我们还可以用许多其他方法来组织属性类型,使类型间不互斥。机器学习领域的分类算法常把属性分为离散的或连续的属性。不同类型有不同的处理方法。
50 |
51 | 离散属性具有有限或无限可数个值。如学生成绩属性,优、良、中、差;二元属性取1和0以及年龄属性取0到110。如一个属性可能取值的值集合是无限的,但可以建立一个与自然数的一一对应,则其也是离散属性。如果一个属性不是离散的,则它是连续的。注意:在文献中,术语 “数值属性” 和“连续属性”常可以互换使用,因此,“连续属性”也常被称为“数值属性”。
52 |
53 | 参考书目《无监督学习方法及其应用》
54 |
55 |
--------------------------------------------------------------------------------
/ml/6.md:
--------------------------------------------------------------------------------
1 | # 6. 监督学习和无监督学习
2 |
3 |
4 |
5 | ## 关键区别
6 |
7 | **是否有监督(supervised),就看输入数据是否有标签(label)。输入数据有标签,则为(有)监督学习,没标签则为无监督学习。**
8 | ### 知乎的通俗回答
9 |
10 | 作者:王丰
11 | [链接](https://www.zhihu.com/question/23194489/answer/25028661)
12 |
13 | 首先看什么是学习(learning)?一个成语就可概括:举一反三。此处以高考为例,高考的题目在上考场前我们未必做过,但在高中三年我们做过很多很多题目,懂解题方法,因此考场上面对陌生问题也可以算出答案。机器学习的思路也类似:我们能不能利用一些训练数据(已经做过的题),使机器能够利用它们(解题方法)分析未知数据(高考的题目)?
14 |
15 | 最简单也最普遍的一类机器学习算法就是分类(classification)。对于分类,输入的训练数据有特征(feature),有标签(label)。所谓的学习,其本质就是找到特征和标签间的关系(mapping)。这样当有特征而无标签的未知数据输入时,我们就可以通过已有的关系得到未知数据标签。
16 |
17 | 在上述的分类过程中,如果所有训练数据都有标签,则为有监督学习(supervised learning)。如果数据没有标签,显然就是无监督学习(unsupervised learning)了,也即聚类(clustering)。目前分类算法的效果还是不错的,但相对来讲,聚类算法就有些惨不忍睹了。确实,无监督学习本身的特点使其难以得到如分类一样近乎完美的结果。这也正如我们在高中做题,答案(标签)是非常重要的,假设两个完全相同的人进入高中,一个正常学习,另一人做的所有题目都没有答案,那么想必第一个人高考会发挥更好,第二个人会发疯。
18 |
19 | 这时各位可能要问,既然分类如此之好,聚类如此之不靠谱,那为何我们还可以容忍聚类的存在?因为在实际应用中,标签的获取常常需要极大的人工工作量,有时甚至非常困难。例如在自然语言处理(NLP)中,Penn Chinese Treebank在2年里只完成了4000句话的标签……
20 |
21 | 
22 |
23 | 这时有人可能会想,难道有监督学习和无监督学习就是非黑即白的关系吗?有没有灰呢?Good idea。灰是存在的。二者的中间带就是半监督学习(semi-supervised learning)。对于半监督学习,其训练数据的一部分是有标签的,另一部分没有标签,而没标签数据的数量常常极大于有标签数据数量(这也是符合现实情况的)。隐藏在半监督学习下的基本规律在于:数据的分布必然不是完全随机的,通过一些有标签数据的局部特征,以及更多没标签数据的整体分布,就可以得到可以接受甚至是非常好的分类结果。(此处大量忽略细节)
24 |
25 | 因此,learning家族的整体构造是这样的:
26 |
27 | - 有监督学习(分类,回归)
28 | - ↕
29 | - 半监督学习(分类,回归),transductive learning(分类,回归)
30 | - ↕
31 | - 半监督聚类(有标签数据的标签不是确定的,类似于:肯定不是xxx,很可能是yyy)
32 | - ↕
33 | - 无监督学习(聚类)
34 |
35 | ## 概念
36 | ### 监督学习
37 | 通过已有的训练样本(即已知数据以及其对应的输出)来训练,从而得到一个最优模型,再利用这个模型将所有新的数据样本映射为相应的输出结果,对输出结果进行简单的判断从而实现分类的目的,那么这个最优模型也就具有了对未知数据进行分类的能力。
38 |
39 | 监督学习最常见的就是:分类(classification)&回归(regression)
40 |
41 | ### 无监督学习
42 | 输入数据没有被标记,也没有确定的结果。样本数据类别未知,需要根据样本间的相似性对样本集进行分类(聚类,clustering)试图使类内差距最小化,类间差距最大化。通俗点将就是实际应用中,不少情况下无法预先知道样本的标签,也就是说没有训练样本对应的类别,因而只能从原先没有样本标签的样本集开始学习分类器设计。
43 |
44 | 无监督学习最常见的就是:聚类(Clustering)
45 |
46 | 无监督学习举例:
47 | - 新闻分类
48 |
49 |
50 |
--------------------------------------------------------------------------------
/ml/7.md:
--------------------------------------------------------------------------------
1 | # 7. 熵是为消除不确定性所需要获得的信息量,投掷均匀正六面体骰子的熵是
2 |
3 |
4 |
5 | 2.6比特
6 |
7 |
8 | ## 信息熵
9 |
10 |
11 | 如何计算信息量的多少?在日常生活中,极少发生的事件一旦发生是容易引起人们关注的,而司空见惯的事不会引起注意,也就是说,极少见的事件所带来的信息量多。如果用统计学的术语来描述,就是出现概率小的事件信息量多。因此,事件出现得概率越小,信息量愈大。即信息量的多少是与事件发生频繁(即概率大小)成反比。
12 |
13 | 1.如已知事件Xi已发生,则表示Xi所含有或所提供的信息量
14 |
15 |
16 | H(Xi) = − logP(Xi)
17 |
18 | 例题:若估计在一次国际象棋比赛中谢军获得冠军的可能性为0.1(记为事件A),而在另一次国际象棋比赛中她得到冠军的可能性为0.9(记为事件B)。试分别计算当你得知她获得冠军时,从这两个事件中获得的信息量各为多少?
19 |
20 | H(A)=-log2 P(0.1)≈3.32(比特)
21 |
22 | H(B)=-log2 P(0.9)≈0.152(比特)
23 |
24 | 2.统计信息量的计算公式为:
25 | H(X)=$$sum^{n}_{i=1}P(Xi)log P(Xi)$$
26 |
27 | Xi —— 表示第i个状态(总共有n种状态);
28 |
29 | P(Xi)——表示第i个状态出现的概率;
30 |
31 | H(X)——表示用以消除这个事物的不确定性所需要的信息量。
32 |
33 | 例题:向空中投掷硬币,落地后有两种可能的状态,一个是正面朝上,另一个是反面朝上,每个状态出现的概率为1/2。如投掷均匀的正六面体的骰子,则可能会出现的状态有6个,每一个状态出现的概率均为1/6。试通过计算来比较状态的不肯定性与硬币状态的不肯定性的大小。
34 |
35 | H(硬币)= -\sum^{n}_{i=1}P(Xi)log P(Xi)
36 |
37 | = -(2×1/2)×logP2(1/2)≈1(比特)
38 |
39 | H(骰子)= -\sum^{n}_{i=1}P(Xi)log P(Xi)
40 |
41 | = -6×(1/6)×logP2(1/6)≈2.6(比特)
42 |
43 | 由以上计算可以得出两个推论:
44 |
45 | [推论1] 当且仅当某个P(Xi)=1,其余的都等于0时, H(X)= 0。
46 |
47 | [推论2]当且仅当某个P(Xi)=1/n,i=1, 2,……, n时,H(X)有极大值log n。
48 | 数值属性是可度量的量,用整数或实数值表示,有区间标度和比率标度两种类型。
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/ml/8.md:
--------------------------------------------------------------------------------
1 | # 8. 数据清洗与特征处理
2 |
3 |
4 |
5 | ## 数据清洗
6 | 清洗标注数据,主要是数据采样和样本过滤
7 |
8 | **数据采样**
9 |
10 | 数据采样,例如对于分类问题:选取正例,负例。对于回归问题,需要采集数据。对于采样得到的样本,根据需要,需要设定样本权重。当模型不能使用全部的数据来训练时,需要对数据进行采样,设定一定的采样率。采样的方法包括随机采样,固定比例采样等方法。
11 |
12 | **样本过滤**
13 |
14 | 1.结合业务情况进行数据的过滤,例如去除crawler抓取,spam,作弊等数据。
15 |
16 | 2.异常点检测,采用异常点检测算法对样本进行分析,常用的异常点检测算法包括:
17 |
18 | - 偏差检测,例如聚类,最近邻等。
19 | - 基于统计的异常点检测算法
20 | 例如极差,四分位数间距,均差,标准差等,这种方法适合于挖掘单变量的数值型数据。全距(Range),又称极差,是用来表示统计资料中的变异量数(measures of variation) ,其最大值与最小值之间的差距;四分位距通常是用来构建箱形图,以及对概率分布的简要图表概述。
21 | - 基于距离的异常点检测算法,主要通过距离方法来检测异常点,将数据集中与大多数点之间距离大于某个阈值的点视为异常点,主要使用的距离度量方法有绝对距离 ( 曼哈顿距离 ) 、欧氏距离和马氏距离等方法。
22 | - 基于密度的异常点检测算法,考察当前点周围密度,可以发现局部异常点,例如LOF算法
23 |
24 | ## 特征处理
25 |
26 | ### 特征处理与分析
27 |
28 | 在对特征进行分类后,下面介绍下对特征常用的处理方法。包括1.特征归一化,离散化,缺省值处理。2.特征降维方法。3.特征选择方法等。
29 |
30 | 特征归一化,离散化,缺省值处理
31 | 主要用于单个特征的处理。
32 |
33 | **归一化**
34 |
35 | 不同的特征有不同的取值范围,在有些算法中,例如线性模型或者距离相关的模型像聚类模型、knn模型等,特征的取值范围会对最终的结果产生较大影响,例如二元特征的取值范围为[0,1],而距离特征取值可能是[0,正无穷),在实际使用中会对距离进行截断,例如[0,3000000],但是这两个特征由于取值范围不一致导致了模型可能会更偏向于取值范围较大的特征,为了平衡取值范围不一致的特征,需要对特征进行归一化处理,将特征取值归一化到[0,1]区间。常用的归一化方法包括1.函数归一化,通过映射函数将特征取值映射到[0,1]区间,例如最大最小值归一化方法,是一种线性的映射。还有通过非线性函数的映射,例如log函数等。2.分维度归一化,可以使用最大最小归一化方法,但是最大最小值选取的是所属类别的最大最小值,即使用的是局部最大最小值,不是全局的最大最小值。3.排序归一化,不管原来的特征取值是什么样的,将特征按大小排序,根据特征所对应的序给予一个新的值。
36 |
37 | **离散化**
38 |
39 | 在上面介绍过连续值的取值空间可能是无穷的,为了便于表示和在模型中处理,需要对连续值特征进行离散化处理。常用的离散化方法包括等值划分和等量划分。等值划分是将特征按照值域进行均分,每一段内的取值等同处理。例如某个特征的取值范围为[0,10],我们可以将其划分为10段,[0,1),[1,2),...,[9,10)。等量划分是根据样本总数进行均分,每段等量个样本划分为1段。例如距离特征,取值范围[0,3000000],现在需要切分成10段,如果按照等比例划分的话,会发现绝大部分样本都在第1段中。使用等量划分就会避免这种问题,最终可能的切分是[0,100),[100,300),[300,500),..,[10000,3000000],前面的区间划分比较密,后面的比较稀疏。
40 |
41 | **缺省值处理**
42 |
43 | 有些特征可能因为无法采样或者没有观测值而缺失,例如距离特征,用户可能禁止获取地理位置或者获取地理位置失败,此时需要对这些特征做特殊的处理,赋予一个缺省值。缺省值如何赋予,也有很多种方法。例如单独表示,众数,平均值等。
44 |
45 | 
46 |
47 | ### 参考
48 | [https://tech.meituan.com/machinelearning-data-feature-process.html](https://tech.meituan.com/machinelearning-data-feature-process.html)
--------------------------------------------------------------------------------
/ml/9.md:
--------------------------------------------------------------------------------
1 | # 9. 猜测这种划分最可能是什么聚类算法的结果
2 |
3 |
4 |
5 | 
6 |
7 | ## 以下是各个算法的比较
8 |
9 | 
10 |
11 | ## 各个聚类算法比较的Python代码
12 |
13 | [python代码链接](https://github.com/geektutu/interview-questions/tree/master/ipynb/sklearn-cluster-compare.ipynb)
14 |
15 | > 最可能是KMean算法
--------------------------------------------------------------------------------
/ml/image/10.svm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/ml/image/10.svm.png
--------------------------------------------------------------------------------
/ml/image/11.F1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/ml/image/11.F1.png
--------------------------------------------------------------------------------
/ml/image/11.accuracy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/ml/image/11.accuracy.png
--------------------------------------------------------------------------------
/ml/image/11.confusion_matrix.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/ml/image/11.confusion_matrix.png
--------------------------------------------------------------------------------
/ml/image/11.precision.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/ml/image/11.precision.png
--------------------------------------------------------------------------------
/ml/image/11.recall.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/ml/image/11.recall.png
--------------------------------------------------------------------------------
/ml/image/13.laplace.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/ml/image/13.laplace.png
--------------------------------------------------------------------------------
/ml/image/13.naive.bayes.formula.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/ml/image/13.naive.bayes.formula.png
--------------------------------------------------------------------------------
/ml/image/14.decision_tree_eg.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/ml/image/14.decision_tree_eg.gif
--------------------------------------------------------------------------------
/ml/image/14.entropy.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/ml/image/14.entropy.jpg
--------------------------------------------------------------------------------
/ml/image/14.gain.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/ml/image/14.gain.jpg
--------------------------------------------------------------------------------
/ml/image/14.gain.ratio.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/ml/image/14.gain.ratio.jpg
--------------------------------------------------------------------------------
/ml/image/14.splitInfo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/ml/image/14.splitInfo.jpg
--------------------------------------------------------------------------------
/ml/image/4.cosine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/ml/image/4.cosine.png
--------------------------------------------------------------------------------
/ml/image/6.nlp.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/ml/image/6.nlp.jpg
--------------------------------------------------------------------------------
/ml/image/8.数据清洗与特征处理.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/ml/image/8.数据清洗与特征处理.jpg
--------------------------------------------------------------------------------
/ml/image/9.cluster.algorithms.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/ml/image/9.cluster.algorithms.png
--------------------------------------------------------------------------------
/ml/image/9.cluster.question.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/ml/image/9.cluster.question.png
--------------------------------------------------------------------------------
/qa-golang/qa-golang-1.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Go 语言笔试面试题(基础语法)
3 | seo_title: 极客面试
4 | date: 2020-09-04 22:10:10
5 | description: Go 语言/golang 笔试题,面试题,基础语法与内部实现原理,包括不限于垃圾回收机制(GC)、面向对象、并发编程等。
6 | tags:
7 | - Go
8 | nav: 面试
9 | categories:
10 | - Go 语言面试题
11 | image: post/qa-golang/go_questions.jpg
12 | github: https://github.com/geektutu/interview-questions
13 | ---
14 |
15 | 
16 |
17 | **[Go 语言笔试面试题汇总](https://geektutu.com/post/qa-golang.html),[Github](https://github.com/geektutu/interview-questions)**
18 |
19 |
20 | ## Q1 `=` 和 `:=` 的区别?
21 |
22 |
23 | 答案
24 |
25 |
26 | `:=` 声明+赋值
27 |
28 | `=` 仅赋值
29 |
30 | ```go
31 | var foo int
32 | foo = 10
33 | // 等价于
34 | foo := 10
35 | ```
36 |
37 |
38 |
39 |
40 |
41 |
42 | ## Q2 指针的作用?
43 |
44 |
45 | 答案
46 |
47 |
48 | 指针用来保存变量的地址。
49 |
50 | 例如
51 |
52 | ```go
53 | var x = 5
54 | var p *int = &x
55 | fmt.Printf("x = %d", *p) // x 可以用 *p 访问
56 | ```
57 |
58 | - `*` 运算符,也称为解引用运算符,用于访问地址中的值。
59 | - `&`运算符,也称为地址运算符,用于返回变量的地址。
60 |
61 |
62 |
63 |
64 |
65 | ## Q3 Go 允许多个返回值吗?
66 |
67 |
68 | 答案
69 |
70 |
71 | 允许
72 |
73 | ```go
74 | func swap(x, y string) (string, string) {
75 | return y, x
76 | }
77 |
78 | func main() {
79 | a, b := swap("A", "B")
80 | fmt.Println(a, b) // B A
81 | }
82 | ```
83 |
84 |
85 |
86 |
87 |
88 | ## Q4 Go 有异常类型吗?
89 |
90 |
91 | 答案
92 |
93 |
94 | Go 没有异常类型,只有错误类型(Error),通常使用返回值来表示异常状态。
95 |
96 | ```go
97 | f, err := os.Open("test.txt")
98 | if err != nil {
99 | log.Fatal(err)
100 | }
101 | ```
102 |
103 |
104 |
105 |
106 |
107 | ## Q5 什么是协程(Goroutine)
108 |
109 |
110 | 答案
111 |
112 |
113 | Goroutine 是与其他函数或方法同时运行的函数或方法。 Goroutines 可以被认为是轻量级的线程。 与线程相比,创建 Goroutine 的开销很小。 Go应用程序同时运行数千个 Goroutine 是非常常见的做法。
114 |
115 |
116 |
117 |
118 |
119 | ## Q6 如何高效地拼接字符串
120 |
121 |
122 | 答案
123 |
124 |
125 | Go 语言中,字符串是只读的,也就意味着每次修改操作都会创建一个新的字符串。如果需要拼接多次,应使用 `strings.Builder`,最小化内存拷贝次数。
126 |
127 | ```go
128 | var str strings.Builder
129 | for i := 0; i < 1000; i++ {
130 | str.WriteString("a")
131 | }
132 | fmt.Println(str.String())
133 | ```
134 |
135 |
136 |
137 |
138 |
139 | ## Q7 什么是 rune 类型
140 |
141 |
142 | 答案
143 |
144 |
145 | ASCII 码只需要 7 bit 就可以完整地表示,但只能表示英文字母在内的128个字符,为了表示世界上大部分的文字系统,发明了 Unicode, 它是ASCII的超集,包含世界上书写系统中存在的所有字符,并为每个代码分配一个标准编号(称为Unicode CodePoint),在 Go 语言中称之为 rune,是 int32 类型的别名。
146 |
147 | Go 语言中,字符串的底层表示是 byte (8 bit) 序列,而非 rune (32 bit) 序列。例如下面的例子中 `语` 和 `言` 使用 UTF-8 编码后各占 3 个 byte,因此 `len("Go语言")` 等于 8,当然我们也可以将字符串转换为 rune 序列。
148 |
149 | ```go
150 | fmt.Println(len("Go语言")) // 8
151 | fmt.Println(len([]rune("Go语言"))) // 4
152 | ```
153 |
154 |
155 |
156 |
157 |
158 | ## Q8 如何判断 map 中是否包含某个 key ?
159 |
160 |
161 | 答案
162 |
163 |
164 | ```go
165 | if val, ok := dict["foo"]; ok {
166 | //do something here
167 | }
168 | ```
169 |
170 | `dict["foo"]` 有 2 个返回值,val 和 ok,如果 ok 等于 `true`,则说明 dict 包含 key `"foo"`,val 将被赋予 `"foo"` 对应的值。
171 |
172 |
173 |
174 |
175 |
176 | ## Q9 Go 支持默认参数或可选参数吗?
177 |
178 |
179 | 答案
180 |
181 |
182 | Go 语言不支持可选参数(python 支持),也不支持方法重载(java支持)。
183 |
184 |
185 |
186 |
187 |
188 | ## Q10 defer 的执行顺序
189 |
190 |
191 | 答案
192 |
193 |
194 | - 多个 defer 语句,遵从后进先出(Last In First Out,LIFO)的原则,最后声明的 defer 语句,最先得到执行。
195 | - defer 在 return 语句之后执行,但在函数退出之前,defer 可以修改返回值。
196 |
197 | 例如:
198 |
199 | ```go
200 | func test() int {
201 | i := 0
202 | defer func() {
203 | fmt.Println("defer1")
204 | }()
205 | defer func() {
206 | i += 1
207 | fmt.Println("defer2")
208 | }()
209 | return i
210 | }
211 |
212 | func main() {
213 | fmt.Println("return", test())
214 | }
215 | // defer2
216 | // defer1
217 | // return 0
218 | ```
219 |
220 | 这个例子中,可以看到 defer 的执行顺序:后进先出。但是返回值并没有被修改,这是由于 Go 的返回机制决定的,执行 return 语句后,Go 会创建一个临时变量保存返回值,因此,defer 语句修改了局部变量 i,并没有修改返回值。那如果是有名的返回值呢?
221 |
222 | ```go
223 | func test() (i int) {
224 | i = 0
225 | defer func() {
226 | i += 1
227 | fmt.Println("defer2")
228 | }()
229 | return i
230 | }
231 |
232 | func main() {
233 | fmt.Println("return", test())
234 | }
235 | // defer2
236 | // return 1
237 | ```
238 |
239 | 这个例子中,返回值被修改了。对于有名返回值的函数,执行 return 语句时,并不会再创建临时变量保存,因此,defer 语句修改了 i,即对返回值产生了影响。
240 |
241 |
242 |
243 |
244 |
245 | ## Q11 如何交换 2 个变量的值?
246 |
247 |
248 | 答案
249 |
250 |
251 | ```go
252 | a, b := "A", "B"
253 | a, b = b, a
254 | fmt.Println(a, b) // B A
255 | ```
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 | ## Q12 Go 语言 tag 的用处?
264 |
265 |
266 | 答案
267 |
268 |
269 | tag 可以理解为 struct 字段的注解,可以用来定义字段的一个或多个属性。框架/工具可以通过反射获取到某个字段定义的属性,采取相应的处理方式。tag 丰富了代码的语义,增强了灵活性。
270 |
271 | 例如:
272 |
273 | ```go
274 | package main
275 |
276 | import "fmt"
277 | import "encoding/json"
278 |
279 | type Stu struct {
280 | Name string `json:"stu_name"`
281 | ID string `json:"stu_id"`
282 | Age int `json:"-"`
283 | }
284 |
285 | func main() {
286 | buf, _ := json.Marshal(Stu{"Tom", "t001", 18})
287 | fmt.Printf("%s\n", buf)
288 | }
289 | ```
290 |
291 | 这个例子使用 tag 定义了结构体字段与 json 字段的转换关系,Name -> `stu_name`, ID -> `stu_id`,忽略 Age 字段。很方便地实现了 Go 结构体与不同规范的 json 文本之间的转换。
292 |
293 |
294 |
295 |
296 |
297 |
298 | ## Q13 如何判断 2 个字符串切片(slice) 是相等的?
299 |
300 |
301 | 答案
302 |
303 |
304 | go 语言中可以使用反射 `reflect.DeepEqual(a, b)` 判断 a、b 两个切片是否相等,但是通常不推荐这么做,使用反射非常影响性能。
305 |
306 | 通常采用的方式如下,遍历比较切片中的每一个元素(注意处理越界的情况)。
307 |
308 | ```go
309 | func StringSliceEqualBCE(a, b []string) bool {
310 | if len(a) != len(b) {
311 | return false
312 | }
313 |
314 | if (a == nil) != (b == nil) {
315 | return false
316 | }
317 |
318 | b = b[:len(a)]
319 | for i, v := range a {
320 | if v != b[i] {
321 | return false
322 | }
323 | }
324 |
325 | return true
326 | }
327 | ```
328 |
329 |
330 |
331 |
332 |
333 | ## Q14 字符串打印时,`%v` 和 `%+v` 的区别
334 |
335 |
336 | 答案
337 |
338 |
339 | `%v` 和 `%+v` 都可以用来打印 struct 的值,区别在于 `%v` 仅打印各个字段的值,`%+v` 还会打印各个字段的名称。
340 |
341 | ```go
342 | type Stu struct {
343 | Name string
344 | }
345 |
346 | func main() {
347 | fmt.Printf("%v\n", Stu{"Tom"}) // {Tom}
348 | fmt.Printf("%+v\n", Stu{"Tom"}) // {Name:Tom}
349 | }
350 | ```
351 |
352 | 但如果结构体定义了 `String()` 方法,`%v` 和 `%+v` 都会调用 `String()` 覆盖默认值。
353 |
354 |
355 |
356 |
357 |
358 | ## Q15 Go 语言中如何表示枚举值(enums)
359 |
360 |
361 | 答案
362 |
363 |
364 | 通常使用常量(const) 来表示枚举值。
365 |
366 | ```go
367 | type StuType int32
368 |
369 | const (
370 | Type1 StuType = iota
371 | Type2
372 | Type3
373 | Type4
374 | )
375 |
376 | func main() {
377 | fmt.Println(Type1, Type2, Type3, Type4) // 0, 1, 2, 3
378 | }
379 | ```
380 |
381 | 参考 [What is an idiomatic way of representing enums in Go? - StackOverflow](https://stackoverflow.com/questions/14426366/what-is-an-idiomatic-way-of-representing-enums-in-go)
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 | ## Q16 空 struct{} 的用途
390 |
391 |
392 | 答案
393 |
394 |
395 | 使用空结构体 struct{} 可以节省内存,一般作为占位符使用,表明这里并不需要一个值。
396 |
397 | ```go
398 | fmt.Println(unsafe.Sizeof(struct{}{})) // 0
399 | ```
400 |
401 | 比如使用 map 表示集合时,只关注 key,value 可以使用 struct{} 作为占位符。如果使用其他类型作为占位符,例如 int,bool,不仅浪费了内存,而且容易引起歧义。
402 |
403 | ```go
404 | type Set map[string]struct{}
405 |
406 | func main() {
407 | set := make(Set)
408 |
409 | for _, item := range []string{"A", "A", "B", "C"} {
410 | set[item] = struct{}{}
411 | }
412 | fmt.Println(len(set)) // 3
413 | if _, ok := set["A"]; ok {
414 | fmt.Println("A exists") // A exists
415 | }
416 | }
417 | ```
418 |
419 | 再比如,使用信道(channel)控制并发时,我们只是需要一个信号,但并不需要传递值,这个时候,也可以使用 struct{} 代替。
420 |
421 | ```go
422 | func main() {
423 | ch := make(chan struct{}, 1)
424 | go func() {
425 | <-ch
426 | // do something
427 | }()
428 | ch <- struct{}{}
429 | // ...
430 | }
431 | ```
432 |
433 | 再比如,声明只包含方法的结构体。
434 |
435 | ```go
436 | type Lamp struct{}
437 |
438 | func (l Lamp) On() {
439 | println("On")
440 |
441 | }
442 | func (l Lamp) Off() {
443 | println("Off")
444 | }
445 | ```
446 |
447 |
448 |
449 |
450 |
--------------------------------------------------------------------------------
/qa-golang/qa-golang-2.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Go 语言笔试面试题(实现原理)
3 | seo_title: 极客面试
4 | date: 2020-09-04 23:10:10
5 | description: Go 语言/golang 笔试题,面试题,基础语法与内部实现原理,包括不限于垃圾回收机制(GC)、面向对象、并发编程等。
6 | tags:
7 | - Go
8 | nav: 面试
9 | categories:
10 | - Go 语言面试题
11 | image: post/qa-golang/go_questions.jpg
12 | github: https://github.com/geektutu/interview-questions
13 | ---
14 |
15 | 
16 |
17 | **[Go 语言笔试面试题汇总](https://geektutu.com/post/qa-golang.html),[Github](https://github.com/geektutu/interview-questions)**
18 |
19 | ## Q1 init() 函数是什么时候执行的?
20 |
21 |
22 | 答案
23 |
24 |
25 | `init()` 函数是 Go 程序初始化的一部分。Go 程序初始化先于 main 函数,由 runtime 初始化每个导入的包,初始化顺序不是按照从上到下的导入顺序,而是按照解析的依赖关系,没有依赖的包最先初始化。
26 |
27 | 每个包首先初始化包作用域的常量和变量(常量优先于变量),然后执行包的 `init()` 函数。同一个包,甚至是同一个源文件可以有多个 `init()` 函数。`init()` 函数没有入参和返回值,不能被其他函数调用,同一个包内多个 `init()` 函数的执行顺序不作保证。
28 |
29 | 一句话总结: import --> const --> var --> `init()` --> `main()`
30 |
31 | 示例:
32 |
33 | ```go
34 | package main
35 |
36 | import "fmt"
37 |
38 | func init() {
39 | fmt.Println("init1:", a)
40 | }
41 |
42 | func init() {
43 | fmt.Println("init2:", a)
44 | }
45 |
46 | var a = 10
47 | const b = 100
48 |
49 | func main() {
50 | fmt.Println("main:", a)
51 | }
52 | // 执行结果
53 | // init1: 10
54 | // init2: 10
55 | // main: 10
56 | ```
57 |
58 |
59 |
60 |
61 |
62 |
63 | ## Q2 Go 语言的局部变量分配在栈上还是堆上?
64 |
65 |
66 | 答案
67 |
68 |
69 | 由编译器决定。Go 语言编译器会自动决定把一个变量放在栈还是放在堆,编译器会做逃逸分析(escape analysis),当发现变量的作用域没有超出函数范围,就可以在栈上,反之则必须分配在堆上。
70 |
71 | ```go
72 | func foo() *int {
73 | v := 11
74 | return &v
75 | }
76 |
77 | func main() {
78 | m := foo()
79 | println(*m) // 11
80 | }
81 | ```
82 |
83 | `foo()` 函数中,如果 v 分配在栈上,foo 函数返回时,`&v` 就不存在了,但是这段函数是能够正常运行的。Go 编译器发现 v 的引用脱离了 foo 的作用域,会将其分配在堆上。因此,main 函数中仍能够正常访问该值。
84 |
85 |
86 |
87 |
88 |
89 | ## Q3 2 个 interface 可以比较吗?
90 |
91 |
92 | 答案
93 |
94 |
95 | Go 语言中,interface 的内部实现包含了 2 个字段,类型 `T` 和 值 `V`,interface 可以使用 `==` 或 `!=` 比较。2 个 interface 相等有以下 2 种情况
96 |
97 | 1) 两个 interface 均等于 nil(此时 V 和 T 都处于 unset 状态)
98 | 2) 类型 T 相同,且对应的值 V 相等。
99 |
100 | 看下面的例子:
101 |
102 | ```go
103 | type Stu struct {
104 | Name string
105 | }
106 |
107 | type StuInt interface{}
108 |
109 | func main() {
110 | var stu1, stu2 StuInt = &Stu{"Tom"}, &Stu{"Tom"}
111 | var stu3, stu4 StuInt = Stu{"Tom"}, Stu{"Tom"}
112 | fmt.Println(stu1 == stu2) // false
113 | fmt.Println(stu3 == stu4) // true
114 | }
115 | ```
116 |
117 | `stu1` 和 `stu2` 对应的类型是 `*Stu`,值是 Stu 结构体的地址,两个地址不同,因此结果为 false。
118 | `stu3` 和 `stu4` 对应的类型是 `Stu`,值是 Stu 结构体,且各字段相等,因此结果为 true。
119 |
120 |
121 |
122 |
123 |
124 |
125 | ## Q4 两个 nil 可能不相等吗?
126 |
127 |
128 | 答案
129 |
130 |
131 | 可能。
132 |
133 | 接口(interface) 是对非接口值(例如指针,struct等)的封装,内部实现包含 2 个字段,类型 `T` 和 值 `V`。一个接口等于 nil,当且仅当 T 和 V 处于 unset 状态(T=nil,V is unset)。
134 |
135 | - 两个接口值比较时,会先比较 T,再比较 V。
136 | - 接口值与非接口值比较时,会先将非接口值尝试转换为接口值,再比较。
137 |
138 | ```go
139 | func main() {
140 | var p *int = nil
141 | var i interface{} = p
142 | fmt.Println(i == p) // true
143 | fmt.Println(p == nil) // true
144 | fmt.Println(i == nil) // false
145 | }
146 | ```
147 |
148 | 上面这个例子中,将一个 nil 非接口值 p 赋值给接口 i,此时,i 的内部字段为`(T=*int, V=nil)`,i 与 p 作比较时,将 p 转换为接口后再比较,因此 `i == p`,p 与 nil 比较,直接比较值,所以 `p == nil`。
149 |
150 | 但是当 i 与 nil 比较时,会将 nil 转换为接口 `(T=nil, V=nil)`,与i `(T=*int, V=nil)` 不相等,因此 `i != nil`。因此 V 为 nil ,但 T 不为 nil 的接口不等于 nil。
151 |
152 |
153 |
154 |
155 |
156 | ## Q5 简述 Go 语言GC(垃圾回收)的工作原理
157 |
158 |
159 | 答案
160 |
161 |
162 | 最常见的垃圾回收算法有标记清除(Mark-Sweep) 和引用计数(Reference Count),Go 语言采用的是标记清除算法。并在此基础上使用了三色标记法和写屏障技术,提高了效率。
163 |
164 | 标记清除收集器是跟踪式垃圾收集器,其执行过程可以分成标记(Mark)和清除(Sweep)两个阶段:
165 |
166 | - 标记阶段 — 从根对象出发查找并标记堆中所有存活的对象;
167 | - 清除阶段 — 遍历堆中的全部对象,回收未被标记的垃圾对象并将回收的内存加入空闲链表。
168 |
169 | 标记清除算法的一大问题是在标记期间,需要暂停程序(Stop the world,STW),标记结束之后,用户程序才可以继续执行。为了能够异步执行,减少 STW 的时间,Go 语言采用了三色标记法。
170 |
171 | 三色标记算法将程序中的对象分成白色、黑色和灰色三类。
172 |
173 | - 白色:不确定对象。
174 | - 灰色:存活对象,子对象待处理。
175 | - 黑色:存活对象。
176 |
177 | 标记开始时,所有对象加入白色集合(这一步需 STW )。首先将根对象标记为灰色,加入灰色集合,垃圾搜集器取出一个灰色对象,将其标记为黑色,并将其指向的对象标记为灰色,加入灰色集合。重复这个过程,直到灰色集合为空为止,标记阶段结束。那么白色对象即可需要清理的对象,而黑色对象均为根可达的对象,不能被清理。
178 |
179 | 三色标记法因为多了一个白色的状态来存放不确定对象,所以后续的标记阶段可以并发地执行。当然并发执行的代价是可能会造成一些遗漏,因为那些早先被标记为黑色的对象可能目前已经是不可达的了。所以三色标记法是一个 false negative(假阴性)的算法。
180 |
181 | 三色标记法并发执行仍存在一个问题,即在 GC 过程中,对象指针发生了改变。比如下面的例子:
182 |
183 | ```bash
184 | A (黑) -> B (灰) -> C (白) -> D (白)
185 | ```
186 |
187 | 正常情况下,D 对象最终会被标记为黑色,不应被回收。但在标记和用户程序并发执行过程中,用户程序删除了 C 对 D 的引用,而 A 获得了 D 的引用。标记继续进行,D 就没有机会被标记为黑色了(A 已经处理过,这一轮不会再被处理)。
188 |
189 | ```bash
190 | A (黑) -> B (灰) -> C (白)
191 | ↓
192 | D (白)
193 | ```
194 |
195 | 为了解决这个问题,Go 使用了内存屏障技术,它是在用户程序读取对象、创建新对象以及更新对象指针时执行的一段代码,类似于一个钩子。垃圾收集器使用了写屏障(Write Barrier)技术,当对象新增或更新时,会将其着色为灰色。这样即使与用户程序并发执行,对象的引用发生改变时,垃圾收集器也能正确处理了。
196 |
197 | 一次完整的 GC 分为四个阶段:
198 |
199 | - 1)标记准备(Mark Setup,需 STW),打开写屏障(Write Barrier)
200 | - 2)使用三色标记法标记(Marking, 并发)
201 | - 3)标记结束(Mark Termination,需 STW),关闭写屏障。
202 | - 4)清理(Sweeping, 并发)
203 |
204 |
205 | - 参考 [fullstack](https://www.fullstack.cafe/golang)
206 |
207 |
208 |
209 |
210 |
211 |
212 | ## Q6 函数返回局部变量的指针是否安全?
213 |
214 |
215 | 答案
216 |
217 |
218 | 这在 Go 中是安全的,Go 编译器将会对每个局部变量进行逃逸分析。如果发现局部变量的作用域超出该函数,则不会将内存分配在栈上,而是分配在堆上。
219 |
220 |
221 |
222 |
223 |
224 | ## Q7 非接口非接口的任意类型 T() 都能够调用 `*T` 的方法吗?反过来呢?
225 |
226 |
227 | 答案
228 |
229 |
230 | - 一个T类型的值可以调用为`*T`类型声明的方法,但是仅当此T的值是可寻址(addressable) 的情况下。编译器在调用指针属主方法前,会自动取此T值的地址。因为不是任何T值都是可寻址的,所以并非任何T值都能够调用为类型`*T`声明的方法。
231 | - 反过来,一个`*T`类型的值可以调用为类型T声明的方法,这是因为解引用指针总是合法的。事实上,你可以认为对于每一个为类型 T 声明的方法,编译器都会为类型`*T`自动隐式声明一个同名和同签名的方法。
232 |
233 | 哪些值是不可寻址的呢?
234 |
235 | - 字符串中的字节;
236 | - map 对象中的元素(slice 对象中的元素是可寻址的,slice的底层是数组);
237 | - 常量;
238 | - 包级别的函数等。
239 |
240 | 举一个例子,定义类型 T,并为类型 `*T` 声明一个方法 `hello()`,变量 t1 可以调用该方法,但是常量 t2 调用该方法时,会产生编译错误。
241 |
242 | ```go
243 | type T string
244 |
245 | func (t *T) hello() {
246 | fmt.Println("hello")
247 | }
248 |
249 | func main() {
250 | var t1 T = "ABC"
251 | t1.hello() // hello
252 | const t2 T = "ABC"
253 | t2.hello() // error: cannot call pointer method on t
254 | }
255 | ```
256 |
257 |
258 |
259 |
--------------------------------------------------------------------------------
/qa-golang/qa-golang-3.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Go 语言笔试面试题(并发编程)
3 | seo_title: 极客面试
4 | date: 2020-09-05 23:10:10
5 | description: Go 语言/golang 笔试题,面试题,基础语法与内部实现原理,包括不限于垃圾回收机制(GC)、面向对象、并发编程等。
6 | tags:
7 | - Go
8 | nav: 面试
9 | categories:
10 | - Go 语言面试题
11 | image: post/qa-golang/go_questions.jpg
12 | github: https://github.com/geektutu/interview-questions
13 | ---
14 |
15 | 
16 |
17 | **[Go 语言笔试面试题汇总](https://geektutu.com/post/qa-golang.html),[Github](https://github.com/geektutu/interview-questions)**
18 |
19 | ## Q1 无缓冲的 channel 和 有缓冲的 channel 的区别?
20 |
21 |
22 | 答案
23 |
24 |
25 | 对于无缓冲的 channel,发送方将阻塞该信道,直到接收方从该信道接收到数据为止,而接收方也将阻塞该信道,直到发送方将数据发送到该信道中为止。
26 |
27 | 对于有缓存的 channel,发送方在没有空插槽(缓冲区使用完)的情况下阻塞,而接收方在信道为空的情况下阻塞。
28 |
29 | 例如:
30 |
31 | ```go
32 | func main() {
33 | st := time.Now()
34 | ch := make(chan bool)
35 | go func () {
36 | time.Sleep(time.Second * 2)
37 | <-ch
38 | }()
39 | ch <- true // 无缓冲,发送方阻塞直到接收方接收到数据。
40 | fmt.Printf("cost %.1f s\n", time.Now().Sub(st).Seconds())
41 | time.Sleep(time.Second * 5)
42 | }
43 | ```
44 |
45 | ```go
46 | func main() {
47 | st := time.Now()
48 | ch := make(chan bool, 2)
49 | go func () {
50 | time.Sleep(time.Second * 2)
51 | <-ch
52 | }()
53 | ch <- true
54 | ch <- true // 缓冲区为 2,发送方不阻塞,继续往下执行
55 | fmt.Printf("cost %.1f s\n", time.Now().Sub(st).Seconds()) // cost 0.0 s
56 | ch <- true // 缓冲区使用完,发送方阻塞,2s 后接收方接收到数据,释放一个插槽,继续往下执行
57 | fmt.Printf("cost %.1f s\n", time.Now().Sub(st).Seconds()) // cost 2.0 s
58 | time.Sleep(time.Second * 5)
59 | }
60 | ```
61 |
62 |
63 |
64 |
65 |
66 | ## Q2 什么是协程泄露(Goroutine Leak)?
67 |
68 |
69 | 答案
70 |
71 |
72 | 协程泄露是指协程创建后,长时间得不到释放,并且还在不断地创建新的协程,最终导致内存耗尽,程序崩溃。常见的导致协程泄露的场景有以下几种:
73 |
74 | - 缺少接收器,导致发送阻塞
75 |
76 | 这个例子中,每执行一次 query,则启动1000个协程向信道 ch 发送数字 0,但只接收了一次,导致 999 个协程被阻塞,不能退出。
77 |
78 | ```go
79 | func query() int {
80 | ch := make(chan int)
81 | for i := 0; i < 1000; i++ {
82 | go func() { ch <- 0 }()
83 | }
84 | return <-ch
85 | }
86 |
87 | func main() {
88 | for i := 0; i < 4; i++ {
89 | query()
90 | fmt.Printf("goroutines: %d\n", runtime.NumGoroutine())
91 | }
92 | }
93 | // goroutines: 1001
94 | // goroutines: 2000
95 | // goroutines: 2999
96 | // goroutines: 3998
97 | ```
98 |
99 | - 缺少发送器,导致接收阻塞
100 |
101 | 那同样的,如果启动 1000 个协程接收信道的信息,但信道并不会发送那么多次的信息,也会导致接收协程被阻塞,不能退出。
102 |
103 | - 死锁(dead lock)
104 |
105 | 两个或两个以上的协程在执行过程中,由于竞争资源或者由于彼此通信而造成阻塞,这种情况下,也会导致协程被阻塞,不能退出。
106 |
107 | - 无限循环(infinite loops)
108 |
109 | 这个例子中,为了避免网络等问题,采用了无限重试的方式,发送 HTTP 请求,直到获取到数据。那如果 HTTP 服务宕机,永远不可达,导致协程不能退出,发生泄漏。
110 |
111 | ```go
112 | func request(url string, wg *sync.WaitGroup) {
113 | i := 0
114 | for {
115 | if _, err := http.Get(url); err == nil {
116 | // write to db
117 | break
118 | }
119 | i++
120 | if i >= 3 {
121 | break
122 | }
123 | time.Sleep(time.Second)
124 | }
125 | wg.Done()
126 | }
127 |
128 | func main() {
129 | var wg sync.WaitGroup
130 | for i := 0; i < 1000; i++ {
131 | wg.Add(1)
132 | go request(fmt.Sprintf("https://127.0.0.1:8080/%d", i), &wg)
133 | }
134 | wg.Wait()
135 | }
136 | ```
137 |
138 |
139 |
140 |
141 | ## Q3 Go 可以限制运行时操作系统线程的数量吗?
142 |
143 |
144 | 答案
145 |
146 |
147 | > The GOMAXPROCS variable limits the number of operating system threads that can execute user-level Go code simultaneously. There is no limit to the number of threads that can be blocked in system calls on behalf of Go code; those do not count against the GOMAXPROCS limit.
148 |
149 | 可以使用环境变量 `GOMAXPROCS` 或 `runtime.GOMAXPROCS(num int)` 设置,例如:
150 |
151 | ```go
152 | runtime.GOMAXPROCS(1) // 限制同时执行Go代码的操作系统线程数为 1
153 | ```
154 |
155 | 从官方文档的解释可以看到,`GOMAXPROCS` 限制的是同时执行用户态 Go 代码的操作系统线程的数量,但是对于被系统调用阻塞的线程数量是没有限制的。`GOMAXPROCS` 的默认值等于 CPU 的逻辑核数,同一时间,一个核只能绑定一个线程,然后运行被调度的协程。因此对于 CPU 密集型的任务,若该值过大,例如设置为 CPU 逻辑核数的 2 倍,会增加线程切换的开销,降低性能。对于 I/O 密集型应用,适当地调大该值,可以提高 I/O 吞吐率。
156 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/qa-golang/qa-golang-c1.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Go 语言笔试面试题(代码输出)
3 | seo_title: 极客面试
4 | date: 2020-10-10 23:10:10
5 | description: Go 语言/golang 笔试题,面试题,基础语法与内部实现原理,包括不限于垃圾回收机制(GC)、面向对象、并发编程等。
6 | tags:
7 | - Go
8 | nav: 面试
9 | categories:
10 | - Go 语言面试题
11 | image: post/qa-golang/go_questions.jpg
12 | github: https://github.com/geektutu/interview-questions
13 | ---
14 |
15 | 
16 |
17 | **[Go 语言笔试面试题汇总](https://geektutu.com/post/qa-golang.html),[Github](https://github.com/geektutu/interview-questions)**
18 |
19 | ## 常量与变量
20 |
21 | 1. 下列代码的输出是:
22 |
23 | ```go
24 | func main() {
25 | const (
26 | a, b = "golang", 100
27 | d, e
28 | f bool = true
29 | g
30 | )
31 | fmt.Println(d, e, g)
32 | }
33 |
34 | ```
35 |
36 |
37 | 答案
38 |
39 |
40 | golang 100 true
41 |
42 | 在同一个 const group 中,如果常量定义与前一行的定义一致,则可以省略类型和值。编译时,会按照前一行的定义自动补全。即等价于
43 |
44 | ```go
45 | func main() {
46 | const (
47 | a, b = "golang", 100
48 | d, e = "golang", 100
49 | f bool = true
50 | g bool = true
51 | )
52 | fmt.Println(d, e, g)
53 | }
54 | ```
55 |
56 |
57 |
58 |
59 | 2. 下列代码的输出是:
60 |
61 | ```go
62 | func main() {
63 | const N = 100
64 | var x int = N
65 |
66 | const M int32 = 100
67 | var y int = M
68 | fmt.Println(x, y)
69 | }
70 | ```
71 |
72 |
73 | 答案
74 |
75 |
76 | 编译失败:cannot use M (type int32) as type int in assignment
77 |
78 | Go 语言中,常量分为无类型常量和有类型常量两种,`const N = 100`,属于无类型常量,赋值给其他变量时,如果字面量能够转换为对应类型的变量,则赋值成功,例如,`var x int = N`。但是对于有类型的常量 `const M int32 = 100`,赋值给其他变量时,需要类型匹配才能成功,所以显示地类型转换:
79 |
80 | ```go
81 | var y int = int(M)
82 | ```
83 |
84 |
85 |
86 |
87 |
88 | 3. 下列代码的输出是:
89 |
90 | ```go
91 | func main() {
92 | var a int8 = -1
93 | var b int8 = -128 / a
94 | fmt.Println(b)
95 | }
96 | ```
97 |
98 |
99 | 答案
100 |
101 |
102 | -128
103 |
104 | int8 能表示的数字的范围是 [-2^7, 2^7-1],即 [-128, 127]。-128 是无类型常量,转换为 int8,再除以变量 -1,结果为 128,常量除以变量,结果是一个变量。变量转换时允许溢出,符号位变为1,转为补码后恰好等于 -128。
105 |
106 | 对于有符号整型,最高位是是符号位,计算机用补码表示负数。补码 = 原码取反加一。
107 |
108 | 例如:
109 |
110 | ```bash
111 | -1 : 11111111
112 | 00000001(原码) 11111110(取反) 11111111(加一)
113 | -128:
114 | 10000000(原码) 01111111(取反) 10000000(加一)
115 |
116 | -1 + 1 = 0
117 | 11111111 + 00000001 = 00000000(最高位溢出省略)
118 | -128 + 127 = -1
119 | 10000000 + 01111111 = 11111111
120 | ```
121 |
122 |
123 |
124 |
125 | 4. 下列代码的输出是:
126 |
127 | ```go
128 | func main() {
129 | const a int8 = -1
130 | var b int8 = -128 / a
131 | fmt.Println(b)
132 | }
133 | ```
134 |
135 |
136 | 答案
137 |
138 |
139 | 编译失败:constant 128 overflows int8
140 |
141 | -128 和 a 都是常量,在编译时求值,-128 / a = 128,两个常量相除,结果也是一个常量,常量类型转换时不允许溢出,因而编译失败。
142 |
143 |
144 |
145 |
146 | ## 作用域
147 |
148 | 1. 下列代码的输出是:
149 |
150 | ```go
151 | func main() {
152 | var err error
153 | if err == nil {
154 | err := fmt.Errorf("err")
155 | fmt.Println(1, err)
156 | }
157 | if err != nil {
158 | fmt.Println(2, err)
159 | }
160 | }
161 | ```
162 |
163 |
164 | 答案
165 |
166 |
167 | 1 err
168 |
169 | `:=` 表示声明并赋值,`=` 表示仅赋值。
170 |
171 | 变量的作用域是大括号,因此在第一个 if 语句 `if err == nil` 内部重新声明且赋值了与外部变量同名的局部变量 err。对该局部变量的赋值不会影响到外部的 err。因此第二个 if 语句 `if err != nil` 不成立。所以只打印了 `1 err`。
172 |
173 |
174 |
175 |
176 | ## defer 延迟调用
177 |
178 | 1. 下列代码的输出是:
179 |
180 | ```go
181 | type T struct{}
182 |
183 | func (t T) f(n int) T {
184 | fmt.Print(n)
185 | return t
186 | }
187 |
188 | func main() {
189 | var t T
190 | defer t.f(1).f(2)
191 | fmt.Print(3)
192 | }
193 | ```
194 |
195 |
196 |
197 | 答案
198 |
199 |
200 | 132
201 |
202 | defer 延迟调用时,需要保存函数指针和参数,因此链式调用的情况下,除了最后一个函数/方法外的函数/方法都会在调用时直接执行。也就是说 `t.f(1)` 直接执行,然后执行 `fmt.Print(3)`,最后函数返回时再执行 `.f(2)`,因此输出是 132。
203 |
204 |
205 |
206 |
207 | 2. 下列代码的输出是:
208 |
209 | ```go
210 | func f(n int) {
211 | defer fmt.Println(n)
212 | n += 100
213 | }
214 |
215 | func main() {
216 | f(1)
217 | }
218 | ```
219 |
220 |
221 | 答案
222 |
223 |
224 | 1
225 |
226 | 打印 1 而不是 101。defer 语句执行时,会将需要延迟调用的函数和参数保存起来,也就是说,执行到 defer 时,参数 n(此时等于1) 已经被保存了。因此后面对 n 的改动并不会影响延迟函数调用的结果。
227 |
228 |
229 |
230 |
231 | 3. 下列代码的输出是:
232 |
233 | ```go
234 | func main() {
235 | n := 1
236 | defer func() {
237 | fmt.Println(n)
238 | }()
239 | n += 100
240 | }
241 | ```
242 |
243 |
244 | 答案
245 |
246 |
247 | 101
248 |
249 | 匿名函数没有通过传参的方式将 n 传入,因此匿名函数内的 n 和函数外部的 n 是同一个,延迟执行时,已经被改变为 101。
250 |
251 |
252 |
253 |
254 | 4. 下列代码的输出是:
255 |
256 | ```go
257 | func main() {
258 | n := 1
259 | if n == 1 {
260 | defer fmt.Println(n)
261 | n += 100
262 | }
263 | fmt.Println(n)
264 | }
265 | ```
266 |
267 |
268 | 答案
269 |
270 |
271 | ```
272 | 101
273 | 1
274 | ```
275 |
276 | 先打印 101,再打印 1。defer 的作用域是函数,而不是代码块,因此 if 语句退出时,defer 不会执行,而是等 101 打印后,整个函数返回时,才会执行。
277 |
278 |
279 |
280 |
281 |
282 |
--------------------------------------------------------------------------------
/qa-golang/qa-golang.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Go 语言笔试面试题汇总
3 | seo_title: 极客面试
4 | date: 2020-09-04 20:10:10
5 | description: Go 语言/golang 笔试题,面试题,基础语法与内部原理/实现,包括不限于垃圾回收机制(GC)、面向对象、并发编程等。
6 | tags:
7 | - Go
8 | nav: 面试
9 | categories:
10 | - Go 语言面试题
11 | top: 2
12 | image: post/qa-golang/go_questions.jpg
13 | github: https://github.com/geektutu/interview-questions
14 | ---
15 |
16 | 
17 |
18 | **[Go 语言笔试面试题汇总](https://geektutu.com/post/qa-golang.html),[Github](https://github.com/geektutu/interview-questions)**
19 |
20 | ## [基础语法](https://geektutu.com/post/qa-golang-1.html)
21 |
22 | - 01 `=` 和 `:=` 的区别?
23 | - 02 指针的作用
24 | - 03 Go 允许多个返回值吗?
25 | - 04 Go 有异常类型吗?
26 | - 05 什么是协程(Goroutine)
27 | - 06 如何高效地拼接字符串
28 | - 07 什么是 rune 类型
29 | - 08 如何判断 map 中是否包含某个 key ?
30 | - 09 Go 支持默认参数或可选参数吗?
31 | - 10 defer 的执行顺序
32 | - 11 如何交换 2 个变量的值?
33 | - 12 Go 语言 tag 的用处?
34 | - 13 如何判断 2 个字符串切片(slice) 是相等的?
35 | - 14 字符串打印时,`%v` 和 `%+v` 的区别
36 | - 15 Go 语言中如何表示枚举值(enums)?
37 | - 16 空 struct{} 的用途
38 |
39 | ## [实现原理](https://geektutu.com/post/qa-golang-2.html)
40 |
41 | - 01 init() 函数是什么时候执行的?
42 | - 02 Go 语言的局部变量分配在栈上还是堆上?
43 | - 03 2 个 interface 可以比较吗 ?
44 | - 04 2 个 nil 可能不相等吗?
45 | - 05 简述 Go 语言GC(垃圾回收)的工作原理
46 | - 06 函数返回局部变量的指针是否安全?
47 | - 07 非接口非接口的任意类型 T() 都能够调用 `*T` 的方法吗?反过来呢?
48 |
49 | ## [并发编程](https://geektutu.com/post/qa-golang-3.html)
50 |
51 | - 01 无缓冲的 channel 和有缓冲的 channel 的区别?
52 | - 02 什么是协程泄露(Goroutine Leak)?
53 | - 03 Go 可以限制运行时操作系统线程的数量吗?
54 |
55 | ## [代码输出](https://geektutu.com/post/qa-golang-c1.html)
56 |
57 | - 变量与常量
58 | - 作用域
59 | - defer 延迟调用
--------------------------------------------------------------------------------
/qa-golang/qa-golang/go_questions.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/qa-golang/qa-golang/go_questions.jpg
--------------------------------------------------------------------------------
/qa-ml/qa-ml-1-svm-pylot.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 |
4 | plt.axis([-3, 3, -3, 3])
5 |
6 | points_a = np.array([(-1, 1), (1, -1), (-1, -1)])
7 | points_b = np.array([(1, 1), (2, 0), (2, 1)])
8 |
9 | plt.scatter(points_a[:,0], points_a[:,1], color='red', s=10**2)
10 | plt.scatter(points_b[:,0], points_b[:,1], color='blue', s=10**2)
11 |
12 | for _x, _y in np.concatenate([points_a, points_b]):
13 | plt.text(_x - 0.5, _y - 0.5, '({}, {})'.format(_x, _y), fontsize=16)
14 |
15 | plt.show()
16 |
--------------------------------------------------------------------------------
/qa-ml/qa-ml-1.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 机器学习笔试面试题 1-10
3 | seo_title: 极客面试
4 | date: 2019-08-04 00:10:10
5 | description: 机器学习(machine learning)/深度学习(deep learning)/面试笔试题(interview questions),吴恩达(Andrew Ng)机器学习课程(machine learning course)课后习题,CMU 考试题和答案。
6 | tags:
7 | - 机器学习
8 | nav: 面试
9 | categories:
10 | - 机器学习面试题
11 | image: post/qa-ml-1/6_svm.jpg
12 | github: https://github.com/geektutu/interview-questions
13 | ---
14 |
15 | 声明:所有习题系博主花费大量精力整理,请尊重劳动成果,禁止转载。
16 |
17 | **机器学习(machine learning)深度学习(deep learning)**
18 | **面试笔试题(interview questions)/课程课后考试习题解答**
19 | **[机器学习笔试面试题汇总](https://geektutu.com/post/qa-ml.html),[Github](https://github.com/geektutu/interview-questions)**
20 |
21 | ## Q1 决策树
22 |
23 | 使用决策树分类时,如果输入的某个特征的值是连续的,通常使用二分法对连续属性离散化,即根据是否大于/小于某个阈值进行划分。如果采用多路划分,每个出现的值都划分为一个分支,这种方式的最大问题是:
24 |
25 | - A 计算量太大
26 | - B 训练集和测试集表现都很差
27 | - C 训练集表现良好,测试集表现差
28 | - D 训练集表现差,测试集表现良好
29 |
30 |
31 | 答案
32 |
33 |
34 | **C** 连续值通常采用二分法,离散特征通常采用多路划分的方法,但分支数不宜过多。
35 | 连续特征每个值都划分为一个分支,容易过拟合,泛化能力差,导致训练集表现好,测试集表现差。
36 |
37 |
38 |
39 | ## Q2 朴素贝叶斯
40 |
41 | 输入属性是 A, B, C,输出属性是 Y。若使用朴素贝叶斯分类(Naive Bayes Classifier),下面哪张图能表示朴素贝叶斯分类的假设。
42 |
43 | 
44 |
45 |
46 | 答案
47 |
48 |
49 | **C** 朴素贝叶斯分类器是机器学习一个特别质朴而深刻的模型:当要根据多个特征而非一个特征对数据进行分类时,假设这些特征相互独立,然后利用条件概率乘法法则得到每一个分类的概率,选择概率最大的那个作为输出。
50 |
51 | 回顾一下贝叶斯公式 P(Y|A,B,C) = P(A,B,C|Y) * P(Y) / P(A,B,C),如果需要求在A,B,C条件下Y的概率,则需要知道先验概率P(A,B,C)和P(Y),和在Y条件下,A,B,C的概率。
52 |
53 |
54 |
55 | ## Q3 神经网络
56 |
57 | 对神经网络(neural network)而言,哪一项对过拟合(overfitting)和欠拟合(underfitting)影响最大。
58 |
59 | - A 隐藏层节点(hidden nodes)数量
60 | - B 学习速率(learning rate)
61 | - C 初始权重
62 | - D 每一次训练的输入个数固定
63 |
64 |
65 | 答案
66 |
67 |
68 | **A** 过拟合和欠拟合与神经网络的复杂程度有关,模型越大越容易过拟合。隐藏层节点数量直接决定了模型的大小与复杂程度。
69 |
70 |
71 |
72 | ## Q4 回归
73 |
74 | 对多项式回归(polynomial regression)而言,哪一项对过拟合(overfitting)和欠拟合(underfitting)影响最大。
75 |
76 | - A 多项式的度(polynomial degree)
77 | - B 是否通过矩阵求逆/梯度下降学习权重
78 | - C 高斯噪声方差(variance of the Gaussian noise)
79 | - D 每一次训练的输入个数固定
80 |
81 |
82 | 答案
83 |
84 |
85 | **A** 多拟合/欠拟合与模型复杂度有关,和模型复杂度最相关的是多项式的度。举一个极端的例子,度为1,则是线性回归,y=kx+b,一条直线分类,很容易欠拟合。那度比较大时,则能表示更为复杂的曲线,容易过拟合。
86 |
87 |
88 |
89 | ## Q5 特征缩放
90 |
91 | 特征缩放(feature scaling)的作用?
92 |
93 | - A 降低每次迭代计算成本加速梯度下降
94 | - B 防止陷入局部最优
95 | - C 加快了标准方程(Normal Equation)的求解
96 | - D 相同的训练效果迭代次数更少,从而加速了梯度下降。
97 |
98 |
99 | 答案
100 |
101 |
102 | **D** 如果某个特征比其他特征值大得多,则需要付出额外的迭代成本。因此训练前,进行特征缩放可以避免额外的迭代,快速达到预期效果。最常用的方法,比如归一化。将所有的特征的值缩放到0-1之间。
103 |
104 |
105 |
106 | ## Q6 SVM
107 |
108 | 在下面的二元标签数据集上训练线性支持向量机(Support Vector Machine, SVM)模型
109 |
110 | ```bash
111 | +:(-1, 1), (1, -1), (-1, -1)
112 | -:(1, 1), (2, 0), (2, 1)
113 | ```
114 |
115 | 请问,这个模型中的支持向量是哪些?
116 |
117 | - A (-1, 1), (1, 1), (2, 1)
118 | - B (-1, 1), (-1, -1), (2, 1)
119 | - C (-1, 1), (1, -1), (1, 1), (2,0)
120 |
121 |
122 | 答案
123 |
124 |
125 | 
126 |
127 | **C** 先将坐标点画出来,问自己一个问题,是不是所有的点对于分割线的位置起决定性作用?
128 |
129 | 其实在特别远的区域,无论增加多少个样本点,也不会影响分割线的位置,因为分割线是由几个关键点决定的(图上四个),这几个关键点支撑起了一个分割超平面,这四个关键点,就是支持向量。
130 |
131 |
132 |
133 | ## Q7 过拟合
134 |
135 | 下列哪个模型过拟合(Overfit)了。
136 |
137 | 
138 |
139 |
140 | 答案
141 |
142 |
143 | **B** 拟合曲线紧跟数据集且复杂很高,表明过度拟合了训练集。
144 |
145 |
146 |
147 | ## Q8 误差
148 |
149 | 经验误差(empirical error)与泛化误差(generalization error)分别指?
150 |
151 |
152 | 答案
153 |
154 |
155 | - 经验误差: 也叫训练误差(training error),模型在训练集上的误差。
156 | - 泛化误差: 模型在新样本集(测试集)上的误差。
157 |
158 |
159 |
160 | ## Q9 交叉验证
161 |
162 | 简述 K折交叉验证(k-fold crossValidation)。
163 |
164 |
165 | 答案
166 |
167 |
168 | - 数据集大小为N,分成K份,则每份含有样本N/K个。每次选择其中1份作为测试集,另外K-1份作为训练集,共K种情况。
169 | - 在每种情况中,训练集训练模型,用测试集测试模型,计算模型的泛化误差。
170 | - 将K种情况下,模型的泛化误差取均值,得到模型最终的泛化误差。
171 |
172 |
173 |
174 | ## Q10 类别不平衡
175 |
176 | 如何处理数据中的“类别不平衡”?例如二分类问题,训练集中80%分类为A,20%分类为B。
177 |
178 |
179 | 答案
180 |
181 |
182 | - **简单方法**
183 | - 数据多的欠采样(under-sampling),舍弃一部分数据,使其与较少类别的数据相当。
184 | - 数据少的过采样(over-sampling),即重复使用一部分数据,使其与较多类别的数据相当。
185 | - 阈值调整(threshold moving,例如数据均衡时,阈值为0.5,那么可以按比例,例如调整到 0.8。
186 |
187 | - **复杂方法**
188 | - 数据采样过程中,生成并插样“少数类别”数据,代表算法 SMOTE 和 ADASYN。
189 | - 数据先聚类,“多数类别”随机欠采样,“少数类别”数据生成。
190 | - 随机欠采样容易丢失重要信息,可结合集成学习欠采样,代表算法:EasyEnsemble。利用集成学习机制,将大类划分为若干个集合供不同的学习器使用。相当于对每个学习器欠采样,避免全局丢失重要信息。
191 |
192 |
193 |
194 |
195 | ## 附:题目主要来源
196 |
197 | - [Machine Learning exam - CMU](http://www.cs.cmu.edu/~tom/10701_sp11/prev.shtml)
198 | - [Andrew Ng - coursera](https://www.coursera.org/learn/machine-learning)
--------------------------------------------------------------------------------
/qa-ml/qa-ml-1/6_svm.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/qa-ml/qa-ml-1/6_svm.jpg
--------------------------------------------------------------------------------
/qa-ml/qa-ml-1/nbc.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/qa-ml/qa-ml-1/nbc.jpg
--------------------------------------------------------------------------------
/qa-ml/qa-ml-1/overfit.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/qa-ml/qa-ml-1/overfit.jpg
--------------------------------------------------------------------------------
/qa-ml/qa-ml-2.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 机器学习笔试面试题 11-20
3 | seo_title: 极客面试
4 | date: 2019-08-06 00:10:10
5 | description: 机器学习(machine learning)/深度学习(deep learning)/面试笔试题(interview questions),吴恩达(Andrew Ng)机器学习课程(machine learning course)课后习题,CMU 考试题和答案。
6 | tags:
7 | - 机器学习
8 | nav: 面试
9 | categories:
10 | - 机器学习面试题
11 | image: post/qa-ml-2/boosting.jpg
12 | github: https://github.com/geektutu/interview-questions
13 | ---
14 |
15 | 声明:所有习题系博主花费大量精力整理,请尊重劳动成果,禁止转载。
16 |
17 | **机器学习(machine learning)深度学习(deep learning)**
18 | **面试笔试题(interview questions)/课程课后考试习题解答**
19 | **[机器学习笔试面试题汇总](https://geektutu.com/post/qa-ml.html),[Github](https://github.com/geektutu/interview-questions)**
20 |
21 |
22 | ## Q11 - 皮尔逊相关系数
23 |
24 | 两个变量的 Pearson 相关性系数为零,但这两个变量的值同样可以相关?
25 |
26 | - A 正确
27 | - B 错误
28 |
29 |
30 | 答案
31 |
32 |
33 | **A** Pearson相关系数只能衡量线性相关性,但无法衡量非线性关系。如y=x^2,x和y有很强的非线性关系。
34 |
35 | 在数据标准化后,Pearson相关性系数、余弦相似(Cosine相似度)、欧式距离的平方可认为是等价的。这三种方法都是用来度量线性相关性的。
36 |
37 | 参考:[如何理解皮尔逊相关系数(Pearson Correlation Coefficient) - 知乎](https://www.zhihu.com/question/19734616)
38 |
39 |
40 |
41 |
42 | ## Q12 - 信息熵
43 |
44 | 计算变量 [0,0,1,1,1] 的信息熵。
45 |
46 | - A -(3/5 log(3/5) + 2/5 log(2/5))
47 | - B 3/5 log(3/5) + 2/5 log(2/5)
48 | - C 2/5 log(3/5) + 3/5 log(2/5)
49 | - D 3/5 log(2/5) – 2/5 log(3/5)
50 |
51 |
52 | 答案
53 |
54 |
55 | **A**,公式:H(X) = -sum(p(xi) * log(p(xi))) (i = 1, 2, 3, ... , n)
56 |
57 | 香农的信息熵本质上是对“不确定现象”的数学化度量。
58 |
59 | 例如,如果我们用1代表下雨,0代表不下雨。[0,0,1,1,1]代表有 3/5 的概率下雨,信息熵是 0.97;而 [1,1,1,1,1] 代表100%的概率下雨,信息熵是 -1 * log(5/5) = 0。
60 |
61 | 完全确定的事件,信息熵为0;信息熵越大,代表不确定性越大。
62 |
63 | 参考:[信息熵是什么?- 知乎](https://www.zhihu.com/question/22178202)
64 |
65 |
66 |
67 |
68 | ## Q13 - 数据归一化
69 |
70 | 数据预处理阶段,对数值特征归一化或标准化,理论上不会对哪种模型产生很大影响。
71 |
72 | - A 决策树
73 | - B k-means
74 | - C kNN
75 |
76 |
77 |
78 | 答案
79 |
80 |
81 | **A** k-means和kNN(k-NearestNeighbor)都需要使用距离。而决策树对于数值特征,只在乎其大小排序,而非绝对大小。不管是标准化或者归一化,都不会影响数值之间的相对大小。
82 |
83 |
84 |
85 |
86 | ## Q14 - 神经网络
87 |
88 | 某个神经网络的激活函数是 ReLU,若使用线性激活函数代替 ReLU,那么该神经网络还能表征异或(XNOR)函数吗?
89 |
90 | - A 可以
91 | - B 不可以
92 |
93 |
94 | 答案
95 |
96 |
97 | **B** 线性激活函数不能解决非线性问题,异或(XNOR)关系是非线性的。
98 |
99 | 常用的非线性激活函数有:sigmoid,tanh,softplus,Relu。
100 |
101 | 其中 Relu 的函数表达式为:y = max(0, x)
102 |
103 |
104 |
105 |
106 | ## Q15 - Batch
107 |
108 | 机器学习训练时,Mini-Batch 的大小优选为2的幂,如 64 或 128,原因是?
109 |
110 | - A 设置为偶数,梯度下降算法训练更快
111 | - B GPU 对2的幂次的 batch 可以发挥更佳的性能,利于并行化处理
112 | - C 设置为奇数,损失函数不稳定
113 |
114 |
115 | 答案
116 |
117 |
118 | **B**
119 |
120 |
121 |
122 | ## Q16 - 降维
123 |
124 | 下列不属于降维算法的是?
125 |
126 | - A 主成分分析(Principal Component Analysis,PCA)
127 | - B 线性判别分析(Linear Discriminant Analysis, LDA)
128 | - C 逻辑回归(Logistic Regression, LR)
129 |
130 |
131 | 答案
132 |
133 |
134 | **C** PCA 和 LDA 都是常用的降维算法。LDA作用于带标签数据,PCA作用于无标签数据。
135 |
136 | LDA的原理是,将带上标签的数据(点),通过投影的方法,投影到维度更低的空间中,使得投影后的点,会形成按类别区分,一簇一簇的情况,相同类别的点,将会在投影后的空间中更接近。
137 |
138 | PCA的原理是,通过正交变换将一组可能存在相关性的变量转换为一组线性不相关的变量,转换后的这组变量叫主成分。
139 |
140 | 参考:[主成分分析](https://zh.wikipedia.org/wiki/%E4%B8%BB%E6%88%90%E5%88%86%E5%88%86%E6%9E%90)
141 |
142 |
143 |
144 |
145 |
146 | ## Q17 - 曼哈顿距离&欧式距离
147 |
148 | 计算 (1, 3), (4, 7) 的曼哈顿距离(L1距离)和欧氏距离(L2距离)
149 |
150 |
151 | 答案
152 |
153 |
154 | L1:|1-4| + |3-7| = 7
155 | L2: sqrt((1-4)^2 + (3-7)^2) = 5
156 |
157 |
158 |
159 |
160 | ## Q18 - 召回率和准确率
161 |
162 | 召回率(Recall)和准确率 (Precision)的区别。
163 |
164 |
165 | 答案
166 |
167 |
168 | 准确率和召回率是广泛用于信息检索和统计学分类领域的两个度量值,用来评价结果的质量。其中精度是检索出相关文档数与检索出的文档总数的比率,衡量的是检索系统的查准率;召回率是指检索出的相关文档数和文档库中所有的相关文档数的比率,衡量的是检索系统的查全率。
169 |
170 | 简而言之:
171 |
172 | 召回率 (Recall):正样本有多少被找出来了(**召回了多少**)。
173 | 准确率 (Precision):你认为的正样本,有多少猜对了(**猜的准确性如何**)。
174 |
175 | 举个例子:1000辆卡车,5辆有质量问题。选取了其中10辆,其中有3辆有质量问题。那么找到有质量问题的卡车的准确率为 3/10,召回率为 3/5。
176 |
177 | 参考:[如何解释召回率与准确率? - 知乎](https://www.zhihu.com/question/19645541)
178 |
179 |
180 |
181 | ## Q19 - Boosting
182 |
183 | 简介Boosting方法原理。
184 |
185 | 
186 |
187 | 图片来源:[A Quick Guide to Boosting in ML - Medium](https://medium.com/greyatom/a-quick-guide-to-boosting-in-ml-acf7c1585cb5)
188 |
189 |
190 | 答案
191 |
192 |
193 | boosting算法是一类将弱学习器提升为强学习器的集成学习算法,它通过改变训练样本的权值,学习多个分类器,并将这些分类器进行线性组合,提高泛化性能。
194 |
195 | 先介绍一下“强学习”和“弱学习”的概念:一个分类,如果存在一个多项式算法能够学习他,并得到很高的正确率,那么这个算法称为强学习器,反之如果正确率只是稍大于随机猜测(50%),则称为弱学习器。在实际情况中,我们往往会发现弱学习器比强学习器更容易获得,所以就有了能否把弱学习器提升(boosting)为强学习器的疑问。于是提升类方法应运而生,它代表了一类从弱学习器出发,反复训练,得到一系列弱学习器,然后组合这些弱学习器,构成一个强学习器的算法。大多数boost方法会改变数据的概率分布(改变数据权值),具体而言就是提高前一轮训练中被错分类的数据的权值,降低正确分类数据的权值,使得被错误分类的数据在下轮的训练中更受关注;然后根据不同分布调用弱学习算法得到一系列弱学习器实现的,再将这些学习器线性组合,具体组合方法是误差率小的学习器会被增大权值,误差率大的学习器会被减小权值,典型代表adaboost算法。
196 |
197 |
198 |
199 |
200 | ## Q20 - 随机森林
201 |
202 | 随机森林的随机性体现在哪里?
203 |
204 |
205 | 答案
206 |
207 |
208 | 随机森林是一个包含多个决策树的分类器,并且其输出的类别是由个别树输出的类别的众数而定。随机森林的随机性体现在每颗树的训练样本是随机的,树中每个节点的分裂属性集合也是随机选择确定的。有了这2个随机的保证,随机森林就不会产生过拟合的现象了。
209 |
210 | 随机森林是用一种随机的方式建立的一个森林,森林是由很多棵决策树组成的,每棵树所分配的训练样本是随机的,树中每个节点的分裂属性集合也是随机选择确定的。
211 |
212 | 参考:[独家 | 一文读懂随机森林的解释和实现 - 知乎](https://zhuanlan.zhihu.com/p/51165358)
213 |
214 |
215 |
--------------------------------------------------------------------------------
/qa-ml/qa-ml-2/boosting.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/qa-ml/qa-ml-2/boosting.jpg
--------------------------------------------------------------------------------
/qa-ml/qa-ml.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 机器学习笔试面试题汇总
3 | seo_title: 极客面试
4 | date: 2019-08-03 20:10:10
5 | description: 机器学习(machine learning)/深度学习(deep learning)/面试笔试题(interview questions),吴恩达(Andrew Ng)机器学习课程(machine learning course)课后习题,CMU 考试题和答案。
6 | tags:
7 | - 机器学习
8 | nav: 面试
9 | categories:
10 | - 机器学习面试题
11 | image: post/qa-ml/interview.jpg
12 | github: https://github.com/geektutu/interview-questions
13 | ---
14 |
15 | **机器学习(machine learning)深度学习(deep learning)**
16 | **面试笔试题(interview questions)/课程课后考试习题解答**
17 | **[机器学习笔试面试题汇总](https://geektutu.com/post/qa-ml.html),[Github](https://github.com/geektutu/interview-questions)**
18 |
19 | ## [1-10](https://geektutu.com/post/qa-ml-1.html)
20 |
21 | - 01 (单选)决策树对连续值特征多路划分的最大问题是
22 | - 02 (单选)下面哪张图能表示朴素贝叶斯分类的假设
23 | - 03 (单选)对神经网络而言,哪一项对过拟合和欠拟合影响最大
24 | - 04 (单选)对多项式回归而言,哪一项对过拟合和欠拟合影响最大
25 | - 05 (单选)特征缩放的作用
26 | - 06 (单选)在二元标签数据集上训练线性支持向量机模型,支持向量是哪些
27 | - 07 (单选)下列哪个模型过拟合了
28 | - 08 (简答)经验误差与泛化误差分别指
29 | - 09 (简答)简述 K折交叉验证
30 | - 10 (简答)如何处理数据中的“类别不平衡”?
31 |
32 | ## [11-20](https://geektutu.com/post/qa-ml-2.html)
33 |
34 | - 11 (单选)两个变量的 Pearson 相关性系数为零,但仍可以相关?
35 | - 12 (单选)计算变量 [0,0,1,1,1] 的信息熵。
36 | - 13 (单选)数据预处理阶段,对数值特征归一化或标准化,理论上不会对哪种模型产生很大影响。
37 | - 14 (单选)线性激活函数能表征异或(XNOR)函数吗?
38 | - 15 (单选)机器学习训练时,Mini-Batch 的大小优选为2的幂,如 64 或 128,原因是?
39 | - 16 (单选)下列不属于降维算法的是?
40 | - 17 (简答)计算 (1, 3), (4, 7) 的曼哈顿距离(L1距离)和欧氏距离(L2距离)
41 | - 18 (简答)召回率(Recall)和准确率 (Precision)的区别。
42 | - 19 (简答)简介Boosting方法原理
43 | - 20 (简答)随机森林的随机性体现在哪里?
--------------------------------------------------------------------------------
/qa-ml/qa-ml/interview.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geektutu/interview-questions/08564a38fbbed2d4fe4b9d46e952666b5e4e0ae2/qa-ml/qa-ml/interview.jpg
--------------------------------------------------------------------------------
/ts.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | def main(filename):
4 | if not filename.endswith(".bak"):
5 | raise "need a backup file"
6 | print(filename)
7 | s = ""
8 | with open(filename) as f:
9 | end = False
10 | for line in f:
11 | if line.startswith("## "):
12 | if end:
13 | s += "\n\n\n\n"
14 | end = False
15 | s += line
16 | print(line.replace("##", "-"), end="")
17 | s += "\n\n答案
\n\n"
18 | end = True
19 | else:
20 | s += line
21 | s += "\n
\n \n\n"
22 |
23 |
24 | with open(filename.strip(".bak"), "w") as f:
25 | f.write(s)
26 |
27 |
28 | main(sys.argv[1])
--------------------------------------------------------------------------------