作者归档:文广

一文总结学习 Python 的 14 张思维导图

本文主要涵盖了 Python 编程的核心知识(暂不包括标准库及第三方库,后续会发布相应专题的文章)。

  1. 首先,按顺序依次展示了以下内容的一系列思维导图:基础知识,数据类型(数字,字符串,列表,元组,字典,集合),条件&循环,文件对象,错误&异常,函数,模块,面向对象编程;
  2. 接着,结合这些思维导图主要参考的资料,分享一下我的学习体验,一方面可供初学者参考,另一方面,也便于大家结合思维导图深入学习、理解、思考;
  3. 最后,提供几篇文章链接,方便希望从 Python 2.x 迁移到 3.x 的朋友理解。

注意事项

  • 本篇笔记原先基于 Python 2.x,经历多次改版,目前最新版本基于 Python 3.x,由于参考资料多来源于 2.x,可能有部分知识没有完全更新,欢迎提出意见,笔者会定期汇总修改。
  • 如需基于 Python 2.x 版本的笔记,可移步博客:https://woaielf.github.io (详见「总览」思维导图)。
  • 本文是笔者在个人学习过程中总结的学习笔记,难免有疏忽&错误之处,望大家提出宝贵意见。
  • 文末附 PDF 下载链接。

思维导图

  • 默认阅读顺序:从右→左,顺时针方向。
  • 思维导图软件:XMind

总览

14 张思维导图

基础知识


数据类型

序列

字符串

列表 & 元组

字典 & 集合

条件 & 循环

文件对象

错误 & 异常

函数

模块

面向对象编程

参考资料

浅谈物联网的关键技术和难点

物联网中的核心关键技术

核心关键技术主要有RFID技术、传感器技术、无线网络技术、人工智能技术、云计算技术等。

   1、RFID技术

是物联网中“让物品开口说话”的关键技术,物联网中RFID标签上存着规范而具有互通性的信息,通过无线数据通信网络把他们自动采集到中央信息系统中实现物品的识别。

 

 

    2、传感器技术

在物联网中传感器主要负责接收物品“讲话”的内容。传感器技术是从自然信源获取信息并对获取的信息进行处理、变换、识别的一门多学科交叉的现代科学与工程技术,它涉及传感器、信息处理和识别的规划设计、开发、制造、测试、应用及评价改进活动等内容。

 3、无线网络技术

物联网中物品要与人无障碍地交流,必然离不开高速、可进行大批量数据传输的无线网络。无线网络既包括允许用户建立远距离无线连接的全球语音和数据网络,也包括近距离的蓝牙技术、红外技术和Zigbee技术。

 

 

    4、人工智能技术

人工智能是研究是计算机来模拟人的某些思维过程和智能行为(如学习、推理、思考和规划等)的技术。在物联网中人工智能技术主要将物品“讲话”的内容进行分析,从而实现计算机自动处理。

 5、云计算技术

物联网的发展理离不开云计算技术的支持。物联网中的终端的计算和存储能力有限,云计算平台可以作为物联网的大脑,以实现对海量数据的存储和计算。

 

 

    物联网中的技术难点

 (1)数据安全问题

由于传感器数据采集频繁,基本可以说是随时在采集数据,数据安全必须重点考虑。

 (2)终端问题

物联网中的终端除了具有自己的功能外还有传感器和网络接入功能,且不同的行业千差万别,如何满足终端产品的多样化需求,对研究者和运营商都是一个巨大挑战。

6个编写优质干净代码的技巧

原文:6 Simple Tips on How to Start Writing Clean Code
作者:Alex Devero
译者:Teixeira10

【译者注】作为一名开发者,编写一手干净的代码很重要,所以在本文中作者先列举出编写干净代码的一些好处,再提出6个技巧用于编写干净代码,供开发者进行参考学习。
以下为译文:

编写干净的代码并不是一件容易的事情,这需要尝试不同的技巧和实践。问题是,在这个问题上有太多的实践和技巧,因此开发人员很难进行选择,所以要把这个问题简化一下。在本文中,将首先讨论编写干净代码的一些好处,然后将讨论6个技巧或者实践,用于编写最常用的干净代码。

以下是目录内容:

编写干净代码的好处
1. 更容易开始和继续一个项目
2.有利于团队新员工培训
3.更容易遵循编码模式

写干净代码的技巧
1.编写可读的代码
2.为变量、函数和方法使用有意义的名称
3.让每个函数或方法只执行一个任务
4.使用注释来解释代码
5.保持代码风格一致性
6.定期检查你的代码

关于编写干净代码的一些想法

写干净代码的好处

先来了解编写干净代码的一些好处。其中一个主要好处是,干净的代码可以减少花在阅读上的时间和理解代码的时间。凌乱的代码会减慢任何开发人员的速度,使开发者的工作变得更加困难。代码越混乱,开发人员就越需要花更多的时间去充分理解它,这样才能使用这些代码。而且,如果代码太乱,开发人员可能会决定停止阅读这些代码,并自己从头开始编写。

1.更容易开始和继续一个项目
先用一个简单的例子来说明这个问题。假设在很长一段时间后我们回到了之前的一个项目,也许在这段时间是一位客户联系我们去做了另一项工作。现在,想象一下,那时如果没有编写干净的代码,那么在第一眼看到代码之后,该是有多糟糕和混乱。而且,也可以知道从当初离开的地方开始编码有多困难。

因此,现在必须花更多的时间在项目上,因为我们需要理解之前编写的代码。这本来是可以避免的,如果从一开始就编写干净的代码,然而现在必须为此付出代价。而且,旧代码是如此混乱和糟糕,以至于我们可能决定从头开始。客户听到这些消息后可能不会高兴。

另一方面,干净的代码通常就没有这个问题。假设前面的例子是相反的情况,以前的代码是干净和优雅的,那么理解它需要多长时间?也许只需要读几分钟的代码就能理解所有的工作原理,而且我们可能已经开始编写一段时间了,所以在这种情况下花的精力将明显小于第一个案例,同时,客户也不会太在意。

这是编写干净代码的第一个好处,而且,这不仅适用于自己的项目,也适用于其他开发人员的工作。干净的代码可以更快地启动工作,任何人都不需要花费数小时来研究代码,相反,我们可以直接进入工作。

2.有利于团队新员工培训
编写干净代码的另一个好处与第一个好处是密切相关的,那就是可以让新员工更容易更快地使用代码。假设我们需要雇佣一个开发人员,那么她要花多长时间才能理解代码并学会使用它呢?当然这要视情况而定。如果我们的代码很乱,写得很差,她就需要花更多的时间来学习代码。另一方面,如果代码干净、易读、简单易懂,她将能够更快地开始她的工作。

有些人可能会说,这不是个问题,因为其他开发人员可以帮助她。当然这是正确的,但是帮助只应该花很短的时间,是两三次或者一两天,而并不应该是两三个星期。所以,决定雇佣另一个开发人员的目的,是来加速我们的工作,而不是减慢速度,也不是花费更多的时间来帮助她学会使用代码。

当我们努力写出干净的代码时,其他人就会向我们学习,也就更容易跟着写出干净的代码。当然,仍然需要留出一些时间来帮助每个新开发人员了解和理解代码。当然,我的意思是几天,而不是几周。此外,干净的代码将帮助团队带来更多的开发人员,并同时帮助他们理解代码。简单地说,代码越简洁就越容易解释,误解也就越少。

3.更容易遵循编码模式
有一件事需要记住,理解和学习如何使用代码是一回事。然而,这仅仅是个开始,同时还需要确保开发人员能够愿意遵循我们的编码模式。当然,使用干净的代码比混乱的代码更容易实现这个目标。这是很重要的,因为团队不仅想要编写干净的代码,而且还一直保持这种模式,这也是需要长期思考的。

另外,如果开发人员不遵循当前的编码模式该怎么办? 这个问题通常可以自行解决。假设有一群人在同一个代码基础上工作,其中一个人开始偏离标准样式。然后,团队的其他成员将推动这个开发人员遵循标准。她会接受建议,因为她不想离开这个团队。

