精华内容
参与话题
问答
  • 用通俗易懂的大白话讲解Map/Reduce原理

    万次阅读 多人点赞 2014-03-31 16:20:44
    下面是我自己的微信公众号(不定期更新 JAVA 、大数据、个人成长等干货) 1、公众号上有经典的技术电子书可以免费领 2、大家有问题可以在公众号问我,只要你问了我就会回复(相互交流) 也可以扫描下面二维码...

    下面是我自己的微信公众号(不定期更新 JAVA 、大数据、个人成长等干货)

    1、公众号上有经典的技术电子书可以免费领

    2、大家有问题可以在公众号问我,只要你问了我就会回复(相互交流)

     

    也可以扫描下面二维码, 加我个人微信,和我直接沟通

    Hadoop简介

    Hadoop就是一个实现了Google云计算系统的开源系统,包括并行计算模型Map/Reduce,分布式文件系统HDFS,以及分布式数据库Hbase,同时Hadoop的相关项目也很丰富,包括ZooKeeper,Pig,Chukwa,Hive,Hbase,Mahout,flume等.

    这里详细分解这里面的概念让大家通过这篇文章了解到底是什么hadoop:




    1.什么是Map/Reduce,看下面的各种解释:

    (1)MapReduce是hadoop的核心组件之一,hadoop要分布式包括两部分,一是分布式文件系统hdfs,一部是分布式计算框,就是mapreduce,缺一不可,也就是说,可以通过mapreduce很容易在hadoop平台上进行分布式的计算编程。

    (2)Mapreduce是一种编程模型,是一种编程方法,抽象理论。

    (3)下面是一个关于一个程序员是如何个妻子讲解什么是MapReduce?文章很长请耐心的看。

    我问妻子:“你真的想要弄懂什么是MapReduce?” 她很坚定的回答说“是的”。 因此我问道:

    我: 你是如何准备洋葱辣椒酱的?(以下并非准确食谱,请勿在家尝试)

    妻子: 我会取一个洋葱,把它切碎,然后拌入盐和水,最后放进混合研磨机里研磨。这样就能得到洋葱辣椒酱了。


    妻子: 但这和MapReduce有什么关系?

    我: 你等一下。让我来编一个完整的情节,这样你肯定可以在15分钟内弄懂MapReduce.

    妻子: 好吧。

    我:现在,假设你想用薄荷、洋葱、番茄、辣椒、大蒜弄一瓶混合辣椒酱。你会怎么做呢?

    妻子: 我会取薄荷叶一撮,洋葱一个,番茄一个,辣椒一根,大蒜一根,切碎后加入适量的盐和水,再放入混合研磨机里研磨,这样你就可以得到一瓶混合辣椒酱了。

    我: 没错,让我们把MapReduce的概念应用到食谱上。Map和Reduce其实是两种操作,我来给你详细讲解下。
    Map(映射): 把洋葱、番茄、辣椒和大蒜切碎,是各自作用在这些物体上的一个Map操作。所以你给Map一个洋葱,Map就会把洋葱切碎。 同样的,你把辣椒,大蒜和番茄一一地拿给Map,你也会得到各种碎块。 所以,当你在切像洋葱这样的蔬菜时,你执行就是一个Map操作。 Map操作适用于每一种蔬菜,它会相应地生产出一种或多种碎块,在我们的例子中生产的是蔬菜块。在Map操作中可能会出现有个洋葱坏掉了的情况,你只要把坏洋葱丢了就行了。所以,如果出现坏洋葱了,Map操作就会过滤掉坏洋葱而不会生产出任何的坏洋葱块。


    Reduce(化简):在这一阶段,你将各种蔬菜碎都放入研磨机里进行研磨,你就可以得到一瓶辣椒酱了。这意味要制成一瓶辣椒酱,你得研磨所有的原料。因此,研磨机通常将map操作的蔬菜碎聚集在了一起。

    妻子: 所以,这就是MapReduce?

    我: 你可以说是,也可以说不是。 其实这只是MapReduce的一部分,MapReduce的强大在于分布式计算。

    妻子: 分布式计算? 那是什么?请给我解释下吧。

    我: 没问题。

    我: 假设你参加了一个辣椒酱比赛并且你的食谱赢得了最佳辣椒酱奖。得奖之后,辣椒酱食谱大受欢迎,于是你想要开始出售自制品牌的辣椒酱。假设你每天需要生产10000瓶辣椒酱,你会怎么办呢?

    妻子: 我会找一个能为我大量提供原料的供应商。

    我:是的..就是那样的。那你能否独自完成制作呢?也就是说,独自将原料都切碎? 仅仅一部研磨机又是否能满足需要?而且现在,我们还需要供应不同种类的辣椒酱,像洋葱辣椒酱、青椒辣椒酱、番茄辣椒酱等等。

    妻子: 当然不能了,我会雇佣更多的工人来切蔬菜。我还需要更多的研磨机,这样我就可以更快地生产辣椒酱了。
    我:没错,所以现在你就不得不分配工作了,你将需要几个人一起切蔬菜。每个人都要处理满满一袋的蔬菜,而每一个人都相当于在执行一个简单的Map操作。每一个人都将不断的从袋子里拿出蔬菜来,并且每次只对一种蔬菜进行处理,也就是将它们切碎,直到袋子空了为止。
    这样,当所有的工人都切完以后,工作台(每个人工作的地方)上就有了洋葱块、番茄块、和蒜蓉等等。


    妻子:但是我怎么会制造出不同种类的番茄酱呢?

    我:现在你会看到MapReduce遗漏的阶段—搅拌阶段。MapReduce将所有输出的蔬菜碎都搅拌在了一起,这些蔬菜碎都是在以key为基础的 map操作下产生的。搅拌将自动完成,你可以假设key是一种原料的名字,就像洋葱一样。 所以全部的洋葱keys都会搅拌在一起,并转移到研磨洋葱的研磨器里。这样,你就能得到洋葱辣椒酱了。同样地,所有的番茄也会被转移到标记着番茄的研磨器里,并制造出番茄辣椒酱。

    (4)上面都是从理论上来说明什么是MapReduce,那么咱们在MapReduce产生的过程和代码的角度来理解这个问题。
    如果想统计下过去10年计算机论文出现最多的几个单词,看看大家都在研究些什么,那收集好论文后,该怎么办呢? 

      方法一:

          我可以写一个小程序,把所有论文按顺序遍历一遍,统计每一个遇到的单词的出现次数,最后就可以知道哪几个单词最热门了。 这种方法在数据集比较小时,是非常有效的,而且实现最简单,用来解决这个问题很合适。 

     方法二:

           写一个多线程程序,并发遍历论文。 
      这个问题理论上是可以高度并发的,因为统计一个文件时不会影响统计另一个文件。当我们的机器是多核或者多处理器,方法二肯定比方法一高效。但是写一个多线程程序要比方法一困难多了,我们必须自己同步共享数据,比如要防止两个线程重复统计文件。 

    方法三:

          把作业交给多个计算机去完成。 
      我们可以使用方法一的程序,部署到N台机器上去,然后把论文集分成N份,一台机器跑一个作业。这个方法跑得足够快,但是部署起来很麻烦,我们要人工把程序copy到别的机器,要人工把论文集分开,最痛苦的是还要把N个运行结果进行整合(当然我们也可以再写一个程序)。 

      方法四:

          让MapReduce来帮帮我们吧! 

      MapReduce本质上就是方法三,但是如何拆分文件集,如何copy程序,如何整合结果这些都是框架定义好的。我们只要定义好这个任务(用户程序),其它都交给MapReduce。



    map函数和reduce函数  


    map函数和reduce函数是交给用户实现的,这两个函数定义了任务本身。 

      map函数:接受一个键值对(key-value pair),产生一组中间键值对。MapReduce框架会将map函数产生的中间键值对里键相同的值传递给一个reduce函数。 

      reduce函数:接受一个键,以及相关的一组值,将这组值进行合并产生一组规模更小的值(通常只有一个或零个值)。 

      统计词频的MapReduce函数的核心代码非常简短,主要就是实现这两个函数。 

      map(String key, String value): 

      // key: document name 

      // value: document contents 

      for each word w in value: 

      EmitIntermediate(w, "1"); 

      reduce(String key, Iterator values): 

      // key: a word 

      // values: a list of counts 

      int result = 0; 

      for each v in values: 

      result += ParseInt(v); 

      Emit(AsString(result)); 

      在统计词频的例子里,map函数接受的键是文件名,值是文件的内容,map逐个遍历单词,每遇到一个单词w,就产生一个中间键值对<w, "1">,这表示单词w咱又找到了一个;MapReduce将键相同(都是单词w)的键值对传给reduce函数,这样reduce函数接受的键就是单词w,值是一串"1"(最基本的实现是这样,但可以优化),个数等于键为w的键值对的个数,然后将这些“1”累加就得到单词w的出现次数。最后这些单词的出现次数会被写到用户定义的位置,存储在底层的分布式存储系统(GFS或HDFS)。 




    工作原理

     

      
    上图是论文里给出的流程图。一切都是从最上方的user program开始的,user program链接了MapReduce库,实现了最基本的Map函数和Reduce函数。图中执行的顺序都用数字标记了。

      1.MapReduce库先把user program的输入文件划分为M份(M为用户定义),每一份通常有16MB到64MB,如图左方所示分成了split0~4;然后使用fork将用户进程拷贝到集群内其它机器上。 

      2.user program的副本中有一个称为master,其余称为worker,master是负责调度的,为空闲worker分配作业(Map作业或者Reduce作业),worker的数量也是可以由用户指定的。 

      3.被分配了Map作业的worker,开始读取对应分片的输入数据,Map作业数量是由M决定的,和split一一对应;Map作业从输入数据中抽取出键值对,每一个键值对都作为参数传递给map函数,map函数产生的中间键值对被缓存在内存中。 

      4.缓存的中间键值对会被定期写入本地磁盘,而且被分为R个区,R的大小是由用户定义的,将来每个区会对应一个Reduce作业;这些中间键值对的位置会被通报给master,master负责将信息转发给Reduce worker。 

      5.master通知分配了Reduce作业的worker它负责的分区在什么位置(肯定不止一个地方,每个Map作业产生的中间键值对都可能映射到所有R个不同分区),当Reduce worker把所有它负责的中间键值对都读过来后,先对它们进行排序,使得相同键的键值对聚集在一起。因为不同的键可能会映射到同一个分区也就是同一个Reduce作业(谁让分区少呢),所以排序是必须的。 

      6.reduce worker遍历排序后的中间键值对,对于每个唯一的键,都将键与关联的值传递给reduce函数,reduce函数产生的输出会添加到这个分区的输出文件中。 

      6.当所有的Map和Reduce作业都完成了,master唤醒正版的user program,MapReduce函数调用返回user program的代码。 

      所有执行完毕后,MapReduce输出放在了R个分区的输出文件中(分别对应一个Reduce作业)。用户通常并不需要合并这R个文件,而是将其作为输入交给另一个MapReduce程序处理。整个过程中,输入数据是来自底层分布式文件系统(GFS)的,中间数据是放在本地文件系统的,最终输出数据是写入底层分布式文件系统(GFS)的。而且我们要注意Map/Reduce作业和map/reduce函数的区别:Map作业处理一个输入数据的分片,可能需要调用多次map函数来处理每个输入键值对;Reduce作业处理一个分区的中间键值对,期间要对每个不同的键调用一次reduce函数,Reduce作业最终也对应一个输出文件。

    总结:

    通过以上你是否了解什么是MapReduce了那,什么是key,怎么过滤有效数据,怎么得到自己想要的数据。
    MapReduce是一种编程思想,可以使用java来实现,C++来实现。Map的作用是过滤一些原始数据,Reduce则是处理这些数据,得到我们想要的结果,比如你想造出番茄辣椒酱。也就是我们使用hadoop,比方来进行日志处理之后,得到我们想要的关心的数据

                                                    
     

    展开全文
  • 希尔排序--简单易懂图解

    万次阅读 多人点赞 2018-04-19 15:56:22
    图解算法---希尔排序前情回顾:直接插入排序(对插入排序不熟悉的建议先阅读此文)一天,一尘拿着扑克自己在那玩,刚被师傅看见了首先它把较大的数据集合分割成若干个小组(逻辑上分组),然后对每一个小组分别进行...

    强烈推荐30个原生JavaScript的demo,包括canvas时钟特效、自定义视频播放器、搜索栏快速匹配、fetch访问资源、console调试技巧等,先fork后学习,详见点击打开链接,欢迎点赞~~~谢谢,共同进步学习!

    图解算法---希尔排序

    图解算法---希尔排序

    图解算法---希尔排序

    前情回顾:直接插入排序(对插入排序不熟悉的建议先阅读此文)

    一天,一尘拿着扑克自己在那玩,刚被师傅看见了

    图解算法---希尔排序

    图解算法---希尔排序

    图解算法---希尔排序

    首先它把较大的数据集合分割成若干个小组(逻辑上分组),然后对每一个小组分别进行插入排序,此时,插入排序所作用的数据量比较小(每一个小组),插入的效率比较高

    图解算法---希尔排序

    图解算法---希尔排序

    可以看出,他是按下标相隔距离为4分的组,也就是说把下标相差4的分到一组,比如这个例子中a[0]与a[4]是一组、a[1]与a[5]是一组...,这里的差值(距离)被称为增量

    图解算法---希尔排序

    每个分组进行插入排序后,各个分组就变成了有序的了(整体不一定有序)

    图解算法---希尔排序

    此时,整个数组变的部分有序了(有序程度可能不是很高)

    图解算法---希尔排序

    然后缩小增量为上个增量的一半:2,继续划分分组,此时,每个分组元素个数多了,但是,数组变的部分有序了,插入排序效率同样比高

    图解算法---希尔排序

    同理对每个分组进行排序(插入排序),使其每个分组各自有序

    图解算法---希尔排序

    最后设置增量为上一个增量的一半:1,则整个数组被分为一组,此时,整个数组已经接近有序了,插入排序效率高

    图解算法---希尔排序

    同理,对这仅有的一组数据进行排序,排序完成

    图解算法---希尔排序

    图解算法---希尔排序

    图解算法---希尔排序

    图解算法---希尔排序

    图解算法---希尔排序

    随后一尘写出了插入arr[i]到所在组正确位置的代码(insertI)

    图解算法---希尔排序

    图解算法---希尔排序

    图解算法---希尔排序

    图解算法---希尔排序

    图解算法---希尔排序

    希尔排序的复杂度和增量序列是相关的

    {1,2,4,8,...}这种序列并不是很好的增量序列,使用这个增量序列的时间复杂度(最坏情形)是O(n^2)

    Hibbard提出了另一个增量序列{1,3,7,...,2^k-1},这种序列的时间复杂度(最坏情形)为O(n^1.5)

    Sedgewick提出了几种增量序列,其最坏情形运行时间为O(n^1.3),其中最好的一个序列是{1,5,19,41,109,...}

    图解算法---希尔排序

    图解算法---希尔排序

    图解算法---希尔排序

    图解算法---希尔排序

    图解算法---希尔排序

    图解算法---希尔排序

    说完,一尘继续玩起了扑克。

    公众号:一线开发,内有交流群,佛系关注入群

    展开全文
  • 快速排序基本思路(通俗易懂+例子)

    万次阅读 多人点赞 2017-07-02 22:06:32
    快速排序今天看到大神写的一篇快速排序的博客,肃然起敬,觉得原来快速排序这么简单 下面进行简单的试试快速排序的基本思想是 1、先从数列中取出一个数作为基准数 2、分区过程,将比这个数大的数全放到它的...

    快速排序

    今天看到大神写的一篇快速排序的博客,肃然起敬,觉得原来快速排序这么简单
    下面进行简单的试试

    快速排序的基本思想是

    1、先从数列中取出一个数作为基准数

    2、分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边

    3、再对左右区间重复第二步,直到各区间只有一个数

    概括来说为 挖坑填数+分治法

    下面举例来进行说明,主要有三个参数,i为区间的开始地址,j为区间的结束地址,X为当前的开始的值

    第一步,i=0,j=9,X=21

    0 1 2 3 4 5 6 7 8 9
    21 32 43 98 54 45 23 4 66 86

    第二步,从j开始由,后向前找,找到比X小的第一个数a[7]=4,此时i=0,j=6,X=21
    进行替换

    0 1 2 3 4 5 6 7 8 9
    4 32 43 98 54 45 23 21 66 86

    第三步,由前往后找,找到比X大的第一个数a[1]=32,此时i=2,j=6,X=21

    0 1 2 3 4 5 6 7 8 9
    4 21 43 98 54 45 23 32 66 86

    第四步,从j=6开始由,由后向前找,找到比X小的第一个数a[0]=4,此时i=2,j=0,X=21,发现j<=i,所以第一回结束

    可以发现21前面的数字都比21小,后面的数字都比21大
    接下来对两个子区间[0,0]和[2,9]重复上面的操作即可

    下面直接给出过程,就步详细解说了

    i=2,j=6,X=43

    0 1 2 3 4 5 6 7 8 9
    4 21 43 98 54 45 23 32 66 86

    i=4,j=6,X=43

    0 1 2 3 4 5 6 7 8 9
    4 21 32 98 54 45 23 43 66 86

    i=4,j=5,x=43

    0 1 2 3 4 5 6 7 8 9
    4 21 32 43 54 45 23 98 66 86

    i=5,j=5,x=43

    0 1 2 3 4 5 6 7 8 9
    4 21 32 23 43 45 54 98 66 86

    然后被分为了两个子区间[2,3]和[5,9]

    …最后排序下去就是最终的答案

    0 1 2 3 4 5 6 7 8 9
    4 21 23 32 43 45 54 66 86 98

    总结:

    1.i =L; j = R; 将基准数挖出形成第一个坑a[i]。

    2.j–由后向前找比它小的数,找到后挖出此数填前一个坑a[i]中。

    3.i++由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]中。

    4.再重复执行2,3二步,直到i==j,将基准数填入a[i]中。


    代码

    class Solution {
    	public void sort(int left,int right,int[] array) {
    		if (left>=right) return ;
    		int start=left;
    		int end=right;
    		int flag=left;
    		while(left<right) {
    			while ((left<right)&&(array[right]>=array[flag])) {
    				right--;
    			}
    			if (array[right]<array[flag]) {
    				int tmp=array[right];
    				array[right]=array[flag];
    				array[flag]=tmp;
    				flag=right;
    			}
    			while ((left<right)&&(array[left]<=array[flag])) {
    				left++;
    				}
    			if (array[left]>array[flag]) {
    				int tmp=array[left];
    				array[left]=array[flag];
    				array[flag]=tmp;
    				flag=left;
    			}
    		}
    		sort(start, left-1, array);
    		sort(left+1, end, array);
    	}
    }
    

    分享一个比较牛逼的学习java的网站,基础知识和架构等都有,连接如下:
    http://how2j.cn?p=54321
    在这里插入图片描述

    展开全文
  • 深入浅出的讲解傅里叶变换(真正的通俗易懂

    万次阅读 多人点赞 2016-07-04 00:40:51
    我保证这篇文章和你以前看过的所有文章都不同,这是12年还在果壳的时候写的,但是当时没有来得及写完就出国了……于是拖了两年,嗯,我是拖延症患者……  这篇文章的核心思想就是:  要让读者在不看任何数学公式的...
     
     
    原文出处: 韩昊   
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    作 者:韩 昊
    知 乎:Heinrich
    微 博:@花生油工人
    知乎专栏:与时间无关的故事
     
    谨以此文献给大连海事大学的吴楠老师,柳晓鸣老师,王新年老师以及张晶泊老师。
     
    转载的同学请保留上面这句话,谢谢。如果还能保留文章来源就更感激不尽了。

    我保证这篇文章和你以前看过的所有文章都不同,这是 2012 年还在果壳的时候写的,但是当时没有来得及写完就出国了……于是拖了两年,嗯,我是拖延症患者……

    这篇文章的核心思想就是:

    要让读者在不看任何数学公式的情况下理解傅里叶分析。

    傅里叶分析不仅仅是一个数学工具,更是一种可以彻底颠覆一个人以前世界观的思维模式。但不幸的是,傅里叶分析的公式看起来太复杂了,所以很多大一新生上来就懵圈并从此对它深恶痛绝。老实说,这么有意思的东西居然成了大学里的杀手课程,不得不归咎于编教材的人实在是太严肃了。(您把教材写得好玩一点会死吗?会死吗?)所以我一直想写一个有意思的文章来解释傅里叶分析,有可能的话高中生都能看懂的那种。所以,不管读到这里的您从事何种工作,我保证您都能看懂,并且一定将体会到通过傅里叶分析看到世界另一个样子时的快感。至于对于已经有一定基础的朋友,也希望不要看到会的地方就急忙往后翻,仔细读一定会有新的发现。

    ————以上是定场诗————

    下面进入正题:

    抱歉,还是要啰嗦一句:其实学习本来就不是易事,我写这篇文章的初衷也是希望大家学习起来更加轻松,充满乐趣。但是千万!千万不要把这篇文章收藏起来,或是存下地址,心里想着:以后有时间再看。这样的例子太多了,也许几年后你都没有再打开这个页面。无论如何,耐下心,读下去。这篇文章要比读课本要轻松、开心得多……

    一、什么是频域

    从我们出生,我们看到的世界都以时间贯穿,股票的走势、人的身高、汽车的轨迹都会随着时间发生改变。这种以时间作为参照来观察动态世界的方法我们称其为时域分析。而我们也想当然的认为,世间万物都在随着时间不停的改变,并且永远不会静止下来。但如果我告诉你,用另一种方法来观察世界的话,你会发现世界是永恒不变的,你会不会觉得我疯了?我没有疯,这个静止的世界就叫做频域。

    先举一个公式上并非很恰当,但意义上再贴切不过的例子:

    在你的理解中,一段音乐是什么呢?

    这是我们对音乐最普遍的理解,一个随着时间变化的震动。但我相信对于乐器小能手们来说,音乐更直观的理解是这样的:


    好的!下课,同学们再见。

    是的,其实这一段写到这里已经可以结束了。上图是音乐在时域的样子,而下图则是音乐在频域的样子。所以频域这一概念对大家都从不陌生,只是从来没意识到而已。

    现在我们可以回过头来重新看看一开始那句痴人说梦般的话:世界是永恒的。

    将以上两图简化:

    时域:


    频域:

    在时域,我们观察到钢琴的琴弦一会上一会下的摆动,就如同一支股票的走势;而在频域,只有那一个永恒的音符。

    所以

    你眼中看似落叶纷飞变化无常的世界,实际只是躺在上帝怀中一份早已谱好的乐章。

    抱歉,这不是一句鸡汤文,而是黑板上确凿的公式:傅里叶同学告诉我们,任何周期函数,都可以看作是不同振幅,不同相位正弦波的叠加。在第一个例子里我们可以理解为,利用对不同琴键不同力度,不同时间点的敲击,可以组合出任何一首乐曲。

    而贯穿时域与频域的方法之一,就是传中说的傅里叶分析。傅里叶分析可分为傅里叶级数(Fourier Serie)和傅里叶变换(Fourier Transformation),我们从简单的开始谈起。

     

    二、傅里叶级数(Fourier Series)的频谱

    还是举个栗子并且有图有真相才好理解。

    如果我说我能用前面说的正弦曲线波叠加出一个带 90 度角的矩形波来,你会相信吗?你不会,就像当年的我一样。但是看看下图:

    第一幅图是一个郁闷的正弦波 cos(x)

    第二幅图是 2 个卖萌的正弦波的叠加 cos (x) +a.cos (3x)

    第三幅图是 4 个发春的正弦波的叠加

    第四幅图是 10 个便秘的正弦波的叠加

    随着正弦波数量逐渐的增长,他们最终会叠加成一个标准的矩形,大家从中体会到了什么道理?

    (只要努力,弯的都能掰直!)

    随着叠加的递增,所有正弦波中上升的部分逐渐让原本缓慢增加的曲线不断变陡,而所有正弦波中下降的部分又抵消了上升到最高处时继续上升的部分使其变为水平线。一个矩形就这么叠加而成了。但是要多少个正弦波叠加起来才能形成一个标准 90 度角的矩形波呢?不幸的告诉大家,答案是无穷多个。(上帝:我能让你们猜着我?)

    不仅仅是矩形,你能想到的任何波形都是可以如此方法用正弦波叠加起来的。这是没有接触过傅里叶分析的人在直觉上的第一个难点,但是一旦接受了这样的设定,游戏就开始有意思起来了。

    还是上图的正弦波累加成矩形波,我们换一个角度来看看:

    在这几幅图中,最前面黑色的线就是所有正弦波叠加而成的总和,也就是越来越接近矩形波的那个图形。而后面依不同颜色排列而成的正弦波就是组合为矩形波的各个分量。这些正弦波按照频率从低到高从前向后排列开来,而每一个波的振幅都是不同的。一定有细心的读者发现了,每两个正弦波之间都还有一条直线,那并不是分割线,而是振幅为 0 的正弦波!也就是说,为了组成特殊的曲线,有些正弦波成分是不需要的。

    这里,不同频率的正弦波我们成为频率分量。

    好了,关键的地方来了!!

    如果我们把第一个频率最低的频率分量看作“1”,我们就有了构建频域的最基本单元。

    对于我们最常见的有理数轴,数字“1”就是有理数轴的基本单元。

    (好吧,数学称法为——基。在那个年代,这个字还没有其他奇怪的解释,后面还有正交基这样的词汇我会说吗?)

    时域的基本单元就是“1 秒”,如果我们将一个角频率为\omega_{0}的正弦波 cos(\omega_{0}t)看作基础,那么频域的基本单元就是\omega_{0}

    有了“1”,还要有“0”才能构成世界,那么频域的“0”是什么呢?cos(0t)就是一个周期无限长的正弦波,也就是一条直线!所以在频域,0 频率也被称为直流分量,在傅里叶级数的叠加中,它仅仅影响全部波形相对于数轴整体向上或是向下而不改变波的形状。

    接下来,让我们回到初中,回忆一下已经死去的八戒,啊不,已经死去的老师是怎么定义正弦波的吧。

    正弦波就是一个圆周运动在一条直线上的投影。所以频域的基本单元也可以理解为一个始终在旋转的圆

    想看动图的同学请戳这里:

    File:Fourier series square wave circles animation.gif

    File:Fourier series sawtooth wave circles animation.gif

    以及这里:

    File:Fourier series sawtooth wave circles animation.gif

    点出去的朋友不要被 wiki 拐跑了,wiki 写的哪有这里的文章这么没节操是不是。

    介绍完了频域的基本组成单元,我们就可以看一看一个矩形波,在频域里的另一个模样了:


    这是什么奇怪的东西?

    这就是矩形波在频域的样子,是不是完全认不出来了?教科书一般就给到这里然后留给了读者无穷的遐想,以及无穷的吐槽,其实教科书只要补一张图就足够了:频域图像,也就是俗称的频谱,就是——

    再清楚一点:

    可以发现,在频谱中,偶数项的振幅都是0,也就对应了图中的彩色直线。振幅为 0 的正弦波。

    File:Fourier series and transform.gif

    动图请戳:

    File:Fourier series and transform.gif

    老实说,在我学傅里叶变换时,维基的这个图还没有出现,那时我就想到了这种表达方法,而且,后面还会加入维基没有表示出来的另一个谱——相位谱。

    但是在讲相位谱之前,我们先回顾一下刚刚的这个例子究竟意味着什么。记得前面说过的那句“世界是静止的”吗?估计好多人对这句话都已经吐槽半天了。想象一下,世界上每一个看似混乱的表象,实际都是一条时间轴上不规则的曲线,但实际这些曲线都是由这些无穷无尽的正弦波组成。我们看似不规律的事情反而是规律的正弦波在时域上的投影,而正弦波又是一个旋转的圆在直线上的投影。那么你的脑海中会产生一个什么画面呢?

    我们眼中的世界就像皮影戏的大幕布,幕布的后面有无数的齿轮,大齿轮带动小齿轮,小齿轮再带动更小的。在最外面的小齿轮上有一个小人——那就是我们自己。我们只看到这个小人毫无规律的在幕布前表演,却无法预测他下一步会去哪。而幕布后面的齿轮却永远一直那样不停的旋转,永不停歇。这样说来有些宿命论的感觉。说实话,这种对人生的描绘是我一个朋友在我们都是高中生的时候感叹的,当时想想似懂非懂,直到有一天我学到了傅里叶级数……

    三、傅里叶级数(Fourier Series)的相位谱

    上一章的关键词是:从侧面看。这一章的关键词是:从下面看。

    在这一章最开始,我想先回答很多人的一个问题:傅里叶分析究竟是干什么用的?这段相对比较枯燥,已经知道了的同学可以直接跳到下一个分割线。

    先说一个最直接的用途。无论听广播还是看电视,我们一定对一个词不陌生——频道。频道频道,就是频率的通道,不同的频道就是将不同的频率作为一个通道来进行信息传输。下面大家尝试一件事:

    先在纸上画一个sin(x),不一定标准,意思差不多就行。不是很难吧。

    好,接下去画一个sin(3x)+sin(5x)的图形。

    别说标准不标准了,曲线什么时候上升什么时候下降你都不一定画的对吧?

    好,画不出来不要紧,我把sin(3x)+sin(5x)的曲线给你,但是前提是你不知道这个曲线的方程式,现在需要你把sin(5x)给我从图里拿出去,看看剩下的是什么。这基本是不可能做到的。

    但是在频域呢?则简单的很,无非就是几条竖线而已。

    所以很多在时域看似不可能做到的数学操作,在频域相反很容易。这就是需要傅里叶变换的地方。尤其是从某条曲线中去除一些特定的频率成分,这在工程上称为滤波,是信号处理最重要的概念之一,只有在频域才能轻松的做到。

    再说一个更重要,但是稍微复杂一点的用途——求解微分方程。(这段有点难度,看不懂的可以直接跳过这段)微分方程的重要性不用我过多介绍了。各行各业都用的到。但是求解微分方程却是一件相当麻烦的事情。因为除了要计算加减乘除,还要计算微分积分。而傅里叶变换则可以让微分和积分在频域中变为乘法和除法,大学数学瞬间变小学算术有没有。

    傅里叶分析当然还有其他更重要的用途,我们随着讲随着提。

    ————————————————————————————————————

    下面我们继续说相位谱:

    通过时域到频域的变换,我们得到了一个从侧面看的频谱,但是这个频谱并没有包含时域中全部的信息。因为频谱只代表每一个对应的正弦波的振幅是多少,而没有提到相位。基础的正弦波A.sin(wt+θ)中,振幅,频率,相位缺一不可,不同相位决定了波的位置,所以对于频域分析,仅仅有频谱(振幅谱)是不够的,我们还需要一个相位谱。那么这个相位谱在哪呢?我们看下图,这次为了避免图片太混论,我们用7个波叠加的图。

    鉴于正弦波是周期的,我们需要设定一个用来标记正弦波位置的东西。在图中就是那些小红点。小红点是距离频率轴最近的波峰,而这个波峰所处的位置离频率轴有多远呢?为了看的更清楚,我们将红色的点投影到下平面,投影点我们用粉色点来表示。当然,这些粉色的点只标注了波峰距离频率轴的距离,并不是相位。


    这里需要纠正一个概念:时间差并不是相位差。如果将全部周期看作2Pi或者360度的话,相位差则是时间差在一个周期中所占的比例。我们将时间差除周期再乘2Pi,就得到了相位差。

    在完整的立体图中,我们将投影得到的时间差依次除以所在频率的周期,就得到了最下面的相位谱。所以,频谱是从侧面看,相位谱是从下面看。下次偷看女生裙底被发现的话,可以告诉她:“对不起,我只是想看看你的相位谱。”

    注意到,相位谱中的相位除了0,就是Pi。因为cos(t+Pi)=-cos(t),所以实际上相位为Pi的波只是上下翻转了而已。对于周期方波的傅里叶级数,这样的相位谱已经是很简单的了。另外值得注意的是,由于cos(t+2Pi)=cos(t),所以相位差是周期的,pi和3pi,5pi,7pi都是相同的相位。人为定义相位谱的值域为(-pi,pi],所以图中的相位差均为Pi。

    最后来一张大集合:

    四、傅里叶变换(Fourier Tranformation)

    相信通过前面三章,大家对频域以及傅里叶级数都有了一个全新的认识。但是文章在一开始关于钢琴琴谱的例子我曾说过,这个栗子是一个公式错误,但是概念典型的例子。所谓的公式错误在哪里呢?

    傅里叶级数的本质是将一个周期的信号分解成无限多分开的(离散的)正弦波,但是宇宙似乎并不是周期的。曾经在学数字信号处理的时候写过一首打油诗:

    往昔连续非周期,

    回忆周期不连续,

    任你ZT、DFT,

    还原不回去。

    (请无视我渣一样的文学水平……)

    在这个世界上,有的事情一期一会,永不再来,并且时间始终不曾停息地将那些刻骨铭心的往昔连续的标记在时间点上。但是这些事情往往又成为了我们格外宝贵的回忆,在我们大脑里隔一段时间就会周期性的蹦出来一下,可惜这些回忆都是零散的片段,往往只有最幸福的回忆,而平淡的回忆则逐渐被我们忘却。因为,往昔是一个连续的非周期信号,而回忆是一个周期离散信号。

    是否有一种数学工具将连续非周期信号变换为周期离散信号呢?抱歉,真没有。

    比如傅里叶级数,在时域是一个周期且连续的函数,而在频域是一个非周期离散的函数。这句话比较绕嘴,实在看着费事可以干脆回忆第一章的图片。

    而在我们接下去要讲的傅里叶变换,则是将一个时域非周期的连续信号,转换为一个在频域非周期的连续信号。

    算了,还是上一张图方便大家理解吧:

    或者我们也可以换一个角度理解:傅里叶变换实际上是对一个周期无限大的函数进行傅里叶变换。

    所以说,钢琴谱其实并非一个连续的频谱,而是很多在时间上离散的频率,但是这样的一个贴切的比喻真的是很难找出第二个来了。

    因此在傅里叶变换在频域上就从离散谱变成了连续谱。那么连续谱是什么样子呢?

    你见过大海么?

    为了方便大家对比,我们这次从另一个角度来看频谱,还是傅里叶级数中用到最多的那幅图,我们从频率较高的方向看。

    以上是离散谱,那么连续谱是什么样子呢?

    尽情的发挥你的想象,想象这些离散的正弦波离得越来越近,逐渐变得连续……

    直到变得像波涛起伏的大海:

    很抱歉,为了能让这些波浪更清晰的看到,我没有选用正确的计算参数,而是选择了一些让图片更美观的参数,不然这图看起来就像屎一样了。

    不过通过这样两幅图去比较,大家应该可以理解如何从离散谱变成了连续谱的了吧?原来离散谱的叠加,变成了连续谱的累积。所以在计算上也从求和符号变成了积分符号。

    不过,这个故事还没有讲完,接下去,我保证让你看到一幅比上图更美丽壮观的图片,但是这里需要介绍到一个数学工具才能然故事继续,这个工具就是——

     

    五、宇宙耍帅第一公式:欧拉公式

    虚数i这个概念大家在高中就接触过,但那时我们只知道它是-1 的平方根,可是它真正的意义是什么呢?


    这里有一条数轴,在数轴上有一个红色的线段,它的长度是1。当它乘以 3 的时候,它的长度发生了变化,变成了蓝色的线段,而当它乘以-1 的时候,就变成了绿色的线段,或者说线段在数轴上围绕原点旋转了 180 度。

    我们知道乘-1 其实就是乘了两次 i 使线段旋转了 180 度,那么乘一次 i 呢——答案很简单——旋转了 90 度。

    同时,我们获得了一个垂直的虚数轴。实数轴与虚数轴共同构成了一个复数的平面,也称复平面。这样我们就了解到,乘虚数i的一个功能——旋转。

    现在,就有请宇宙第一耍帅公式欧拉公式隆重登场——


    这个公式在数学领域的意义要远大于傅里叶分析,但是乘它为宇宙第一耍帅公式是因为它的特殊形式——当x等于 Pi 的时候。


    经常有理工科的学生为了跟妹子表现自己的学术功底,用这个公式来给妹子解释数学之美:”石榴姐你看,这个公式里既有自然底数e,自然数 1 和0,虚数i还有圆周率 pi,它是这么简洁,这么美丽啊!“但是姑娘们心里往往只有一句话:”臭屌丝……“

    这个公式关键的作用,是将正弦波统一成了简单的指数形式。我们来看看图像上的涵义:

    欧拉公式所描绘的,是一个随着时间变化,在复平面上做圆周运动的点,随着时间的改变,在时间轴上就成了一条螺旋线。如果只看它的实数部分,也就是螺旋线在左侧的投影,就是一个最基础的余弦函数。而右侧的投影则是一个正弦函数。

    关于复数更深的理解,大家可以参考:

    复数的物理意义是什么?

    这里不需要讲的太复杂,足够让大家理解后面的内容就可以了。

     

    六、指数形式的傅里叶变换

    有了欧拉公式的帮助,我们便知道:正弦波的叠加,也可以理解为螺旋线的叠加在实数空间的投影。而螺旋线的叠加如果用一个形象的栗子来理解是什么呢?

      光波

    高中时我们就学过,自然光是由不同颜色的光叠加而成的,而最著名的实验就是牛顿师傅的三棱镜实验:

    所以其实我们在很早就接触到了光的频谱,只是并没有了解频谱更重要的意义。

    但不同的是,傅里叶变换出来的频谱不仅仅是可见光这样频率范围有限的叠加,而是频率从 0 到无穷所有频率的组合。

    这里,我们可以用两种方法来理解正弦波:

    第一种前面已经讲过了,就是螺旋线在实轴的投影。

    另一种需要借助欧拉公式的另一种形式去理解:

    e^{it}=cos (t) +i.sin (t)
    e^{-it}=cos (t)-i.sin (t)

    将以上两式相加再除2,得到:

    这个式子可以怎么理解呢?

    我们刚才讲过,e^(it)可以理解为一条逆时针旋转的螺旋线,那么e^(-it)则可以理解为一条顺时针旋转的螺旋线。而 cos (t)则是这两条旋转方向不同的螺旋线叠加的一半,因为这两条螺旋线的虚数部分相互抵消掉了!

    举个例子的话,就是极化方向不同的两束光波,磁场抵消,电场加倍。

    这里,逆时针旋转的我们称为正频率,而顺时针旋转的我们称为负频率(注意不是复频率)。

    好了,刚才我们已经看到了大海——连续的傅里叶变换频谱,现在想一想,连续的螺旋线会是什么样子:

    想象一下再往下翻:

    是不是很漂亮?

    你猜猜,这个图形在时域是什么样子?

    哈哈,是不是觉得被狠狠扇了一个耳光。数学就是这么一个把简单的问题搞得很复杂的东西。

    顺便说一句,那个像大海螺一样的图,为了方便观看,我仅仅展示了其中正频率的部分,负频率的部分没有显示出来。

    如果你认真去看,海螺图上的每一条螺旋线都是可以清楚的看到的,每一条螺旋线都有着不同的振幅(旋转半径),频率(旋转周期)以及相位。而将所有螺旋线连成平面,就是这幅海螺图了。

    好了,讲到这里,相信大家对傅里叶变换以及傅里叶级数都有了一个形象的理解了,我们最后用一张图来总结一下:

    好了,傅里叶的故事终于讲完了,下面来讲讲我的故事:

    这篇文章第一次被卸下来的地方你们绝对猜不到在哪,是在一张高数考试的卷子上。当时为了刷分,我重修了高数(上),但是后来时间紧压根没复习,所以我就抱着裸考的心态去了考场。但是到了考场我突然意识到,无论如何我都不会比上次考的更好了,所以干脆写一些自己对于数学的想法吧。于是用了一个小时左右的时间在试卷上洋洋洒洒写了本文的第一草稿。

    你们猜我的了多少分?

    6 分

    没错,就是这个数字。而这 6 分的成绩是因为最后我实在无聊,把选择题全部填上了C,应该是中了两道,得到了这宝贵的 6 分。说真的,我很希望那张卷子还在,但是应该不太可能了。

    那么你们猜猜我第一次信号与系统考了多少分呢?

    45 分

    没错,刚刚够参加补考的。但是我心一横没去考,决定重修。因为那个学期在忙其他事情,学习真的就抛在脑后了。但是我知道这是一门很重要的课,无论如何我要吃透它。说真的,信号与系统这门课几乎是大部分工科课程的基础,尤其是通信专业。

    在重修的过程中,我仔细分析了每一个公式,试图给这个公式以一个直观的理解。虽然我知道对于研究数学的人来说,这样的学习方法完全没有前途可言,因为随着概念愈加抽象,维度越来越高,这种图像或者模型理解法将完全丧失作用。但是对于一个工科生来说,足够了。

    后来来了德国,这边学校要求我重修信号与系统时,我彻底无语了。但是没办法,德国人有时对中国人就是有种藐视,觉得你的教育不靠谱。所以没办法,再来一遍吧。

    这次,我考了满分,而及格率只有一半。

    老实说,数学工具对于工科生和对于理科生来说,意义是完全不同的。工科生只要理解了,会用,会查,就足够了。但是很多高校却将这些重要的数学课程教给数学系的老师去教。这样就出现一个问题,数学老师讲得天花乱坠,又是推理又是证明,但是学生心里就只有一句话:学这货到底干嘛用的?

    缺少了目标的教育是彻底的失败。

    在开始学习一门数学工具的时候,学生完全不知道这个工具的作用,现实涵义。而教材上有只有晦涩难懂,定语就二十几个字的概念以及看了就眼晕的公式。能学出兴趣来就怪了!

    好在我很幸运,遇到了大连海事大学的吴楠老师。他的课全程来看是两条线索,一条从上而下,一条从下而上。先将本门课程的意义,然后指出这门课程中会遇到哪样的问题,让学生知道自己学习的某种知识在现实中扮演的角色。然后再从基础讲起,梳理知识树,直到延伸到另一条线索中提出的问题,完美的衔接在一起!

    这样的教学模式,我想才是大学里应该出现的。

    最后,写给所有给我点赞并留言的同学。真的谢谢大家的支持,也很抱歉不能一一回复。因为知乎专栏的留言要逐次加载,为了看到最后一条要点很多次加载。当然我都坚持看完了,只是没办法一一回复。

    本文只是介绍了一种对傅里叶分析新颖的理解方法,对于求学,还是要踏踏实实弄清楚公式和概念,学习,真的没有捷径。但至少通过本文,我希望可以让这条漫长的路变得有意思一些。

    最后,祝大家都能在学习中找到乐趣…

    展开全文
  • 反向传播——通俗易懂

    万次阅读 多人点赞 2018-10-04 12:05:05
    最近在看深度学习的东西,一开始看的吴恩达的UFLDL教程,有中文版就直接看了,后来发现有些地方总是不是很明确,又去看英文版,然后又找了些资料看,才发现,中文版的译者在翻译的时候会对省略的公式推导过程进行...
  • spring cloud 常见面试题 来理解微服务(通俗易懂

    万次阅读 多人点赞 2018-11-19 16:17:15
    为什么要谈这些理论知识呢 理论知识 =面试时候的谈资 !!! 你只有进去公司才有资格去做一个码农ok话不多说 ...经历如此漫长的互联网发展 以本人的拙见软件开发粗略的分为三个阶段 ... 也就是说把要做的所有应用...
  • 通俗易懂的主成分分析法(PCA)详解

    万次阅读 多人点赞 2018-04-14 22:32:46
    转载自:http://blog.codinglabs.org/articles/pca-tutorial.html文章分析脉络梳理: 1.向量A和B的内积表示的是向量A在B上的投影长度。那么将一个向量与新的基做内积,结果则表示该向量在新的基下的坐标。...
  • 控制反转和依赖注入的理解(通俗易懂)

    万次阅读 多人点赞 2018-05-13 11:37:38
    学习过Spring框架的人一定都会听过Spring的IoC(控制反转) 、DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC 、DI这两个概念是模糊不清的,是很难理解的,今天和大家分享网上的一些技术大牛们对Spring...
  • 最近,我读到一篇材料,发现有一个很好的类比,可以把它们解释地清晰易懂。 1. 计算机的核心是CPU,它承担了所有的计算任务。它就像一座工厂,时刻在运行。 2. 假定工厂的电力有限,一次只能供给一个车间使用。也...
  • 1.输入图片 输入一张图片,为RGB三通道,像素为32x32,记为输入图像:32x32x3,3也叫深度: 2.卷积核 3.计算卷积 ...3.1如图,将输入图片展开(将图片周围补0),卷积核(有两个卷积核)也展开,图中连线的矩阵...
  • 前言 ...今天,我将全面总结自定义View原理中的measure过程,我能保证这是市面上的最全面、最清晰、最易懂的 文章较长,建议收藏等充足时间再进行阅读 目录 1. 作用 测量View的
  • Docker 通俗易懂的入门

    千次阅读 2015-04-25 22:24:57
    这篇转的文章讲的通俗易懂,算个入门的东西了~ 转自:http://www.csdn.net/article/2014-07-02/2820497-what's-docker 尽管之前久闻Docker的大名了,但是天资愚钝,对其到底是个啥东西一直摸不清,最近花了一...
  • 这里主要将网络里面的一些名词通俗易懂的简要说明 协议: 通俗说就是:中国人和中国人说普通话;印度人说印地语; 猫和猫说猫话(如黑猫警长打电话) : 咚1我是咚2;咚2,收到,我是咚1;巴拉巴拉…(讲猫语) ...
  • 转自知乎-我见过最通俗易懂的KMP算法详解

    万次阅读 多人点赞 2018-04-15 18:23:22
    有些算法,适合从它产生的动机,如何设计与解决问题这样正向地去介绍。但KMP算法真的不适合这样去学。最好的办法是先搞清楚它所用的数据结构是什么,再搞清楚怎么用,最后为什么的问题就会有恍然大悟的感觉。...
  • 计算机网络基础知识(通俗易懂)

    热门讨论 2010-03-30 15:50:38
    计算机网络基础知识,个人看了,觉得非常通俗易懂,发上来,跟大家一起分析。
  • 简单易懂的数据结构

    2018-08-11 17:28:48
    大话数据结构,以一种幽默生动带你走进数据结构的世界。
  • 本课程以通俗易懂的方式讲解 Node.js 技术,帮您快速入门! 课程内容包括: 1.Node.js简介 2.Node.js环境搭建 3.模块化简介 4.模块化的导出和导入 5.npm简介 6.npm常用命令和使用 7.全局模块nrm 8....
  • 本文档包含了作者对于遗传算法学习的一点总结,是为了巩固自己的所学,也为了让更多的小伙伴们快速掌握遗传算法这种智能算法。故在本文档中,既有遗传算法的简单介绍,也有一个简单的问题及求解的程序说明。
  • 教程不仅是零基础,通俗易懂,而且非常风趣幽默,像看小说一样!觉得太牛了,所以分享给大家。点这里可以跳转到教程。” 最近,想必大家不管是网络上、报刊上,还是在大街小巷,经常听到“物联网”这个名词,甚至还...
  • 一个非常非常好的BP神经网络课件,讲的非常简洁,非常到位,对刚刚开始学习神经网络的人很有帮助

空空如也

1 2 3 4 5 ... 20
收藏数 269,554
精华内容 107,821
关键字:

易懂