面试的感受

1,铂涛旅行
投递的是大数据开发工程师,面试的时候是ETL工程师
流程:先写一份试卷,试卷内容大致如下:
1,数据维度的概念,结合平时相关
2,数据库和数据仓库的区别
3,用过什么ETL工具
4,做一道题目
面试主要注重的是数据的采集,要想好怎么答结合平时工作

2,青木科技
这是一家比较不正规的公司
第一轮面试,算是负责人面试问问你做过什么之类的,主要是会Hase和写一些python脚本,在懂一些linxu定时之类的东西
第二轮哪里杀出来的两个人说前面面试我的两个人要走了,问我能不能一来就接替他们的手头工作,而且就只有我一个人,没有其他人做了,全程问了很多次能不能直接上手,估计换成谁都很无语
第三轮说是hr面试但是我没有见到,被刷了
总体,在面试过程中知道加班超级多,工资一般而且搞大数据的人很少,如果有人去这家公司的话,当做赚个面试经验吧

3,久邦数码
最讨厌的一家公司没有之一,招了一大堆人去面试,我等了一个多小时终于轮到我,面试官几句话打发我走了,不问任何跟工作有关的。
总结,这家公司发展不好,公司管理不规范,业务老旧。

4,广发证券
sql:开窗函数
java:并发,hashmap底层
hql,spark
sql调优,hive调优
表的设计
用oozie做大数据任务的调度

面试的时候被某家公司闻到:

懂不懂得做降维:实际就是特征抽取
特征抽取,是数据挖掘技术中的一个常用方法,它是一个属性降维的过程,特征抽取实际上是变换属性。经变换了的属性,或者特性,是原来属性集的线性合并。特征抽取会导致更小、更精的一组属性。用特征抽取建立的模型可能是质量更好的,因为数据被更少的、和更有意义的属性所描述。特征抽取将高维数据集映射到一个低维的数据集中。特征抽取对数据可视化是很有用的,当一个复杂的数据集被降维到两维或三维空间时,数据可有效地被观测。

特征抽取的算法有很多,这里重点介绍主成分分析法、因子分析法、非负矩阵因子分解NMF法等算法。

一、主成分分析算法
假设待分析数据为N个K维数据,主要成分分析(PCA,又称Karhunen-Loeve 或K-L 方法)即是搜索q 个最能代表数据的k-维正交向量,这里q ≤ k。这样将K维数据空间压缩为q维数据空间。PCA不同于前面讲到的相关因子计算法(选择一个较小的属性子集),PCA创建新的、数量较小的属性集合,这些新的属性是原有属性的线性组合。

1、主成分分析算法思想
为了客观、全面的研究问题,需要记录多个观察指标X1、X2、X3、…、Xn。虽然这些观察指标可以提供丰富的信息,但同时也使得数据的分析工作更趋复杂化。例如,在儿童生长发育的评价中,收集到的数据包括每一儿童的身高、体重、胸围、头围、坐高、肺活量等十多个指标。事实上,在实际工作中,所涉及的众多指标之间经常是有相互联系和影响的。通过对原始指标相互关系的研究,找出少数几个综合指标,这些综合指标是原始指标的线性组合,它既保留了原始指标的主要信息,且又互不相关,从而达到寻找少数综合指标以概括原始指标的目的。

2、 主成分分析算法实现
这里写图片描述

主成分分析算法的基本过程如下:
(1) 对数据进行标准化。
(2) PCA 计算q个标准正交基。这q个标准正交基被称为主要成分,所有数据是主要成分的线性组合。
(3) 根据主要成分对于变异的贡献量,即变异百分比,从大到小排序。
(4) 当排序在前的几个因子的累积变异百分比达到一定值(比如75%)后,就可以将后面的因子去掉,达到压缩数据的目的。

PCA 计算花费低,可以用于有序和无序的属性,并且可以处理稀疏和倾斜数据。例如,表1 是一个应用PCA算法得到的因子分析表。表中列出了共12个因子特征根、变异百分比和累积变异百分比。

这里写图片描述

通过上面的表3-3我们可以观察到,前四个因子累积贡献率已经超过75%,可以将12个因子压缩为前四个因子。PCA算法的核心,实际上是维度旋转。通过维度旋转来重新定义维度(变量),维度旋转的原则是尽可能与主要数据的特征保持同向,以达到减少维度(变量)的目的。