还有一种情况,开发人员会说服团队的其他人采纳并遵循自己的编码模式。如果开发人员提出的编码模式更干净,并且能带来更好的结果,这当然是件好事。的确,编写和保持干净的代码并不意味着应该忽略任何改进它的机会,我认为应该始终对目前的做法保持可改进的态度,并努力寻找改进的机会。

因此,如果一个开发人员偏离了当前的模式,同时她的模式也更好,那么我们做出改变也许会更合适。所以在尝试其他模式之前,不应该忽视其他人的编码实践,同时我们应该继续寻找改进的余地。最后,第三种情况。开发人员决定既不采用我们的实践,也不说服我们采用她的实践。因为她将决定离开团队。

写干净代码的技巧

现在除了讨论编写干净代码的好处,也是时候学习一些技巧来帮助我们实现这个目标了。正如将在以下看到的,干净的代码包含并遵循着一些方法。这些方法使代码更干净、易读、更易于理解、更简单。当然没有必要实施所有的方法,实施并遵循一两项措施就足以带来积极的结果。

1.编写可读的代码
的确,所写的代码将会机器解释,然而这并不意味着应该忽视代码的可读性和可理解性,因为在将来总会有另一个人会使用我们写的代码。即使让别人无法访问我们的代码,但我们自己也可能在将来又重新拾起这些代码。出于这些原因,让代码便于阅读和理解是符合我们自己的利益的。那么如何实现呢?

最简单的方法是使用空格。在发布代码之前,可以缩减代码,但是没有必要让代码看起来很小型化。相反,可以使用缩进、换行和空行来使代码结构更具可读性。当决定采用这种方式时,代码的可读性和可理解性就会显著提高。然后,看着代码就可以更容易理解它了。来看两个简单的例子。
代码:

// Bad
const userData=[{userId: 1, userName: 'Anthony Johnson', memberSince: '08-01-2017', fluentIn: [ 'English', 'Greek', 'Russian']},{userId: 2, userName: 'Alice Stevens', memberSince: '02-11-2016', fluentIn: [ 'English', 'French', 'German']},{userId: 3, userName: 'Bradley Stark', memberSince: '29-08-2013', fluentIn: [ 'Czech', 'English', 'Polish']},{userId: 4, userName: 'Hirohiro Matumoto', memberSince: '08-05-2015', fluentIn: [ 'Chinese', 'English', 'German', 'Japanese']}];

// Better
const userData = [
  {
    userId: 1,
    userName: 'Anthony Johnson',
    memberSince: '08-01-2017',
    fluentIn: [
      'English',
      'Greek',
      'Russian'
    ]
  }, {
    userId: 2,
    userName: 'Alice Stevens',
    memberSince: '02-11-2016',
    fluentIn: [
      'English',
      'French',
      'German'
    ]
  }, {
    userId: 3,
    userName: 'Bradley Stark',
    memberSince: '29-08-2013',
    fluentIn: [
      'Czech',
      'English',
      'Polish'
    ]
  }, {
    userId: 4,
    userName: 'Hirohiro Matumoto',
    memberSince: '08-05-2015',
    fluentIn: [
      'Chinese',
      'English',
      'German',
      'Japanese'
    ]
  }
];

代码:

// Bad
class CarouselLeftArrow extends Component{render(){return ( <a href="#" className="carousel__arrow carousel__arrow--left" onClick={this.props.onClick}> <span className="fa fa-2x fa-angle-left"/> </a> );}};

// Better
class CarouselLeftArrow extends Component {
  render() {
    return (
      <a
        href="#"
        className="carousel__arrow carousel__arrow--left"
        onClick={this.props.onClick}
      >
        <span className="fa fa-2x fa-angle-left" />
      </a>
    );
  }
};

2.为变量、函数和方法使用有意义的名称
来看一看第二个技巧,它将帮助我们编写可理解和干净的代码。这个技巧是关于变量、函数和方法的有意义的名称。“有意义的”是什么意思?有意义的名字是描述性足够多的名字,而不仅仅是编写者自己才能够理解的变量、函数或方法。换句话说,名称本身应该根据变量、函数或方法的内容和使用方式来定义。
代码:

// Bad
const fnm = ‘Tom’;
const lnm = ‘Hanks’
const x = 31;
const l = lstnm.length;
const boo = false;
const curr = true;
const sfn = ‘Remember the name’;
const dbl = [‘1984’, ‘1987’, ‘1989’, ‘1991’].map((i) => {
  return i * 2;
});

// Better
const firstName = ‘Tom’;
const lastName = ‘Hanks’
const age = 31;
const lastNameLength = lastName.length;
const isComplete = false;
const isCurrentlyActive = true;
const songFileName = ‘Remember the name’;
const yearsDoubled = [‘1984’, ‘1987’, ‘1989’, ‘1991’].map((year) => {
  return year * 2;
});

然而需要注意的是,使用描述性名称并不意味着可以随意使用任意多个字符。一个好的经验则是将名字限制在3或4个单词。如果需要使用超过4个单词,说明这个函数或方法需要同时执行很多的任务,所以应该简化代码,只使用必要的字符。

3.让一个函数或方法只执行一个任务
当开始编写代码时,使用的函数和方法看起来就像一把瑞士军刀,几乎可以处理任何事情,但是很难找到一个好的命名。另外,除了编写者,几乎没有人知道函数是用来做什么的以及该如何使用它。有时我就会遇到这些问题,我在这方面做的很不好。

然后,有人提出了一个很好的建议:让每个函数或方法只执行一个任务。这个简单的建议改变了一切,帮助我写出了干净的代码,至少比以前更干净了。从那以后,其他人终于能够理解我的代码了,或者说,他们不需要像以前一样花很多时间去读懂代码了,功能和方法也变得更好理解。在相同的输入下,总是能产生相同的输出,而且,命名也变得容易得多。

如果你很难找到函数和方法的描述性名称,或者需要编写冗长的指令以便其他人可以使用,那请考虑这个建议,让每个函数或方法只执行一个任务。如果你的功能和方法看起来像瑞士军刀一样无所不能,那请你执行这个方法,相信我,这种多才多艺不是一种优势。这是一个相当不利的情况,可能会产生事与愿违的结果。

附注:这种让每一个函数或方法只执行一项任务的做法被称为保持纯函数。这种编码实践来自于函数式编程的概念。如果你想了解更多,我推荐阅读《So You Want to be a Functional Programmer series[4]》。
代码:

// Examples of pure functions
function subtract(x, y) {
    return x - y;
}

function multiply(x, y) {
    return x * y;
}

// Double numbers in an array
function doubleArray(array) {
  return array.map(number => number * 2)
}

4.更容易遵循编码模式
不管多么努力地为变量、函数和方法想出有意义的名字,代码仍然不可能完全清晰易懂,还有一些思路需要进行解释。问题可能不是代码很难理解或使用,相反,其他人可能不理解为什么要实现这个函数或方法,或者为什么要以特定的方式创建它。意思是,创建函数或方法的意图还不清楚。

有时可能不得不采用非传统的方法来解决问题,因为没有足够的时间来想出更好的解决方案,这也很难用代码来解释。所以,通过代码注释可以帮助解决这个问题,也可以帮助我们向其他人解释为什么写了这个方法,为什么要用这种特定的方式来写,那么其他人就不必猜测这些方法或函数的用途了。

更重要的是,当我们使用注来解释代码后,其他人可能会找到一个更好的方法来解决这个问题并改进代码。这是有可能的,因为他们知道问题是什么,以及期望的结果是什么。如果不知道这些信息,其他人就很难创建更好的解决方案,或者他们可能不会去尝试,因为他们认为没有必要去修改创建者自己的想法。

因此,每当自己决定使用一些快速修复或非传统的方法时,要用注释来解释为什么这么做。最好是用一两行注释来解释,而不用别人来猜测。

也就是说,我们应该只在必要的时候使用注释,而不是解释糟糕的代码。编写无穷无尽的注释将无助于将糟糕的代码转换成干净的代码。如果代码不好,应该通过改进代码来解决这个问题,而不是添加一些如何使用它的说明。编写干净的代码更重要。

5.保持代码风格一致性
当我们有自己喜欢的特定编码方式或风格时,就会在任何地方一直使用它。但在不同的项目中使用不同的编码风格不是一个好主意,而且也不可能很自然地回到以前的代码,所以仍然需要一些时间来理解在项目中使用的编码风格。

最好的方法是选择一套编码方式,然后在所有的项目中坚持使用。这样的话,回到之前的旧代码会变得更容易。当然,尝试新的编码方式是一件好事,它可以帮助我们找到更好的方法来开展工作。但是最好是在不同的实验项目或练习上尝试不同的编码风格,而不是在主要项目上进行。

另外,当我们决定做一些试验的时候,就应该尝试多次练习,应该花时间彻底地做好。只有真正确信喜欢这种做法,并且对它感到满意时,才应该去实施它。而且决定这样做的时候,最好应用在所有的项目中。是的,这需要时间,这也会促使我们正确地思考。

6.检查你的代码

这是最后一个技巧。不仅仅是编写干净的代码,还要完成最后的工作,那就是需要维护干净代码。我们应该定期检查代码,并试着改进它。否则,如果不审查和更新我们的旧代码,它很快就会过时,就像我们的设备一样。如果想让代码保持最佳状态,就需要定期更新它们。

对于每天使用的代码,情况也是如此。代码会变得更加复杂和混乱,所有应该避免这种情况发生,并保持代码干净。实现这一点的唯一方法是定期检查我们的代码。换句话说,我们需要保持它。对于那些未来不再关心的项目来说,这可能是不必要的,但对其他的来说,维护代码是工作的一部分。

关于编写干净代码的一些想法

今天讨论的这六种做法,可能不是影响最大的,也可能不是最重要的,但这些是经验丰富的开发人员最常提到的,这也就是我选择它们的原因。我希望这些实践或技巧能够帮助你开始编写干净的代码。现在,就像所有的事情一样,最重要的是开始。所以,至少选一个技巧,然后试一试。

循序渐进地代码重构

对于如何进行代码重构,一直有着很多种说法。很多人都认为应该将重构代码放在backlog里。但是其实,这并不是一个理想的方法。

在项目刚刚开始的时候,你的代码很干净。

即使有的时候需要小小的绕一下路,但是这个时候我们可以轻松、平稳的添加功能。这个阶段一般都不会出现问题,而且由于我们比较着急,所以即使出现了一些小问题,我们也不会注意到。

然而,随着项目做的时间变长,这些小的问题就会累计起来。这就是人们所说的“技术债务”。其本质,就是并不算特别好的代码,但是这个时候其问题还没有完全显现出来。

但是,随着我们一直添加新功能,这些问题就会逐渐显现出来,我们不得不小心翼翼的绕开他们。

不可避免的,我们的开发速度会被拖慢。但是为了追求速度,我们开始变得越来越不小心,不久之后,问题也会越来越多。

这些问题会像积木一样累计起来,层层叠叠,让我们的开发速度变得更慢。虽然我们终于意识到了问题的存在,但是没有时间彻底解决它。我们只能继续小心翼翼的绕开它们。

很快,我们会发现半数以上的代码都与那些小问题有交集,它们无时无刻不在影响我们的开发速度。直到有一天,你发现自己没法继续绕开它们。

不得不做点事情了。我们必须要进行复杂的代码重构,让我们重新获得干净的代码。你不得不向上级申请时间进行代码重构。其实这种工作方式并不好,我们花时间去填自己以前挖的坑。而且有的时候,公司并没有让你去重构代码的时间。

即使公司给你时间了,你也很难很好的对代码进行重构。要知道,重构代码所需的时间,往往要远高于你的预期。如果这些纷乱的代码是你用了10周写出来的,那么你很难再用10周的时间对它们进行重构。
由此可见,这种代码重构的方式并不好。那么我们应该怎么做呢?

很简单,那就是每遇到一个问题,就马上解决它,而不是选择绕过它。完善当前正在使用的代码,那些还没有遇到的问题,就先不要理它。在当前前进的道路上,清除所有障碍,以后你肯定还会再一次走这条路,下次来到这里的时候你会发现路上不再有障碍。软件开发就是这样。

或许解决这个问题需要你多花一点时间。但是从长远来看,它会帮你节省下更多的时间。

在添加新功能的时候,我们就先清理这个功能所需要的代码。花一点时间,用滴水穿石的方法逐渐清理代码,随着时间的推移,我们的代码就会越来越干净,开发速度也会越来越快。

一段时间之后,你会发现之前所有的技术债务都不见了,所有的坑都被填平了。这种循序渐进的代码重构的好处开始显现,编程的速度明显加快
这才是代码重构的正确打开方式!

连载:全球最牛的28个大数据可视化应用案例(一)

声明:本文由入驻搜狐公众平台的作者撰写,除搜狐官方账号外,观点仅代表作者本人,不代表搜狐立场。举报

  随着大数据在人们工作及日常生活中的应用,大数据可视化也改变着人类的对信息的阅读和理解方式。从百度迁徙到谷歌流感趋势,再到阿里云推出县域经济可视化产品,大数据技术和大数据可视化都是幕后的英雄。今天,我们将连载由Teradata独家提供的来自全球28个大数据可视化应用案例。文章中不仅有极具艺术美感的可视化炫图,更有作者为大家解析可视化是如何制作的。

本系列4篇文章为36大数据独家专稿,任何不表明来源36大数据和Teradata以及本文链接http://www.36dsj.com/archives/41214的转载均为侵权。公众号也是如此。

一、航线星云

作者:Karthik Guruswamy

关于洞察

截止到2012年1月,开源网站OPENFLIGHTS.ORG上记载了大约6万条直飞航班信息,这些航班穿梭在3000多个机场间,覆盖了500多条航线。

通过高级分析技术,我们可以看到世界上各家不同的航空公司看起来就像是一个美丽的星云(国际星云的组成部分)。同种颜色的圆点和粗线提供了见解,它们代表提供相同航线的航空公司,显示出它们之间的竞争以及在不同区域间的潜在合作。

这张基于数据可视化的Sigma图表显示了服务城市相似的不同航空公司。图中的圆点或圆圈代表航空公司,连线的粗细和远近则反映两个航空公司之间的相似性;连线越粗或越短则代表两家航司服务的城市越相似。图表中有几组航空公司,直观地表现了它们所服务的地理区域。

这张图表中的关键洞察当然地是航空公司之间的相似性甚至是重叠,它们是中国的南航和东航、阿联酋航空和卡塔尔航空、英航和汉莎航空、美航和达美航空;我们可以从中看出这些公司之间的竞争关系。瑞安航空则通过服务与汉莎航空和英航存在潜在协力的城市占据了一个利基市场;比起意大利或汉莎等其他的欧洲航司,法国航空则与美国联航等美国航空公司更为相似,这也许可以解释为联合品牌效应。本质上说,这是一张多维的韦恩图,用一种简明扼要的方式揭示了不同主体间的复杂关系。

总的来说,这张图表揭示了不同航司之间的相似性和竞争情况,有利于发掘潜在的合作关系、增加市场份额和市场覆盖面。这项技术可以通过不同参与者之间的相同变量,用于分析任何生态系统。

分析技术

这张可视化图表通过Aster App中心生成,运用到了关联挖掘的分析技术,研究上下文中各条目的共现关系。其中关联挖掘的算法是协同过滤,它作用于航线和城市数据,并将数据当做零售篮子数据。也就是说,篮子代表城市,而航空公司则是条目。两个航司之间的相似性由相似性得分确定,计分的原则是比较各个航司独有的航线以及同时运营的航线。之后再将这些成对的相似性得分当做连线的权重,再把各个航司当做节点,共同输入可视化仪器当中,运用具有模块上色技术的force-atlas算法,最终生成出这张美丽的图表。