二、因子分析算法
因子分析是一种变量简化技术,从分析多个原始变量的相关关系入手,主要是研究多个变量的相关矩阵,找出支配相关关系的有限个潜在变量,达到用少数变量来解释复杂问题的目的。因子分析跟主成分分析有联系也有区别,从方法学原理上看,因子分析可以看成是主成分分析的推广,因子分析主要是研究解释原始变量之间的关系,而主成分分析重点在综合原始变量的信息。

1、因子分析算法思想
因子分析算法是,目标变量为Y,预测变量为X1、X2、X3、…Xn,对X1到Xn这n个特性进行重新整合,找出控制所有特性的少数公共特性Z1、Z2、…Zm,用少数特性来解释复杂问题的一种方法。

例如公司老板对应聘者进行面试,在15个方面打分,分别为申请书的形式、外貌、专业能力、讨人喜欢、自信心、精明、诚实、推销能力、经验、积极性、抱负、理解能力、潜力、交际能力和适应性。我们可以对这15个方面进行重新整合,归结为应聘者的外露能力、讨人喜欢的程度、经验、专业能力和外貌5个方面。
2、因子分析算法实现
因子分析算法的基本步骤如下:
这里写图片描述

因子分析算法的实质是寻找数据中的潜在因子,并应用潜在因子来解释由原变量显示的现象。

三、非负矩阵因子分解NMF算法
非负矩阵因子分解NMF算法,Non-negative Matrix Factorization (NMF),是一种特征抽取算法,它常常用于属性很多、而且属性模糊或者有很弱的可预测性的数据集。通过合并属性,NMF算法可以产生有意义的模式或主题。NMF算法通过创建用户定义的特征数来压缩多元变量数据,每一个特征是原来属性集的一个线性合并,这些线性合并的系数是非负的。NMF算法可以简单描述为,对于任意给定的一个非负矩阵V,NMF算法能够寻找到一个非负矩阵W和一个非负矩阵H,使得满足V=W*H,从而将一个非负的矩阵分解为两个非负矩阵的乘积。

NMF算法压缩一个数据矩阵V为两个低阶矩阵W和H的乘积,以近似地等于W*H。NMF算法使用交互式过程来修改矩阵W和H的初始值,以便这个乘积接近矩阵V。这个交互式过程当近似值差聚集或者达到一个给定的迭代次数时终止。NMF算法提供了基于简单迭代的求解W、H的方法,求解方法具有收敛速度快、左右非负矩阵存储空间小的特点,它能将高维的数据矩阵降维处理,适合处理大规模数据。利用NMF进行文本、图像大规模数据的分析方法,较传统的处理算法速度更快、更便捷。

特征抽取的本质,是对反映实际问题的复杂矩阵进行分解,即将复杂矩阵V近似分解成两个具有较低秩的W和H的乘积:V=W*H,前面讲过的主成分分析和因子分析也是这个思路。数学意义上的矩阵分解,因子W和H中的元素可为正或负,但是在解决文字聚类、人脸识别、计算机图像工程、基因及细胞分析等方面,负值便没有实际意义,非负矩阵因子分解NMF算法很好的解决了这些问题。

四、特征抽取的应用举例

我们采用医学体检中心的体检数据。选取男性,且终检结果包含“癌胚抗原(CEA)增高”,同时做了血脂、肌酐和尿酸化验的体检者数据为观察组(记为G1),约共1500例。数据集采集项目包括所有体检的生化指标数据以及终检结果的文本描述数据。原始终检结果的文本描述数据如下例:
“高血压病 球蛋白增高 右侧卵巢囊肿 血流变异常 子宫肌瘤 骨质疏松 腰臀比值异常 超重丙氨酸氨基转移酶ALT增高血脂异常”。

我们将大量的如上文本数据应用特征抽取技术进行体检结果特征分析。例如,用特征抽取方法对观察组G1-癌胚抗原增高组进行分析,得到排序在前7位的特征,其特性总参数和特性序号如表2所示。

这里写图片描述
特征7中包括8个并发症:白细胞分类异常,血脂异常,腰臀比值异常,冠心病,空腹血糖高,高血压病,体重指数偏低和双眼视网膜动脉硬化Ⅱ。其中白细胞分类(免疫系统指标)异常占主要因素,说明癌胚抗原增高与免疫系统出现异常同时出现的概率很高。如图2 所示。
这里写图片描述