二、Calling Circles

作者:Christopher Hillman

关于洞察

我们无论何时何地都在使用手机并且产生出非常大量的资料,这些资料代表了我们每天的行为及活动。我们与其他人的每通电话及简讯都对应到我们的社会关系、商业活动以及更广泛的社群互动并且形成了许多复杂互相联结的通话圈。

这个资料视觉化图表是从行动电话使用者的通话模式资料所制作的。每个点都代表一个使用者拨出的手机号码,愈大的点就代表这个号码被拨打愈多次。每条两点之间的线都代表着从一个号码拨打到另一个号码。

每个行动电话使用者都会有一种独特的通话模式,这种模式可以用来发展适合的话费方案并且可以用来定义或预测他/她的行为。举例来说,当一个使用者正要从现在的行动电话服务商转换到另一个服务商时,我们可以从网内及网外发现两个类似的通话模式。

这张特别的图表是在前期由一连串的分析产生用来过滤第一层的通话模式。这里使用到的资料只从在几秒钟的时间取得。从图表的左上角可以看到许多大回圈,这些回圈表示短时间内这些号码被拨打了许多次。可以推测这些号码有可能是机器,像是自动答录机、互动式语音应答(IVR) 系统、安全系统或警报。人类不可能在短时间拨出这么多电话。这些电话会先放置在一个分开的群组,后续的分析就可以集中在个人使用者的通话模式上。

分析技术

我们利用图表来达成资料视觉化,虽然在调整版面格式的参数与传统展示图表不同。有一个常见的问题就是这些互连的图表通常在短时间就会变成非常巨大且因为庞大的互动次数导致几乎不可能被视觉化。从一个高度连结的图表里选出一段范例是一个困难的问题,因为我们需要决定忽略哪些连结。在这个例子里,我们取用来自非常短的时间的资料来达到一个可以呈现的资料范围。

资料格式就相对简单,拨话号码、收话号码、拨话时间、通话时间。我们先利用机器学习(machine-learning) 来对资料作分群然后再利用Aster Lens 来展示图表。

Calling Circles作者介绍

Christopher Hillman

Christopher Hillman 跟他的妻子及两个小孩住在英国伦敦,在Teradata 的进阶分析团队(Advanced Analytics team) 担任首席资料科学家在全世界旅行工作。

他钟情于分析工作且有二十年的经验于商业智慧(business intelligence) 及进阶的分析产业。在Teradata 之前,Chris在Retail 和CPGN vertical作为一位解决方案架构师(solution architect)、首席顾问及技术总监。 Chris 现在与Teradata Aster 专家一同工作且参与大数据的分析专案,他帮助客户洞察资料中的价值并且了解MapReduce 或SQL 作为合适的技术。

在Teradata 工作的期间,Christopher 也同时攻读在Dundee 大学的资料科学博士并运用大数据分析在人类蛋白类的实验资料上。他的研究领域包含利用平行化演算法即时分析质谱仪的资料。他也在大学开课教授Hadoop 及MapReduce 程式设计。

三、信号风暴骑士

作者:桑德拉.拉曼 (Sundara Raman)

关于洞察

此可视化捕捉了桑德拉.拉曼在澳大利亚悉尼通勤列车廊道的旅程。桑德拉携带其手机和专用软件乘坐列车穿行于悉尼, 由于列车快速穿过城市, 我们可以通过其手机与信号发射塔的连接来跟踪, 用彩点(或节点)描绘在图表上。

利用手机数据对运动中的、聚集大量人群的交通模式进行研究是新分析形式的一部分。其主要目的在于优化发射塔网络、避免性能问题、改善客户体验。但它还能支持新兴数据货币化发展,详细的交通流量信息可用于城市规划、零售商店位置分析和市场营销供应。

桑德拉在分析中探寻能击垮发射塔、影响手机性能的信号“风暴”。当拥挤的通勤列车奔跑于轨道线上,后停于车站,列车发出的100-1000个信号快速移动于各发射塔之间,就足以击垮它们。该可视化是一系列图表的一部分,覆盖了发射塔性能数据、通勤交通流量以及塔切换的信息,准确表现出手机信号的“风暴潮”,从而据此提出详细的建议来优化网络。

图表中还能突显出特定客户体验时由于在4G发射塔(暗点)和低速3G发射塔(亮点)间切换而出现的问题—-信号在发射塔之间来回反复切换,塔信号强度剧烈变化,产生“乒乓效应”。典型代表是位于林菲尔德、可莱雅、怀塔拉、北悉尼以及查茨伍德各车站附近的相连的封闭式发射塔群。

分析方法

该可视化是通过Teradata Aster和Aster Lens实现的。智能手机的遥信数据是从同时使用的3G和4G手机中收集的, 收集在拥挤的公共交通路线上使用专用软件的数据, 地点是沿着澳大利亚悉尼北岸线和史卓菲市交通线一带。分析还包括了对火车站和信号发射塔位置数据的地理空间分析, 从而将位于火车站方圆1公里内的发射塔隔离出来。这个方法有助于衡量确定小范围内,车站周围各发射塔之间信号传播的影响。另外GEXF西格玛图表中还添加了颜色代码, 利用可视化语言统一地区分4G和3G信号发射塔的区域。每种颜色代表一组发射塔的网络覆盖区域。悉尼城市铁路公布的统计数据涉及峰值时间每个车站火车的交通负荷, 分析则利用这一数据关联了手机站点的性能。

作者介绍

桑德拉.拉曼 (Sundara Raman)

桑德拉白天是一位高级电信行业咨询师, 夜间则是一位胸怀大志的数据科学家。他在新西兰梅西大学获得商业管理硕士学位, 现在与妻子及2个孩子住在澳大利亚的悉尼。

桑德拉还是一名发明家, 他曾与他的妻子共同应用“认知行为疗法”(CBT)原则, 设计出“计算机辅助心理评估与治疗”, 获得了澳大利亚一项专利权。

所以, 如果你在下一个日常通勤时碰巧瞥见桑德拉在把玩多个手机, 你就会明白他不是疯了。他只是在利用分析获得深入见解, 从而帮助电信客户改善移动网络的客户体验。

四、互联网络

作者:Yasmeen Ahmad

关于洞察

这一匿名可视化报告用于支持一家Telco运营商分析住宅Telco线路。该项目旨在确定线路与网络硬件性能之间的关联,此类关联可能影响到客户体验。

点(节点)代表Telco网络上的DSLAM(数字用户线接入复用器)。DSLAM提供了一项重要服务,能够影响客户呼叫体验;它们可将客户线路连接到主网络。

DSLAM服务级别有多项测量指标,例如衰减、比特率、噪声容限和输出功率,并可针对每条线路整合至三个性能类别。紫色节点显示具备卓越性能的DSLAM,橙色显示具备出色性能的DSLAM,白色显示性能较差的DSLAM。

在图表中,仅少数DSLAM体验到了高质量服务(紫色)。这些 DSLAM 在同一建筑中与主网络基础设施共置,由于靠近中央网络中枢,从而带来了优质服务。大多数客户实现了出色体验(橙色),同时我们发现城市郊区存在服务较差(白色)的DSLAM。

当客户获得可变网络质量时,客户体验和满意度会受到很大影响。Telco的主要目标是确保客户获得一致的体验,即使是那些身处主城市外部的用户也不例外。此图表确定了每个提供可变服务级别的 DSALM;以出色(橙色)和较差(白色)簇之间共享的节点表示。借助这一数据,Telco现在能够调查和优化可变DSLAM。

分析方法

这一西格玛可视化报告使用内建分析和在Teradata Aster平台内发现的可视化创建而成。

收到的数据来自整个城市的住宅线路,其属性包括衰减、比特率等。我们对这些属性进行了整合,以确定表明客户网络体验的性能等级。

这些簇构成了相关性和回归分析的基础,以确定在不同因素下网络性能的变化,这些因素包括:线路技术和长度、调制解调器类型和配置、DSLAM、卡技术、地理位置等。

该西格马可视化图表仅显示了整体分析的一部分,即DSLAM与网络性能间的联系。

作者介绍

Yasmeen Ahmad

Yasmeen是Teradata的最有创意和有见地的数据科学家之一。 Yasmeen在苏格兰长大,她喜欢户外活动,尤其是在苏格兰Munros山和在海上划皮艇。

她在许多国家工作过,包括英国、爱尔兰、荷兰土耳其、比利时和丹麦,她涵盖了金融,电信,零售和公用事业等行业。 Yasmeen专精与企业合作以确定他们的挑战,并将其转化为分析背景。她专注于企业如何利用新的或尚未开发的数据来源,沿着新技术以提高自身的竞争能力的独特能力。

Yasmeen已经与许多分析团队工作,提供领导,培训,指导和实践的支持,提供可操作的见解和经营成果。她使用各种分析方法,包括文本分析,预测建模,归属策略和时间序列分析的发展。她坚信可视化的力量使的在企业用户可以容易进行复杂的沟通。

在Teradata之前,Yasmeen在生命科学行业工作作为数据科学家,建设复杂、多维数据分析管线。 Yasmeen还持有数据管理,挖掘和可视化,这是进行在威康信托中心的基因调控和表达的博士学位。她在国际上发表了多篇论文并在国际会议和活动中演讲。此外,她还在MSc教有关科学数据和商业智能硕士课程。

Yasmeen对于数据分析和可视化有敏锐的热情,通过她的研究中一直好奇地问问题并了解更多信息。这些技能已经允许Yasmeen探索多学科的机会,为她提供了新的无尽的挑战!

五、连续性集装箱修理

作者:Frances Luk

关于洞察

物流集装箱在运输过程中常常会受到损伤,而这些集装箱的修理则依靠世界各地数以百计的供应商来处理。在通常情况下,如果状况不好无法继续使用,受损的集装箱会在被运往下个目的地之前就近修理。我们的客户是全世界最大的一家物流公司,他们希望了解集装箱的修理质量以及各个提供修理的供应商。在进行这项分析之前,客户无法获知集装箱使用寿命当中所发生事件的整体概览。而通过重现每个集装箱使用寿命当中发生的所有事件,我们成功地分析出了集装箱的修理模式。

通过这项分析,客户希望找出因为同一种损伤原因而发生的连续的修理活动,规定这两次修理发生在某一段时间内,或者说第二次修理比预期的时间提前了。这种活动表示早期修理的质量较差,从而造成了第二次的修理。这张桑基图中第一列的方框代表负责第一次修理的国家。

第二列的方框则代表负责第二次修理的国家。从第一列方框直接连到‘结束’框的则代表在第一次修理之后没有再发生修理行为,这是理想的状况;连到第二栏方框的则是意外情况。这张可视化图表让我们的客户得以按地域查看提供修理的供应商,未来还可能在工厂层级继续深钻。

分析技术

集装箱修理活动通过内建的数据装载器从Teradata数据库牵引到了Aster数据库中。我们利用事件序列和模式匹配技术来鉴别连续性修理活动。我们利用这张桑基图来比较不同国家修理工厂的质量,图中的线越粗则表示两个国家共同出现的次数越多。这张图表提供了极佳的整合信息,显示出应该关注于哪个国家,接下去可以利用数据来计算重点关注国家发生第二次修理的相对频率。这张桑基图通过Aster平台中的Aster Lens生成。

作者介绍

Frances Luk

Frances Luk是丹麦哥本哈根团队的一名数据科学家。她从小在香港长大,但某天却决定要去做一些不一样的事情,现在和她的丈夫还有两只可爱的小猫一起在丹麦生活,还拥有哥本哈根大学的硕士学位。在成为数据科学家之前,她曾经用五年时间来开发企业Java应用,并有七年从事银行和物流行业的数据仓库和数据分析的经验,现在负责丹麦和其他北欧国家的跨行业售前和大数据管理PS服务。

Frances对数据科学的热情来源于她强大的技术背景以及她对商业强烈的好奇心。每一比特的数据对她来说都像是一个谜,她喜欢拼凑细节并享受美丽图像产生的那一刻,喜欢看到客户发现未知的洞察时脸上惊叹的表情,这就是她每天工作的功力。

六、集装箱修理波浪

作者:Frances Luk

关于洞察

在通过遍布世界的船舶、卡车、火车进行运输的时候,集装箱时时会受到损伤。损伤情况发生时,集装箱会被运到最近的修理铺里,而这些成百上千个的修理铺散布在世界的各个角落。

我们的客户马士基航运公司希望加强他们对不同修理铺修理质量的了解。过去他们无法在每一个集装箱的层级上对这些数据进行分析,但Teradata Aster平台让马士基航运能够在这个层级调查并分析修理结果,获取有趣的发现、了解它们的模式和趋势,而这是前所未有的。

这张可视化图表中右下方的点代表不同的修理活动,曲线上方的点则表示不同的商品,商品和修理活动之间的连线则代表运输某种商品之后马上发生某种修理活动的频率;连线越粗表示运过某种商品后集装箱发生修理的频率越高。从图中可以看到,最粗的线连接着废金属和底板损伤,也就是说最经常出现的商品和修理类型配对是废金属和集装箱底板修理。

对于马士基航运来说,知道废金属最经常导致破损当然不是什么新鲜事,但采集到的这些数据为将来的分析奠定了强大的基础,(自然可以延伸到考虑比如比起其他货品,是不是更经常要运送废金属)。我们不能完全肯定废金属和底板破损之间的因果关系,但这张可视化图表却突出了问题的规模,建立了马士基航运公司的高级分析团队未来进行更细致的分析时的好的起点。将来的分析工作完成时,最终得到的结果可能就是更差异化的货运定价模型,抵减预计的运后修理成本。

分析技术

集装箱运输和修理活动通过内建的数据加载器从Teradata牵引到Aster当中。通过和马士基航运的ADL(敏捷数据实验室)和AA(高级分析)团队紧密合作,我们确定了适合的途径,用来分析货物和修理之间的关系,并应用模式匹配技术调查连续性运输和修理的模式。

之后我们用sigma可视化工具来展现货物和修理类型之间的关系,这两者在图中表示为实心点,连线的粗细表示共现的次数。初始sigma图通过Aster平台中的Aster Lens生成,现在展现的是优化版本。

作者介绍

Frances Luk,同连续性集装箱修理是一个作者。

七、Terror Report

作者:Kailash Purang

关于洞察

这份资料视觉化是Kailash Purang两部分CIA 报告的第一部分。它展示了进阶分析可以快速地客观地从复杂的文件精炼成简单易懂的视觉化图表。这份图表应该与第两部分的报告(Crown Of Thorns) 一起被检视。

Kailash 刻意挑选了一个具高度政治及情绪相关的主题,这份报告是美国参议院特别委员会研究院针对2001 到2006 年CIA(Central Intelligence Agency) 拘留和审讯程序及审讯拷打的研究。

这是一份相当长的报告,总共从6000 页中有525 页被公开,其中包含特定的政府用词以及在技术文件上会有的专有名词。这是份极端重要的文件以至于少数人可以第一手阅读到并且提供自己的意见,大部分人只能从其他人写的摘要报告接触到。然而像这样泛政治化及情绪性的主题,我们如何确定我们读到的摘要是完全正确且没有其他人的主观意见呢?

简短地来说,这是一个对于测试分析工作是否可以提供一个简单客观的方法来检视报告内容的理想主题。

Kaliash 的第一个视觉化图表”恐怖攻击” 是简单的文字云(word cloud),报告里愈常出现的特定文字在图表上呈现愈大的图形。文字云这样的图表可以很快速被制作,也可以轻易客观被吸收。然而,太粗浅的呈现是它的限制,我们从中可看到关键字,但是并无法从图表中得知任何的细节也无法知道各个主题中间的关联。文字云提供我们一个快速且非常简单的方式来了解报告里的内容。