这里写图片描述

表3 中,该特征提示非常强的主题,即 CEA 增高组有明显的免疫方面的反应。经对CEA 增高组的生化指标进行全面分析,发现淋巴细胞分布异常,95%的案例都有淋巴细胞增高现象,说明CEA与免疫系统因子有较密切联系。

其实,特征抽取技术在医学大数据中的应用是挺广泛的,它不仅可以对结构化的数据进行分析,而且还可以对非结构化的文本数据进行分析,甚至非结构化的医学影像数据挖掘中大显身手,我们有机会在后面的博客中再讨论。本文主要内容摘自本人的《数据挖掘技术与工程实践》一书,更多内容,请参考原著。

本文转载http://blog.sina.com.cn/s/blog_1361bcf9d0102w6n8.html

—————————————————–关于sql的
1,窗口函数
举例:
create table company
(dep string, –部门
employ_id string, –员工id
salary double)–员工薪水
找出每个部门,薪水排名前三的员工id
hive,sql,mysql 。。。都适合用

select * from
(select dep ,employ_id , rank() over(partition by dep, order by salar desc) 排名 from company) temp
where 排名 in (1,2,3)

dep name    salary  rank
aa          lyi         1000    1
aa          lui         1040    2
aa          ljfi        1040    2
abba        lmnni       10120   1
abba        lpl;i       10660   2
abba        lbbdi       10760   3
ahha        lbbi        1020    1
ahha        lbi         10022   2
ahha        lddi        10090   3
bb          lwi         10560   1
bb          lqqi        10560   1
bb          lwsi        100900  3