请接着阅读第二部分“Crown Of Thorrns” 。

分析方法

这份视觉化使用525 页的中央情报局委员拘留及审讯计划报告,这份报告是于2014 年12月9号由美国参议院情报委员会公开发表。

这份图表是使用Wordle 制作的,Wordle 是一个由Jonathon Feinberg发表的文字云制作程式且可以从网站上免费取得。我们可以利用英文里的剔除字(stop word) 来移除低资讯价值的字像”的”跟”了”。制作的图表留下最常出现的字词,读者可以简单地从字词出现的频率得到结论。

作者介绍

Kailash Purang

Kailash 是在Teradata新加坡资料科学家领导人。他也在整个东南亚工作,大部分在印尼支援及领导Teradata在银行及通讯产业客户的服务。

Kailash 有新加坡国立大学经济硕士经济跟统计学学士、新加坡国立大学经济硕士、伦敦大学管理学学士。他在分析领域有长达15年跟产业的经验。

尽管是”出卖灵魂” 投身商业领域,他仍然认为所有这一切的学习和技术的目的是为了让人们的生活更轻松更有趣。为了引进一个有趣的无痛的分析方式,他在业余时间作资料视觉化让每个人都可以从简单的分析应用过程中获益。

作为Teradata资料科学家,他努力使自己的客户实现大数据的全部潜力,使他们的客户可以通过更好的服务和产品受益。

——————

未完待续,明天我们将连载全球最牛的28个大数据可视化应用案例(二)

End.

android uses-permission

<!– 访问网络 –>
<uses-permission android:name=”android.permission.INTERNET”/>
<!– 写外部存储 –>
<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE”/>
<!– 进行网络定位 –>
<uses-permission android:name=”android.permission.ACCESS_COARSE_LOCATION”/>
<!– 访问GPS定位–>
<uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION”/> <uses-permission android:name=”android.permission.ACCESS_MOCK_LOCATION”/>
<!– 获取运营商信息,用于支持提供运营商信息相关的接口–>
<uses-permission android:name=”android.permission.ACCESS_NETWORK_STATE”/>
<!– 访问wifi网络信息,wifi信息可用于进行网络定位–>
<uses-permission android:name=”android.permission.ACCESS_WIFI_STATE”/>
<!– 获取wifi的获取权限,wifi信息可用来进行网络定位–>
<uses-permission android:name=”android.permission.CHANGE_WIFI_STATE”/>
<!– 唤醒CPU –>
<uses-permission android:name=”android.permission.WAKE_LOCK”/>
<!– 控制振动器–>
<uses-permission android:name=”android.permission.VIBRATE”/>
<!– 使用摄像头–>
<uses-permission android:name=”android.permission.CAMERA”/>
<!– 直接拨打电话–>
<uses-permission android:name=”android.permission.CALL_PHONE”/>
<!– 直接发送短信–>
<uses-permission android:name=”android.permission.SEND_SMS”/>
<!– 读取手机当前的状态–>
<uses-permission android:name=”android.permission.READ_PHONE_STATE”/>
<!– 读取手机通讯录–>
<uses-permission android:name=”android.permission.READ_CONTACTS”/>
<!– 写入手机通讯录–>
<uses-permission android:name=”android.permission.WRITE_CONTACTS”/>
<!– 录音–>
<uses-permission android:name=”android.permission.RECORD_AUDIO”/>
<!– 闪光灯–>
<uses-permission android:name=”android.permission.FLASHLIGHT”/>
<!– 读取低级别的系统日志文件–>
<uses-permission android:name=”android.permission.READ_LOGS”/>
<!– 开机启动–>
<uses-permission android:name=”android.permission.RECEIVE_BOOT_COMPLETED”/>
<!– 蓝牙账户–>
<uses-permission android:name=”android.permission.BLUETOOTH_ADMIN”/>
<!– 蓝牙–>
<uses-permission android:name=”android.permission.BLUETOOTH”/>
<!– 手机必要要有照相机 且能自动对焦–>
<uses-feature android:name=”android.hardware.camera”/> <uses-feature android:name=”android.hardware.camera.autofocus” android:required=”false”/> <uses-permission android:name=”android.permission.DOWNLOAD_WITHOUT_NOTIFICATION”/>

优秀程序员眼中的整洁代码

有多少程序员,就有多少定义。所以我只询问了一些非常知名且经验丰富的程序员。
Bjarne Stroustrup,C++语言发明者,C++ Programming Language(中译版《C++程序设计语言》)一书作者。

我喜欢优雅和高效的代码。代码逻辑应当直截了当,叫缺陷难以隐藏;尽量减少依赖关系,使之便于维护;依据某种分层战略完善错误处理代码;性能调至最优,省得引诱别人做没规矩的优化,搞出一堆混乱来。整洁的代码只做好一件事。

Bjarne 用了“优雅”一词。说得好!我 MacBook 上的词典提供了如下定义:外表或举止上令人愉悦的优美和雅观;令人愉悦的精致和简单。注意对“愉悦”一词的强调。Bjarne 显然认为整洁的代码读起来令人愉悦。读这种代码,就像见到手工精美的音乐盒或者设计精良的汽车一般,让你会心一笑。

Bjarne 也提到效率——而且两次提及。这话出自 C++ 发明者之口,或许并不出奇;不过我认为并非是在单纯追求速度。被浪费掉的运算周期并不雅观,并不令人愉悦。留意 Bjarne 怎么描述那种不雅观的结果。他用了“引诱”这个词。诚哉斯言。糟糕的代码引发混乱!别人修改糟糕的代码时,往往会越改越烂。

务实的 Dave Thomas 和 Andy Hunt 从另一角度阐述了这种情况。他们提到破窗理论4。窗户破损了的建筑让人觉得似乎无人照管。于是别人也再不关心。他们放任窗户继续破损。最终自己也参加破坏活动,在外墙上涂鸦,任垃圾堆积。一扇破损的窗户开辟了大厦走向倾颓的道路。

Bjarne 也提到完善错误处理代码。往深处说就是在细节上花心思。敷衍了事的错误处理代码只是程序员忽视细节的一种表现。此外还有内存泄漏,还有竞态条件代码。还有前后不一致的命名方式。结果就是凸现出整洁代码对细节的重视。

Bjarne 以“整洁的代码只做好一件事”结束论断。毋庸置疑,软件设计的许多原则最终都会归结为这句警语。有那么多人发表过类似的言论。糟糕的代码想做太多事,它意图混乱、目的含混。整洁的代码力求集中。每个函数、每个类和每个模块都全神贯注于一事,完全不受四周细节的干扰和污染。

Grady Booch,Object Oriented Analysis and Design with Applications(中译版《面向对象分析与设计》)一书作者。

整洁的代码简单直接。整洁的代码如同优美的散文。整洁的代码从不隐藏设计者的意图,充满了干净利落的抽象和直截了当的控制语句。

Grady 的观点与 Bjarne 的观点有类似之处,但他从可读性的角度来定义。我特别喜欢“整洁的代码如同优美的散文”这种看法。想想你读过的某本好书。回忆一下,那些文字是如何在脑中形成影像!就像是看了场电影,对吧?还不止!你还看到那些人物,听到那些声音,体验到那些喜怒哀乐。

阅读整洁的代码和阅读 Lord of the Rings(中译版《指环王》)自然不同。不过,仍有可类比之处。如同一本好的小说般,整洁的代码应当明确地展现出要解决问题的张力。它应当将这种张力推至高潮,以某种显而易见的方案解决问题和张力,使读者发出“啊哈!本当如此!”的感叹。

窃以为 Grady 所谓“干净利落的抽象”(crisp abstraction),乃是绝妙的矛盾修辞法。毕竟 crisp 几乎就是“具体”(concrete)的同义词。我 MacBook 上的词典这样定义 crisp 一词:果断决绝,就事论事,没有犹豫或不必要的细节。尽管有两种不同的定义,该词还是承载了有力的信息。代码应当讲述事实,不引人猜测。它只该包含必需之物。读者应当感受到我们的果断决绝。

“老大”Dave Thomas,OTI 公司创始人,Eclipse 战略教父。

整洁的代码应可由作者之外的开发者阅读和增补。它应当有单元测试和验收测试。它使用有意义的命名。它只提供一种而非多种做一件事的途径。它只有尽量少的依赖关系,而且要明确地定义和提供清晰、尽量少的 API。代码应通过其字面表达含义,因为不同的语言导致并非所有必需信息均可通过代码自身清晰表达。

Dave 老大在可读性上和 Grady 持相同观点,但有一个重要的不同之处。Dave 断言,整洁的代码便于其他人加以增补。这看似显而易见,但亦不可过分强调。毕竟易读的代码和易修改的代码之间还是有区别的。

Dave 将整洁系于测试之上!要在十年之前,这会让人大跌眼镜。但测试驱动开发(Test Driven Development)已在行业中造成了深远影响,成为基础规程之一。Dave 说得对。没有测试的代码不干净。不管它有多优雅,不管有多可读、多易理解,微乎测试,其不洁亦可知也。

Dave 两次提及“尽量少”。显然,他推崇小块的代码。实际上,从有软件起人们就在反复强调这一点。越小越好。

Dave 也提到,代码应在字面上表达其含义。这一观点源自 Knuth 的“字面编程”(literate programming)5。结论就是应当用人类可读的方式来写代码。

Michael Feathers,Working Effectively with Legacy Code(中译版《修改代码的艺术》)一书作者。

我可以列出我留意到的整洁代码的所有特点,但其中有一条是根本性的。整洁的代码总是看起来像是某位特别在意它的人写的。几乎没有改进的余地。代码作者什么都想到了,如果你企图改进它,总会回到原点,赞叹某人留给你的代码——全心投入的某人留下的代码。

一言以蔽之:在意。这就是本书的题旨所在。或许该加个副标题,如何在意代码

Michael 一针见血。整洁代码就是作者着力照料的代码。有人曾花时间让它保持简单有序。他们适当地关注到了细节。他们在意过。

Ron Jeffries,Extreme Programming Installed(中译版《极限编程实施》)以及 Extreme Programming Adventures in C#(中译版《C#极限编程探险》)作者。

Ron 初入行就在战略空军司令部(Strategic Air Command)编写 Fortran 程序,此后几乎在每种机器上编写过每种语言的代码。他的言论值得咀嚼。

近年来,我开始研究贝克的简单代码规则,差不多也都琢磨透了。简单代码,依其重要顺序:

能通过所有测试;

没有重复代码;

体现系统中的全部设计理念;

包括尽量少的实体,比如类、方法、函数等。

在以上诸项中,我最在意代码重复。如果同一段代码反复出现,就表示某种想法未在代码中得到良好的体现。我尽力去找出到底那是什么,然后再尽力更清晰地表达出来。

在我看来,有意义的命名是体现表达力的一种方式,我往往会修改好几次才会定下名字来。借助 Eclipse 这样的现代编码工具,重命名代价极低,所以我无所顾忌。然而,表达力还不只体现在命名上。我也会检查对象或方法是否想做的事太多。如果对象功能太多,最好是切分为两个或多个对象。如果方法功能太多,我总是使用抽取手段(Extract Method)重构之,从而得到一个能较为清晰地说明自身功能的方法,以及另外数个说明如何实现这些功能的方法。

消除重复和提高表达力让我在整洁代码方面获益良多,只要铭记这两点,改进脏代码时就会大有不同。不过,我时常关注的另一规则就不太好解释了。

这么多年下来,我发现所有程序都由极为相似的元素构成。例如“在集合中查找某物”。不管是雇员记录数据库还是名-值对哈希表,或者某类条目的数组,我们都会发现自己想要从集合中找到某一特定条目。一旦出现这种情况,我通常会把实现手段封装到更抽象的方法或类中。这样做好处多多。

可以先用某种简单的手段,比如哈希表来实现这一功能,由于对搜索功能的引用指向了我那个小小的抽象,就能随需应变,修改实现手段。这样就既能快速前进,又能为未来的修改预留余地。

另外,该集合抽象常常提醒我留意“真正”在发生的事,避免随意实现集合行为,因为我真正需要的不过是某种简单的查找手段。

减少重复代码,提高表达力,提早构建简单抽象。这就是我写整洁代码的方法。

Ron 以寥寥数段文字概括了本书的全部内容。不要重复代码,只做一件事,表达力,小规模抽象。该有的都有了。

Ward Cunningham,Wiki 发明者,eXtreme Programming(极限编程)的创始人之一,Smalltalk 语言和面向对象的思想领袖。所有在意代码者的教父。

如果每个例程都让你感到深合己意,那就是整洁代码。如果代码让编程语言看起来像是专为解决那个问题而存在,就可以称之为漂亮的代码。

这种说法很 Ward。它教你听了之后就点头,然后继续听下去。如此在理,如此浅显,绝不故作高深。你大概以为此言深合己意吧。再走近点看看。

“……深合己意”。你最近一次看到深合己意的模块是什么时候?模块多半都繁复难解吧?难道没有触犯规则吗?你不是也曾挣扎着想抓住些从整个系统中散落而出的线索,编织进你在读的那个模块吗?你最近一次读到某段代码、并且如同对 Ward 的说法点头一般对这段代码点头,是什么时候的事了?

Ward 期望你不会为整洁代码所震惊。你无需花太多力气。那代码就是深合你意。它明确、简单、有力。每个模块都为下一个模块做好准备。每个模块都告诉你下一个模块会是怎样的。整洁的程序好到你根本不会注意到它。设计者把它做得像一切其他设计般简单。

那 Ward 有关“美”的说法又如何呢?我们都曾面临语言不是为要解决的问题所设计的困境。但 Ward 的说法又把球踢回我们这边。他说,漂亮的代码让编程语言像是专为解决那个问题而存在!所以,让语言变得简单的责任就在我们身上了!当心,语言是冥顽不化的!是程序员让语言显得简单。

 

摘自:http://begeek.cn/post/7210.html?_biz=MjM5OTA1MDUyMA==&mid=407358558&idx=2&sn=b21877f23bf4063fa311185009c1f0b7&scene=0#wechat_redirect1468885896550

程序员必须知道的10大基础实用算法及其讲解

算法一:快速排序算法

快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。

快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。

算法步骤:

1 从数列中挑出一个元素,称为 “基准”(pivot),

2 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。

3 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。

Sorting_quicksort_anim

详细介绍:快速排序

算法二:堆排序算法

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

堆排序的平均时间复杂度为Ο(nlogn) 。

算法步骤:

  1. 创建一个堆H[0..n-1]
  2. 把堆首(最大值)和堆尾互换

3. 把堆的尺寸缩小1,并调用shift_down(0),目的是把新的数组顶端数据调整到相应位置

4. 重复步骤2,直到堆的尺寸为1

Sorting_heapsort_anim

详细介绍:堆排序

算法三:归并排序

归并排序(Merge sort,台湾译作:合并排序)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

算法步骤:

1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置

3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

4. 重复步骤3直到某一指针达到序列尾

5. 将另一序列剩下的所有元素直接复制到合并序列尾

Merge_sort_animation2

详细介绍:归并排序

算法四:二分查找算法

二分查找算法是一种在有序数组中查找某一特定元素的搜索算法。搜素过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜素过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。折半搜索每次把搜索区域减少一半,时间复杂度为Ο(logn) 。

详细介绍:二分查找算法

算法五:BFPRT(线性查找算法)

BFPRT算法解决的问题十分经典,即从某n个元素的序列中选出第k大(第k小)的元素,通过巧妙的分析,BFPRT可以保证在最坏情况下仍为线性时间复杂度。该算法的思想与快速排序思想相似,当然,为使得算法在最坏情况下,依然能达到o(n)的时间复杂度,五位算法作者做了精妙的处理。