rank() over(partition by dep, order by salar desc
窗口函数,在一般的函数后面加上over() ,这样这个函数的作用域就是在返回的结果集里面
over 里面一般搭配 partition by xxx, order by xxxx

如果是dense_rank() 的话就不会产生重复跳跃

2,维度表和事实表

3,表的设计

4,sql语句的优化,hive的优化

5,hive任务的调度

—————————————–关于java的———————————–
1,线程的wait(), notify(),notifyall()
1、通过共享对象通信
线程间发送信号的一个简单方式是在共享对象的变量里设置信号值。线程A在一个同步块里设置boolean型成员变量hasDataToProcess为true,线程B也在同步块里读取hasDataToProcess这个成员变量。这个简单的例子使用了一个持有信号的对象,并提供了set和check方法:

01
public class MySignal{
02

03
protected boolean hasDataToProcess = false;
04

05
public synchronized boolean hasDataToProcess(){
06
return this.hasDataToProcess;
07
}
08

09
public synchronized void setHasDataToProcess(boolean hasData){
10
this.hasDataToProcess = hasData;
11
}
12

13
}
线程A和B必须获得指向一个MySignal共享实例的引用,以便进行通信。如果它们持有的引用指向不同的MySingal实例,那么彼此将不能检测到对方的信号。需要处理的数据可以存放在一个共享缓存区里,它和MySignal实例是分开存放的。

2、忙等待(Busy Wait)
准备处理数据的线程B正在等待数据变为可用。换句话说,它在等待线程A的一个信号,这个信号使hasDataToProcess()返回true。线程B运行在一个循环里,以等待这个信号:

1
protected MySignal sharedSignal = …
2

3

4

5
while(!sharedSignal.hasDataToProcess()){
6
//do nothing… busy waiting
7
}
3、wait(),notify()和notifyAll()
忙等待没有对运行等待线程的CPU进行有效的利用,除非平均等待时间非常短。否则,让等待线程进入睡眠或者非运行状态更为明智,直到它接收到它等待的信号。

Java有一个内建的等待机制来允许线程在等待信号的时候变为非运行状态。java.lang.Object 类定义了三个方法,wait()、notify()和notifyAll()来实现这个等待机制。

一个线程一旦调用了任意对象的wait()方法,就会变为非运行状态,直到另一个线程调用了同一个对象的notify()方法。为了调用wait()或者notify(),线程必须先获得那个对象的锁。也就是说,线程必须在同步块里调用wait()或者notify()。以下是MySingal的修改版本——使用了wait()和notify()的MyWaitNotify:

01
public class MonitorObject{
02
}
03

04
public class MyWaitNotify{
05

06
MonitorObject myMonitorObject = new MonitorObject();
07

08
public void doWait(){
09
synchronized(myMonitorObject){
10
try{
11
myMonitorObject.wait();
12
} catch(InterruptedException e){…}
13
}
14
}
15

16
public void doNotify(){
17
synchronized(myMonitorObject){
18
myMonitorObject.notify();
19
}
20
}
21
}
等待线程将调用doWait(),而唤醒线程将调用doNotify()。当一个线程调用一个对象的notify()方法,正在等待该对象的所有线程中将有一个线程被唤醒并允许执行(校注:这个将被唤醒的线程是随机的,不可以指定唤醒哪个线程)。同时也提供了一个notifyAll()方法来唤醒正在等待一个给定对象的所有线程。

如你所见,不管是等待线程还是唤醒线程都在同步块里调用wait()和notify()。这是强制性的!一个线程如果没有持有对象锁,将不能调用wait(),notify()或者notifyAll()。否则,会抛出IllegalMonitorStateException异常。

(校注:JVM是这么实现的,当你调用wait时候它首先要检查下当前线程是否是锁的拥有者,不是则抛出IllegalMonitorStateExcept,参考JVM源码的 1422行。)

但是,这怎么可能?等待线程在同步块里面执行的时候,不是一直持有监视器对象(myMonitor对象)的锁吗?等待线程不能阻塞唤醒线程进入doNotify()的同步块吗?答案是:的确不能。一旦线程调用了wait()方法,它就释放了所持有的监视器对象上的锁。这将允许其他线程也可以调用wait()或者notify()。

一旦一个线程被唤醒,不能立刻就退出wait()的方法调用,直到调用notify()的线程退出了它自己的同步块。换句话说:被唤醒的线程必须重新获得监视器对象的锁,才可以退出wait()的方法调用,因为wait方法调用运行在同步块里面。如果多个线程被notifyAll()唤醒,那么在同一时刻将只有一个线程可以退出wait()方法,因为每个线程在退出wait()前必须获得监视器对象的锁。

2,线程的关键字
volatile 与 synchronized 的比较:

①volatile轻量级,只能修饰变量。synchronized重量级,还可修饰方法

②volatile只能保证数据的可见性,不能用来同步,因为多个线程并发访问volatile修饰的变量不会阻塞。

synchronized不仅保证可见性,而且还保证原子性,因为,只有获得了锁的线程才能进入临界区,从而保证临界区中的所有语句都全部执行。多个线程争抢synchronized锁对象时,会出现阻塞。

线程安全性包括两个方面,①可见性。②原子性。

3,.sleep()方法

在指定时间内让当前正在执行的线程暂停执行,但不会释放“锁标志”。不推荐使用。

sleep()使当前线程进入阻塞状态,在指定时间内不会执行。

4,wait()方法

在其他线程调用对象的notify或notifyAll方法前,导致当前线程等待。线程会释放掉它所占有的“锁标志”,从而使别的线程有机会抢占该锁。

当前线程必须拥有当前对象锁。如果当前线程不是此锁的拥有者,会抛出IllegalMonitorStateException异常。

唤醒当前对象锁的等待线程使用notify或notifyAll方法,也必须拥有相同的对象锁,否则也会抛出IllegalMonitorStateException异常。

waite()和notify()必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized函数或non-synchronized block中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常。

5,yield方法

暂停当前正在执行的线程对象。

yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。

yield()只能使同优先级或更高优先级的线程有执行的机会。

6.join方法

等待该线程终止。

等待调用join方法的线程结束,再继续执行。如:t.join();//主要用于等待t线程运行结束,若无此句,main则会执行完毕,导致结果不可预测。

publicclass Test {
publicstaticvoid main(String[] args) {
Thread t1 = new MyThread1();
t1.start();

            for (int i = 0; i < 20; i++) {
                    System.out.println("主线程第" + i +"次执行!");
                    if (i > 2)try { 
                            //t1线程合并到主线程中,主线程停止执行过程,转而执行t1线程,直到t1执行完毕后继续。
                            t1.join(); 
                    } catch (InterruptedException e) {
                            e.printStackTrace(); 
                    } 
            } 
    } 

}

class MyThread1 extends Thread {
publicvoid run() {
for (int i = 0; i < 10; i++) {
System.out.println(“线程1第” + i + “次执行!”);
}
}
}

猜你喜欢

转载自blog.csdn.net/Tardis1/article/details/79982237