算法步骤:

1. 将n个元素每5个一组,分成n/5(上界)组。

2. 取出每一组的中位数,任意排序方法,比如插入排序。

3. 递归的调用selection算法查找上一步中所有中位数的中位数,设为x,偶数个中位数的情况下设定为选取中间小的一个。

4. 用x来分割数组,设小于等于x的个数为k,大于x的个数即为n-k。

5. 若i==k,返回x;若i<k,在小于x的元素中递归查找第i小的元素;若i>k,在大于x的元素中递归查找第i-k小的元素。

终止条件:n=1时,返回的即是i小元素。

详细介绍:

寻找最小(最大)的k个数

线性查找相关算法

算法六:DFS(深度优先搜索)

深度优先搜索算法(Depth-First-Search),是搜索算法的一种。它沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。DFS属于盲目搜索。

深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多相关的图论问题,如最大路径问题等等。一般用堆数据结构来辅助实现DFS算法。

深度优先遍历图算法步骤:

1. 访问顶点v;

2. 依次从v的未被访问的邻接点出发,对图进行深度优先遍历;直至图中和v有路径相通的顶点都被访问;

3. 若此时图中尚有顶点未被访问,则从一个未被访问的顶点出发,重新进行深度优先遍历,直到图中所有顶点均被访问过为止。

上述描述可能比较抽象,举个实例:

DFS 在访问图中某一起始顶点 v 后,由 v 出发,访问它的任一邻接顶点 w1;再从 w1 出发,访问与 w1邻 接但还没有访问过的顶点 w2;然后再从 w2 出发,进行类似的访问,… 如此进行下去,直至到达所有的邻接顶点都被访问过的顶点 u 为止。

接着,退回一步,退到前一次刚访问过的顶点,看是否还有其它没有被访问的邻接顶点。如果有,则访问此顶点,之后再从此顶点出发,进行与前述类似的访问;如果没有,就再退回一步进行搜索。重复上述过程,直到连通图中所有顶点都被访问过为止。

详细介绍:深度优先搜索

 

算法七:BFS(广度优先搜索)

广度优先搜索算法(Breadth-First-Search),是一种图形搜索算法。简单的说,BFS是从根节点开始,沿着树(图)的宽度遍历树(图)的节点。如果所有节点均被访问,则算法中止。BFS同样属于盲目搜索。一般用队列数据结构来辅助实现BFS算法。

算法步骤:

1. 首先将根节点放入队列中。

2. 从队列中取出第一个节点,并检验它是否为目标。

  • 如果找到目标,则结束搜寻并回传结果。
  • 否则将它所有尚未检验过的直接子节点加入队列中。

3. 若队列为空,表示整张图都检查过了——亦即图中没有欲搜寻的目标。结束搜寻并回传“找不到目标”。

4. 重复步骤2。

Animated_BFS

详细介绍:广度优先搜索

算法八:Dijkstra算法

戴克斯特拉算法(Dijkstra’s algorithm)是由荷兰计算机科学家艾兹赫尔·戴克斯特拉提出。迪科斯彻算法使用了广度优先搜索解决非负权有向图的单源最短路径问题,算法最终得到一个最短路径树。该算法常用于路由算法或者作为其他图算法的一个子模块。

该算法的输入包含了一个有权重的有向图 G,以及G中的一个来源顶点 S。我们以 V 表示 G 中所有顶点的集合。每一个图中的边,都是两个顶点所形成的有序元素对。(uv) 表示从顶点 u 到 v 有路径相连。我们以 E 表示G中所有边的集合,而边的权重则由权重函数 wE → [0, ∞] 定义。因此,w(uv) 就是从顶点 u 到顶点 v 的非负权重(weight)。边的权重可以想像成两个顶点之间的距离。任两点间路径的权重,就是该路径上所有边的权重总和。已知有 V 中有顶点 s 及 t,Dijkstra 算法可以找到 s 到 t的最低权重路径(例如,最短路径)。这个算法也可以在一个图中,找到从一个顶点 s 到任何其他顶点的最短路径。对于不含负权的有向图,Dijkstra算法是目前已知的最快的单源最短路径算法。

算法步骤:

1. 初始时令 S={V0},T={其余顶点},T中顶点对应的距离值

若存在<V0,Vi>,d(V0,Vi)为<V0,Vi>弧上的权值

若不存在<V0,Vi>,d(V0,Vi)为∞

2. 从T中选取一个其距离值为最小的顶点W且不在S中,加入S

3. 对其余T中顶点的距离值进行修改:若加进W作中间顶点,从V0到Vi的距离值缩短,则修改此距离值

重复上述步骤2、3,直到S中包含所有顶点,即W=Vi为止

Dijkstra_Animation

详细:Dijkstra算法

算法九:动态规划算法

动态规划(Dynamic programming)是一种在数学、计算机科学和经济学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。 动态规划常常适用于有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。

动态规划背后的基本思想非常简单。大致上,若要解一个给定问题,我们需要解其不同部分(即子问题),再合并子问题的解以得出原问题的解。 通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量: 一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表。 这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用。

关于动态规划最经典的问题当属背包问题。

算法步骤:

1. 最优子结构性质。如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质(即满足最优化原理)。最优子结构性质为动态规划算法解决问题提供了重要线索。

2. 子问题重叠性质。子问题重叠性质是指在用递归算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格中,当再次需要计算已经计算过的子问题时,只是在表格中简单地查看一下结果,从而获得较高的效率。

详细参考:

从全球导航到输入法:谈谈动态规划

动态规划

算法十:朴素贝叶斯分类算法

朴素贝叶斯分类算法是一种基于贝叶斯定理的简单概率分类算法。贝叶斯分类的基础是概率推理,就是在各种条件的存在不确定,仅知其出现概率的情况下,如何完成推理和决策任务。概率推理是与确定性推理相对应的。而朴素贝叶斯分类器是基于独立假设的,即假设样本每个特征与其他特征都不相关。

朴素贝叶斯分类器依靠精确的自然概率模型,在有监督学习的样本集中能获取得非常好的分类效果。在许多实际应用中,朴素贝叶斯模型参数估计使用最大似然估计方法,换言之朴素贝叶斯模型能工作并没有用到贝叶斯概率或者任何贝叶斯模型。

尽管是带着这些朴素思想和过于简单化的假设,但朴素贝叶斯分类器在很多复杂的现实情形中仍能够取得相当好的效果。

详细参考:

贝叶斯网络

朴素贝叶斯分类算法

本文链接:程序员必须知道的10大基础实用算法及其讲解

出处:快课

转载请保留出处链接,谢谢!

摘自:http://www.cricode.com/2001.html

 

Vysor – 无需 root,用 Chrome 完全控制 Android 设备

Vysor是一款 Chrome 应用,能够在 Chrome 里通过 USB 直接控制 Android 设备,无需 root。@Appinn

Vysor 的设置非常简单,只需要在 Chrome 里安装 Vysor,打开 Android 设备的 USB 调试模式,用 USB 线连接电脑与 Android 设备,就可以控制了。

在 Chrome 里,你能实时看到 Android 的界面,并且可以通过鼠标拖动、点击屏幕,还有其他快捷键:

  • ESC 返回按钮
  • F1 菜单按钮
  • Home 返回桌面
  • 鼠标右键 返回按钮
  • 鼠标中建桌面

第一次连接 Vysor,会自动在 Android 设备中安装一个应用,然后点击信任连接的电脑,就能在 Chrome 操作了,非常简单。

而在连接成功后,你完全可以将 Android 设备放到一边,Vysor 支持点亮屏幕(只需在黑屏上点一下鼠标右键),滑动输入密码,键盘打字,如果再配合PushBullet 将系统通知推送到 Chrome 里,真的 Android 与 电脑合一了…

鉴于需要安装 Chrome 应用,推荐个工具访问 Chrome 网上应用店。

青小蛙使用体验,Chrome 端的显示比较顺滑,处于完全可以接受的状态,两端几乎实时同步,没有延时。