:::: MENU ::::

TalkingData's Blog

现在开始,用数据说话。

Posts Categorized / Data

cialis erfaring cialis i norge hva er kamagra cialis efeitos secundarios cialis bula viagra effekt viagra norge viagra på nett viagra nettbutikk viagra infarmed levitra comprimidos cialis uten resept cialis pris levitra eller cialis kamagra gel comprar viagra farmacia
  • Mar 20 / 2018
  • 0
Data, Ideas, Tech

技术专栏 | 微服务架构初探

作者:TalkingData 徐蓓

本译文禁止商用,转载请注明来源!

什么是微服务 

首先微服务并没有一个官方的定义,想要直接描述微服务比较困难,我们可以通过对比传统Web应用,来理解什么是微服务。

传统的Web应用核心分为业务逻辑、适配器以及API或通过UI访问的Web界面。业务逻辑定义业务流程、业务规则以及领域实体。适配器包括数据库访问组件、消息组件以及访问接口等。

一个打车软件的架构图如下:

尽管也是遵循模块化开发,但最终它们会打包并部署为单体式应用。例如Java应用程序会被打包成WAR,部署在Tomcat或者Jetty上。

这种单体应用比较适合于小项目,优点是:

  • 开发简单直接,集中式管理
  • 基本不会重复开发
  • 功能都在本地,没有分布式的管理开销和调用开销

当然它的缺点也十分明显,特别对于互联网公司来说:

  • 开发效率低:所有的开发在一个项目改代码,递交代码相互等待,代码冲突不断
  • 代码维护难:代码功能耦合在一起,新人不知道何从下手
  • 部署不灵活:构建时间长,任何小修改必须重新构建整个项目,这个过程往往很长
  • 稳定性不高:一个微不足道的小问题,可以导致整个应用挂掉
  • 扩展性不够:无法满足高并发情况下的业务需求

所以,现在主流的设计一般会采用微服务架构。其思路不是开发一个巨大的单体式应用,而是将应用分解为小的、互相连接的微服务。一个微服务完成某个特定功能,比如乘客管理和下单管理等。每个微服务都有自己的业务逻辑和适配器。一些微服务还会提供API接口给其他微服务和应用客户端使用。

比如,前面描述的系统可被分解为:

每个业务逻辑都被分解为一个微服务,微服务之间通过REST API通信。一些微服务也会向终端用户或客户端开发API接口。但通常情况下,这些客户端并不能直接访问后台微服务,而是通过API Gateway来传递请求。API Gateway一般负责服务路由、负载均衡、缓存、访问控制和鉴权等任务。

微服务架构的优点 

微服务架构有很多重要的优点。

首先,它解决了复杂性问题。它将单体应用分解为一组服务。虽然功能总量不变,但应用程序已被分解为可管理的模块或服务。这些服务定义了明确的RPC或消息驱动的API边界。微服务架构强化了应用模块化的水平,而这通过单体代码库很难实现。因此,微服务开发的速度要快很多,更容易理解和维护。

其次,这种体系结构使得每个服务都可以由专注于此服务的团队独立开发。只要符合服务API契约,开发人员可以自由选择开发技术。这就意味着开发人员可以采用新技术编写或重构服务,由于服务相对较小,所以这并不会对整体应用造成太大影响。

第三,微服务架构可以使每个微服务独立部署。开发人员无需协调对服务升级或更改的部署。这些更改可以在测试通过后立即部署。所以微服务架构也使得CI/CD成为可能。

最后,微服务架构使得每个服务都可独立扩展。我们只需定义满足服务部署要求的配置、容量、实例数量等约束条件即可。比如我们可以在EC2计算优化实例上部署CPU密集型服务,在EC2内存优化实例上部署内存数据库服务。

微服务架构的缺点和挑战 

实际上并不存在silver bullets,微服务架构也会给我们带来新的问题和挑战。其中一个就和它的名字类似,微服务强调了服务大小,但实际上这并没有一个统一的标准。业务逻辑应该按照什么规则划分为微服务,这本身就是一个经验工程。有些开发者主张10-100行代码就应该建立一个微服务。虽然建立小型服务是微服务架构崇尚的,但要记住,微服务是达到目的的手段,而不是目标。微服务的目标是充分分解应用程序,以促进敏捷开发和持续集成部署。

微服务的另一个主要缺点是微服务的分布式特点带来的复杂性。开发人员需要基于RPC或者消息实现微服务之间的调用和通信,而这就使得服务之间的发现、服务调用链的跟踪和质量问题变得的相当棘手。

微服务的另一个挑战是分区的数据库体系和分布式事务。更新多个业务实体的业务交易相当普遍。这些类型的事务在单体应用中实现非常简单,因为单体应用往往只存在一个数据库。但在微服务架构下,不同服务可能拥有不同的数据库。CAP原理的约束,使得我们不得不放弃传统的强一致性,而转而追求最终一致性,这个对开发人员来说是一个挑战。

微服务架构对测试也带来了很大的挑战。传统的单体WEB应用只需测试单一的REST API即可,而对微服务进行测试,需要启动它依赖的所有其他服务。这种复杂性不可低估。

微服务的另一大挑战是跨多个服务的更改。比如在传统单体应用中,若有A、B、C三个服务需要更改,A依赖B,B依赖C。我们只需更改相应的模块,然后一次性部署即可。但是在微服务架构中,我们需要仔细规划和协调每个服务的变更部署。我们需要先更新C,然后更新B,最后更新A。

部署基于微服务的应用也要复杂得多。单体应用可以简单的部署在一组相同的服务器上,然后前端使用负载均衡即可。每个应用都有相同的基础服务地址,例如数据库和消息队列。而微服务由不同的大量服务构成。每种服务可能拥有自己的配置、应用实例数量以及基础服务地址。这里就需要不同的配置、部署、扩展和监控组件。此外,我们还需要服务发现机制,以便服务可以发现与其通信的其他服务的地址。因此,成功部署微服务应用需要开发人员有更好地部署策略和高度自动化的水平。

以上问题和挑战可大体概括为:

  • API Gateway
  • 服务间调用
  • 服务发现
  • 服务容错
  • 服务部署
  • 数据调用

幸运的是,出现了很多微服务框架,可以解决以上问题。

第一代微服务框架 

Spring Cloud

Spring Cloud为开发者提供了快速构建分布式系统的通用模型的工具(包括配置管理、服务发现、熔断器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话、集群状态等)。

主要项目包括:

  • spring cloud config:由git存储库支持的集中式外部配置管理。配置资源直接映射到Spring Environment,但是如果需要可以被非Spring应用程序使用。
  • spring cloud netflix:与各种Netflix OSS组件(Eureka,Hystrix,Zuul,Archaius等)集成。
  • spring cloud bus:用于将服务和服务实例与分布式消息传递联系起来的事件总线。用于在集群中传播状态更改(例如配置更改事件)
  • spring cloud for cloud foundry:将您的应用程序与Pivotal Cloudfoundry集成。提供服务发现实现,还可以轻松实现通过SSO和OAuth2保护资源,还可以创建Cloudfoundry服务代理。
  • spring cloud cloud foundry service broker:提供构建管理一个Cloud Foundry中服务的服务代理的起点。
  • spring cloud cluster:领导选举和通用状态模型(基于zookeeper,redis,hazelcast,Consul的抽象和实现)
  • spring cloud consul:结合Hashicorp Consul的服务发现和配置管理
  • spring cloud security:在Zuul代理中为负载平衡的OAuth2休眠客户端和认证头中继提供支持。
  • spring cloud sleuth:适用于Spring Cloud应用程序的分布式跟踪,与Zipkin,HTrace和基于日志(例如ELK)跟踪兼容。
  • spring cloud data flow:针对现代运行时的可组合微服务应用程序的云本地编排服务。易于使用的DSL,拖放式GUI和REST-API一起简化了基于微服务的数据管道的整体编排。
  • spring cloud     stream:轻量级事件驱动的微服务框架,可快速构建可连接到外部系统的应用程序。使用Apache Kafka或RabbitMQ在Spring Boot应用程序之间发送和接收消息的简单声明式模型。
  • spring cloud stream app starters:Spring Cloud任务应用程序启动器是Spring Boot应用程序,可能是任何进程,包括不会永远运行的Spring Batch作业,并且它们在有限时间的数据处理之后结束/停止。
  • spring cloud zookeeper:Zookeeper的服务发现和配置管理
  • spring cloud for amazon web services:轻松集成托管的Amazon的Web Services服务。它通过使用spring的idioms和APIs便捷集成AWS服务,例如缓存或消息API。开发人员可以围绕托管服务,不必关心基础架构来构建应用。
  • spring cloud connectors:使PaaS应用程序在各种平台上轻松连接到后端服务,如数据库和消息代理(以前称为”Spring Cloud”的项目)
  • spring cloud starters:作为基于spring boot的启动项目,降低依赖管理(在Angel.SR2后,不在作为独立项目)
  • spring cloud cli:插件支持基于Groovy预言快速创建spring cloud的组件应用

Dubbo

Dubbo是一个阿里巴巴开源出来的一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。

其核心部分包含:

  • 远程通讯: 提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型,序列化,以及”请求-响应”模式的信息交换方式。
  • 集群容错: 提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持。
  • 自动发现: 基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。

但是显而易见,无论是Dubbo还是Spring Cloud都只适用于特定的应用场景和开发环境,它们的设计目的并不是为了支持通用性和多语言性。并且它们只是Dev层的框架,缺少DevOps的整体解决方案(这正是微服务架构需要关注的)。而随之而来的便是Service Mesh的兴起。

下一代微服务:Service Mesh? 

Service Mesh

Service Mesh又译作”服务网格”,作为服务间通信的基础设施层。如果用一句话来解释什么是Service Mesh,可以将它比作是应用程序或者说微服务间的TCP/IP,负责服务之间的网络调用、限流、熔断和监控。对于编写应用程序来说一般无须关心TCP/IP这一层(比如通过 HTTP 协议的 RESTful 应用),同样使用Service Mesh也就无须关系服务之间的那些原来是通过应用程序或者其他框架实现的事情,比如Spring Cloud、OSS,现在只要交给Service Mesh就可以了。

Service Mesh有如下几个特点:

  • 应用程序间通讯的中间层
  • 轻量级网络代理
  • 应用程序无感知
  • 解耦应用程序的重试/超时、监控、追踪和服务发现

Service Mesh的架构如下图所示:

Service Mesh作为Sidebar运行,对应用程序来说是透明,所有应用程序间的流量都会通过它,所以对应用程序流量的控制都可以在Service Mesh中实现。

目前流行的Service Mesh开源软件有Linkerd、Envoy和Istio,而最近Buoyant(开源Linkerd的公司)又发布了基于Kubernetes的Service Mesh开源项目Conduit。

Linkerd

Linkerd是开源网络代理,设计为以服务网格部署:用于管理,控制和监控应用程序内的服务与服务间通讯的专用层。

Linkerd旨在解决Twitter,Yahoo,Google和Microsoft等公司运营大型生产系统时发现的问题。根据经验,最复杂,令人惊奇和紧急行为的来源通常不是服务本身,而是服务之间的通讯。Linkerd解决了这些问题,不仅仅是控制通讯机制,而是在其上提供一个抽象层。

它的主要特性有:

  • 负载平衡:linkerd提供了多种负载均衡算法,它们使用实时性能指标来分配负载并减少整个应用程序的尾部延迟。
  • 熔断:linkerd包含自动熔断,将停止将流量发送到被认为不健康的实例,从而使他们有机会恢复并避免连锁反应故障。
  • 服务发现:linkerd 与各种服务发现后端集成,通过删除特定的(ad-hoc)服务发现实现来帮助您降低代码的复杂性。
  • 动态请求路由:linkerd 启用动态请求路由和重新路由,允许您使用最少量的配置来设置分段服务(staging service),金丝雀(canaries),蓝绿部署(blue-green deploy),跨DC故障切换和黑暗流量(dark traffic)。
  • 重试次数和截止日期:linkerd可以在某些故障时自动重试请求,并且可以在指定的时间段之后让请求超时。
  • TLS:linkerd 可以配置为使用 TLS 发送和接收请求,您可以使用它来加密跨主机边界的通信,而不用修改现有的应用程序代码。
  • HTTP代理集成:linkerd 可以作为 HTTP 代理,几乎所有现代 HTTP 客户端都广泛支持,使其易于集成到现有应用程序中。
  • 透明代理:您可以在主机上使用 iptables 规则,设置通过 linkerd 的透明代理
  • gRPC:linkerd 支持 HTTP/2 和 TLS,允许它路由 gRPC 请求,支持高级 RPC 机制,如双向流,流程控制和结构化数据负载。
  • 分布式跟踪:linkerd 支持分布式跟踪和度量仪器,可以提供跨越所有服务的统一的可观察性。
  • 仪器仪表: linkerd 支持分布式跟踪和度量仪器,可以提供跨越所有服务的统一的可观察性。

Envoy

Envoy 是一个面向服务架构的L7代理和通信总线而设计的,这个项目诞生是出于以下目标:

对于应用程序而言,网络应该是透明的,当发生网络和应用程序故障时,能够很容易定位出问题的根源。

Envoy可提供以下特性:

  • 外置进程架构:可与任何语言开发的应用一起工作;可快速升级
  • 基于新C++11编码:能够提供高效的性能
  • L3/L4过滤器:核心是一个L3/L4网络代理,能够作为一个可编程过滤器实现不同TCP代理任务,插入到主服务当中。通过编写过滤器来支持各种任务,如原始TCP代理、HTTP代理、TLS客户端证书身份验证等。
  • HTTP L7过滤器:支持一个额外的HTTP L7过滤层。HTTP过滤器作为一个插件,插入到HTTP链接管理子系统中,从而执行不同的任务,如缓冲,速率限制,路由/转发,嗅探Amazon的DynamoDB等等。
  • 支持HTTP/2:在HTTP模式下,支持HTTP/1.1、HTTP/2,并且支持HTTP/1.1、HTTP/2双向代理。这意味着HTTP/1.1和HTTP/2,在客户机和目标服务器的任何组合都可以桥接
  • HTTP L7路由:在HTTP模式下运行时,支持根据content type、runtime values等,基于path的路由和重定向。可用于服务的前端/边缘代理
  • 支持gRPC:gRPC是一个来自谷歌的RPC框架,使用HTTP/2作为底层的多路传输。HTTP/2承载的gRPC请求和应答,都可以使用Envoy的路由和LB能力
  • 支持MongoDB L7:支持获取统计和连接记录等信息
  • 支持DynamoDB L7:支持获取统计和连接等信息
  • 服务发现:支持多种服务发现方法,包括异步DNS解析和通过REST请求服务发现服务
  • 健康检查:含有一个健康检查子系统,可以对上游服务集群进行主动的健康检查。也支持被动健康检查。
  • 高级LB:包括自动重试、断路器,全局限速,阻隔请求,异常检测。未来还计划支持请求速率控制
  • 前端代理:可作为前端代理,包括TLS、HTTP/1.1、HTTP/2,以及HTTP L7路由
  • 极好的可观察性:对所有子系统,提供了可靠的统计能力。目前支持statsd以及兼容的统计库。还可以通过管理端口查看统计信息,还支持第三方的分布式跟踪机制
  • 动态配置:提供分层的动态配置API,用户可以使用这些API构建复杂的集中管理部署

Istio

Istio是一个用来连接、管理和保护微服务的开放平台。Istio提供一种简单的方式来建立已部署服务网络,具备负载均衡、服务间认证、监控等功能,而不需要改动任何服务代码。想要为服务增加对Istio的支持,您只需要在环境中部署一个特殊的边车(sidecar),使用Istio控制面板功能配置和管理代理,拦截微服务之间的所有网络通信。

Istio目前仅支持在Kubernetes上的服务部署,但未来版本中将支持其他环境。

Istio提供了一个完整的解决方案,通过为整个服务网格提供行为洞察和操作控制来满足微服务应用程序的多样化需求。它在服务网络中统一提供了许多关键功能:

  • 流量管理:控制服务之间的流量和API调用的流向,使得调用更可靠,并使网络在恶劣情况下更加健壮
  • 可观察性:了解服务之间的依赖关系,以及它们之间流量的本质和流向,从而提供快速识别问题的能力
  • 策略执行:将组织策略应用于服务之间的互动,确保访问策略得以执行,资源在消费者之间良好分配。策略的更改是通过配置网格而不是修改应用程序代码
  • 服务身份和安全:为网格中的服务提供可验证身份,并提供保护服务流量的能力,使其可以在不同可信度的网络上流转

Istio服务网格逻辑上分为数据面板和控制面板:

  • 数据面板由一组智能代理(Envoy)组成,代理部署为边车,调解和控制微服务之间所有的网络通信
  • 控制面板负责管理和配置代理来路由流量,以及在运行时执行策略

下图显示了构成每个面板的不同组件:

Conduit

Conduit是为Kubernetes设计的一个超轻型服务网格服务,它可透明地管理在Kubernetes上运行的服务的运行时通信,使得它们更安全可靠。Conduit提供了可见性、可靠性和安全性的功能,而无需更改代码。

Conduit service mesh也是由数据面板和控制面板组成。数据面板承载应用实际的网络流量。控制面板驱动数据面板,并对外提供北向接口。

对比

Linkerd和Envoy比较相似,都是一种面向服务通信的网络代理,均可实现诸如服务发现、请求路由、负载均衡等功能。它们的设计目标就是为了解决服务之间的通信问题,使得应用对服务通信无感知,这也是Service Mesh的核心理念。Linkerd和Envoy像是分布式的Sidebar,多个类似Linkerd和Envoy的proxy互相连接,就组成了service mesh。

而Istio则是站在了一个更高的角度,它将Service Mesh分为了Data Plane和Control Plane。Data Plane负责微服务间的所有网络通信,而Control Plane负责管理Data Plane Proxy:

并且Istio天生的支持Kubernetes,这也弥合了应用调度框架与Service Mesh之间的空隙。

关于Conduit的资料较少,从官方介绍看它的定位和功能与Istio类似。

Kubernetes + Service Mesh 

= 完整的微服务框架 

Kubernets已经成为了容器调度编排的事实标准,而容器正好可以作为微服务的最小工作单元,从而发挥微服务架构的最大优势。所以我认为未来微服务架构会围绕Kubernetes展开。

而Istio和Conduit这类Service Mesh天生就是为了Kubernetes设计,它们的出现补足了Kubernetes在微服务间服务通讯上的短板。虽然Dubbo、Spring Cloud等都是成熟的微服务框架,但是它们或多或少都会和具体语言或应用场景绑定,并只解决了微服务Dev层面的问题。若想解决Ops问题,它们还需和诸如Cloud Foundry、Mesos、Docker Swarm或Kubernetes这类资源调度框架做结合:

但是这种结合又由于初始设计和生态,有很多适用性问题需要解决。

Kubernetes则不同,它本身就是一个和开发语言无关的、通用的容器管理平台,它可以支持运行云原生和传统的容器化应用。并且它覆盖了微服务的Dev和Ops阶段,结合Service Mesh,它可以为用户提供完整端到端的微服务体验。

所以我认为,未来的微服务架构和技术栈可能是如下形式

多云平台为微服务提供了资源能力(计算、存储和网络等),容器作为最小工作单元被Kubernetes调度和编排,Service Mesh管理微服务的服务通信,最后通过API Gateway向外暴露微服务的业务接口。

我相信未来随着以Kubernetes和Service Mesh为标准的微服务框架的盛行,将大大降低微服务实施的成本,最终为微服务落地以及大规模使用提供坚实的基础和保障。

参考资料:

  • Introduction to Microservices:https://www.nginx.com/blog/introduction-to-microservices
  • Pattern: Microservice Architecture:http://microservices.io/patterns/microservices.html
  • Spring Cloud for Microservices Compared to Kubernetes:https://developers.redhat.com/blog/2016/12/09/spring-cloud-for-microservices-compared-to-kubernetes
  • Istio:https://istio.io
  • Envoy:https://www.envoyproxy.io
  • Linkerd:https://linkerd.io
  • 微服务(Microservice)那点事:https://yq.aliyun.com/articles/2764?spm=a2c4e.11153959.blogcont8611.3.7ea85f19HP1APU
  • Istio中文文档:http://istio.doczh.cn
  • Linkerd中文文档:http://linkerd.doczh.cn
  • Mar 19 / 2018
  • 0
Data, Tech

两个工具帮你实现酷炫的数据可视化

你想到的数据可视化

通常可能是这样的

但我们能实现的数据可视化

还可以是这样的

这样的

以及这样的

如此高端大气酷炫的数据可视化

是如何实现的?

秘诀在于两个工具

inMap & iView

inMap

inMap是TalkingData可视化团队开源的一款基于 Canvas 的大数据可视化库,专注于大数据方向的散点、热力图、网格、聚合等方式展示,致力于让大数据可视化变得简单易用。

它具有以下特性:

  • 高性能
  • 多线程
  • 多图层叠加
  • 友好的 AP
  • 可以自定义主题

inMap 采用更加智能的地理可视化框架,主要面向从事数据可视化应用相关的工程师和设计师。

底层绘图引擎:目前基于 canvas 2d 提供基础绘图能力,基于 WebGL 的版本正在规划中;

算法:内置了经纬度墨卡托转换、文字避让算法、最佳标记点算法、自动分组标记配色算法等。

inMap 的每个算法都是为了增强用户体验,追求极致效果,打造伟大的产品。

inMap 的接口设计非常友好,希望让开发者通过简单的配置,就能快速构建出优美的可视化效果。

官网:http://inmap.talkingdata.com

GitHub:https://github.com/TalkingData/inmap

iView

iView 是TalkingData可视化团队开源的一套基于 Vue.js 的 UI 组件库,主要服务于 PC 界面的中后台产品。

它具有以下特性:

  • 高质量、功能丰富
  • 友好的 API ,自由灵活地使用空间,面向任何技术水平的开发者
  • 细致、漂亮的 UI
  • 事无巨细的文档
  • 可自定义主题

同时 iView 也是一整套的前端解决方案,包括了设计规范、多语言(目前 iView 支持 15 国语言)、自定义主题、服务端渲染。

iView 支持 Vue.js 2.x、Vue.js 1.x、服务端渲染、Nuxt.js、Electron等。

iView 目前在 GitHub 上有 13,000 多 star,从 star 数量、口碑和功能性、UI / UE上,iView 都排在全球同类产品的 Top3。

官网:https://www.iviewui.com

GitHub:https://github.com/iView/iView

 iView 新版本发布

在过去的两个多月里,iView 陆续发布了 2.9.0 和 2.10.0 两个重要版本。这两个版本总共有 255 个 commit,超过 40 项更新。来看一下,iView 具体有哪些更新:

一、日期组件 DatePicker 的重构

首先是在 2.10.0 对日期组件 DatePicker 的重构。DatePicker 是 iView 48 个组件里最复杂的组件之一。复杂的功能使得代码逻辑非常重,在许多新特性的支持上,比如兼容不同国家的日历规范等都很难在此基础上迭代,不得不推倒重来。

SergioCrisostomo 之前有开发过日期相关的 JS 库(https://github.com/SergioCrisostomo/js-calendar),所以对日期相关的功能点和 API 非常熟,iView 也是基于此库进行的重构。

新的日期组件主要增加了以下功能:

1. 范围选择支持从右往左选择。

之前在范围选择时,必须先选起点,再选终点,也就是从左往右选,但很多用户的习惯却刚好相反。该版本则同时支持两个方向的选择。

2. 新增 split-panels 属性,开启后,左右两面板可以不联动。

之前在范围选择时,左右两个面板是联动的,也就是右边永远比左边大一个月,任何一个面板切换月份或年份,另一个面板都会自动切换。该版本则可以设置为不联动,这样方便定位起始月份和结束月份。如图所示:

3. 新增 multiple 属性,开启后,可以选择多个日期。

虽然之前版本可以用其它 iView 组件组合出来一个多选的日期,但效果和交互多少会打折扣,该版本只要增加属性 multiple,就可以在一个日期面板上同时选择和呈现多个日期了。如图所示:

4. 新增属性 show-week-numbers,开启后,可以显示星期数。

增加这个属性,就可以在日历面板上显示当前是一年的第几周。如图所示:

还有其它很多项的更新,比如新增 start-date 属性,可以设置面板展开时默认显示的日期。新增属性 time-picker-options,可以在 type 为 datetime 和 datetimerange 下,配置 TimePicker 的属性,比如时间间隔 steps。完整的更新可以产看更新日志,这里不一一列举了。

二、键盘可访问性的支持

键盘的可访问性,主要是通过键盘的方向键、tab键、空格键等完成表单组件的切换和交互。在填写一个表单时(iView Form 组件),尤其有用,你可以离开鼠标,就完成一个复杂表单的填写与提交。

目前 iView 最新版本支持键盘可访问性的组件有:

Button、Input、Radio、Checkbox、Switch、AutoComplete、Slider、InputNumber。更多组件还在陆续支持中。

事实上,原生的表单控件,浏览器都是支持键盘的可访问性的,比如 <button>、<input type=”radio”> 等等。iView 对这些原生控件进行了重塑,不仅仅使得 UI 好看和统一,更重要的是功能的丰富和交互体验的提升。

目前上述的组件,都是可以通过键盘的 tab键 选中的,这是第一步,如图所示:

可以看到,组件在被选中时,外面多了一个高亮层,表明当前选中的控件,这时就可以通过键盘其它按键继续操作了,比如单选组件 Radio,在选中状态下,可以通过键盘的方向键直接切换选项;Checkbox 在被激活时,可以通过空格键选择和取消选择某小项,通过 tab 键激活下一个小项。

三、其他更新

还有一些更新,是无法直接看见和体会到的。

比如更新了大量的依赖:

  • babel 系列全部更新
  • 使用了 browserslist
  • 使用了 sourcemap

部分组件的重构,虽然功能无任何变化,但代码结构和逻辑都做了优化和可维护性设计。

还有部分组件的自动化测试、持续集成对 GitHub travis-ci 的兼容等等。

外表需要优化,内部同样也是,就像一个人,既要有外在美,也要有内在美。

这两个版本都需要感谢两位瑞典大神 SergioCrisostomo 和 Xotic750 的贡献,iView 才得以越来越完善。

完整的更新日志可以到 GitHub releases 查看:

2.9.0: https://github.com/iview/iview/releases/tag/v2.9.0

2.10.0: https://github.com/iview/iview/releases/tag/v2.10.0

数据可视化可以很简约也可以很酷炫

别让工具限制了你的想象力

  • Mar 19 / 2018
  • 0
Data, Ideas

锐眼洞察 | 手把手教你简单快速实现5种数据可视化

作者:George Seif

原文:https://towardsdatascience.com/5-quick-and-easy-data-visualizations-in-python-with-code-a2284bae952f

译者:TalkingData数据工程师 新壮

本译文禁止商用,转载请注明来源!

数据可视化是数据科学家工作中的一个重要部分。在项目的早期阶段,你通常会进行探索性数据分析(EDA),以获得对数据的一些见解。创建可视化确实有助于使数据更易懂,特别是对于更大的高维数据集。在你的项目即将结束时,重要的是能够以清晰、简明和令人信服的方式展示你的最终结果,让你的听众可以理解,而他们通常是不懂技术的客户。

Matplotlib是一种流行的Python库,可以非常容易地用来创建数据可视化。然而,每次创建一个新项目时,设置数据、参数、图形和绘图都会非常混乱和乏味。在这篇博客中,我们会使用Matplotlib库写一些快速且简单的函数,实现5种图形可视化。同时,这里有一个非常好的图表,可以为你在工作中选择合适的可视化提供参考!

根据不同情况选择合适的数据可视化技术

散点图 

散点图很好地显示了两个变量之间的关系,因为你可以直接看到数据的原始分布。您也可以通过颜色编码来查看不同组数据之间的关系,如下图所示。想可视化三个变量之间的关系吗?没问题!只需使用另一个参数,比如点大小,对第三个变量进行编码就可以,如下面的第二个图所示。

颜色分组散点图

按颜色分组并对三个变量进行了大小编码的散点图

现在该展示代码了。我们首先引入Matplotlib的pyplot并命名为“plt”。通过调用plt.subplots()创建一个新的图。我们将X轴和Y轴的数据传入ax.scatter()绘制出散点图。我们还可以设置点大小、点颜色和alpha透明度。你甚至可以设置y轴使用对数刻度。然后针对具体的图像设置标题和轴标签。这是一个好用的函数,它从端到端地创建了一个散点图!

import matplotlib.pyplot as plt
import numpy as np

def scatterplot(x_data, y_data, x_label="", y_label="", title="", color = "r", yscale_log=False):

   # Create the plot object
   _, ax = plt.subplots()

   # Plot the data, set the size (s), color and transparency (alpha)
   # of the points
   ax.scatter(x_data, y_data, s = 10, color = color, alpha = 0.75)

   if yscale_log == True:
       ax.set_yscale('log')

   # Label the axes and provide a title
   ax.set_title(title)
   ax.set_xlabel(x_label)
   ax.set_ylabel(y_label)

线形图 

当你想清楚展示一个变量随另一个变量明显变化时(例如它们有很高的协方差),最好使用线形图。让我们通过下图来说明。

我们可以清楚地看到,所有专业的百分比随着时间的推移有很大的变化。用散点图来绘制这些图形会非常混乱,很难真正理解并看出正在发生的事情。对这种情况来说,线形图则是完美的,因为它们基本上快速地给我们总结了这两个变量的协方差(百分比和时间)。同样,我们还可以使用颜色编码对其分组。

线形图示例

下面是线形图的代码。它和上面的散点图很相似,只是变量有一些细微的变化。

def lineplot(x_data, y_data, x_label="", y_label="", title=""):
   # Create the plot object
   _, ax = plt.subplots()

   # Plot the best fit line, set the linewidth (lw), color and
   # transparency (alpha) of the line
   ax.plot(x_data, y_data, lw = 2, color = '#539caf', alpha = 1)

   # Label the axes and provide a title
   ax.set_title(title)
   ax.set_xlabel(x_label)
   ax.set_ylabel(y_label)
view raw

直方图 

直方图对于显示或发现数据点的分布非常有用。看看下面的直方图,我们画出频率 vs IQ直方图。我们可以清楚地看到均值和中位数是什么。我们也可以看到它遵循高斯分布。使用直方图(而不是散点图)可以让我们清楚地看到每个bin(直方)频率之间的相对差异。使用bin(经过离散化)确实帮助我们看到“更大的图景”,因为如果我们使用所有的数据点而不是离散化后的bin,那么在可视化中可能会有很多噪音,很难看清到底发生了什么。

直方图实例

使用Matplotlib绘制直方图的代码如下所示。有两个参数需要注意。首先,n_bins参数控制我们希望我们的直方图有多少个离散箱。更多的bins会给我们提供更详细的信息,但也可能会带来噪音,使我们远离更大的画面;另一方面,减少bins给我们更多的“鸟瞰”,描述发生了什么事情而没有更详细的细节。其次,cumulative参数是一个布尔值,它允许我们选择我们的直方图是否累积。也就是说选择的是概率密度函数(PDF)还是累积密度函数(CDF)。

def histogram(data, n_bins, cumulative=False, x_label = "", y_label = "", title = ""):
   _, ax = plt.subplots()
   ax.hist(data, n_bins = n_bins, cumulative = cumulative, color = '#539caf')
   ax.set_ylabel(y_label)
   ax.set_xlabel(x_label)
   ax.set_title(title)

假设我们要比较数据中两个变量的分布。有人可能认为你必须制作两个单独的直方图,并把它们并排进行比较。但是,实际上有一个更好的方法:我们可以用不同的透明度覆盖直方图。查看下图。均匀分布被设置为透明度为0.5,这样我们就可以看到它后面是什么。这允许直接查看同一图形上的两个分布。

覆盖直方图

在代码中设置了一些用于覆盖直方图的参数。首先,我们设置水平范围来容纳两个变量分布。根据这个范围和所需的箱数,实际上可以计算每个箱子的宽度。最后,我们将两个直方图绘制在同一个图上,其中一个稍微透明一些。

# Overlay 2 histograms to compare them
def overlaid_histogram(data1, data2, n_bins = 0, data1_name="", data1_color="#539caf", data2_name="", data2_color="#7663b0", x_label="", y_label="", title=""):
   # Set the bounds for the bins so that the two distributions are fairly compared
   max_nbins = 10
   data_range = [min(min(data1), min(data2)), max(max(data1), max(data2))]
   binwidth = (data_range[1] - data_range[0]) / max_nbins


   if n_bins == 0
     bins = np.arange(data_range[0], data_range[1] + binwidth, binwidth)
   else: 
     bins = n_bins

   # Create the plot
   _, ax = plt.subplots()
   ax.hist(data1, bins = bins, color = data1_color, alpha = 1, label = data1_name)
   ax.hist(data2, bins = bins, color = data2_color, alpha = 0.75, label = data2_name)
   ax.set_ylabel(y_label)
   ax.set_xlabel(x_label)
   ax.set_title(title)
   ax.legend(loc = 'best')

柱状图 

当你试图把类别较少(大概是10个)的分类数据可视化时,柱状图最有效。如果我们有太多的类别,那么柱状图将是非常混乱,并且难以理解。它们对于分类数据是很好的,因为你可以很容易地根据柱状的形状(例如大小)来区分类别之间的区别;类别也很容易划分和进行颜色编码。我们要看3种不同类型的柱状图:常规的、分组的和堆积的。下图中代码的顺序与图的顺序一致。

常规柱状图是下面的第一个图。在barplot()函数中,x_data代表X轴上的tickers和y_data代表Y轴上的柱状高度。error线是一条在每一柱状中间的额外的线,可以画出以显示标准差。

常规柱状图

分组柱状图允许我们比较多个分类变量。看看下面的第二个柱状图。我们首先比较的变量是分数如何根据组(G1,G2等)而变化。我们还通过颜色编码比较了他们的性别。我们来看一看代码,y_data_list变量现在真的是一个列表的列表,其中每个子列表代表一个不同的组。然后我们遍历每个组,对于每个组绘制x轴上的每一个刻度条,每组也是颜色编码的。

分组柱状图

堆积柱状图非常适合可视化不同变量的类别构成。在下面的堆积柱状图中,我们一天天地比较服务器负载。通过颜色编码后的堆,我们可以很容易地看到并理解哪一台服务器每天工作最多,以及一台服务器负载如何与其他服务器进行比较。此代码遵循与分组柱状图相同的样式。除了我们遍历每个组时在旧的上面画新的条,而不是在它们旁边。

堆积柱状图

def barplot(x_data, y_data, error_data, x_label="", y_label="", title=""):
   _, ax = plt.subplots()
   # Draw bars, position them in the center of the tick mark on the x-axis
   ax.bar(x_data, y_data, color = '#539caf', align = 'center')
   # Draw error bars to show standard deviation, set ls to 'none'
   # to remove line between points
   ax.errorbar(x_data, y_data, yerr = error_data, color = '#297083', ls = 'none', lw = 2, capthick = 2)
   ax.set_ylabel(y_label)
   ax.set_xlabel(x_label)
   ax.set_title(title)

   
def stackedbarplot(x_data, y_data_list, colors, y_data_names="", x_label="", y_label="", title=""):
   _, ax = plt.subplots()
   # Draw bars, one category at a time
   for i in range(0, len(y_data_list)):
       if i == 0:
           ax.bar(x_data, y_data_list[i], color = colors[i], align = 'center', label = y_data_names[i])
       else:
           # For each category after the first, the bottom of the
           # bar will be the top of the last category
           ax.bar(x_data, y_data_list[i], color = colors[i], bottom = y_data_list[i - 1], align = 'center', label = y_data_names[i])
   ax.set_ylabel(y_label)
   ax.set_xlabel(x_label)
   ax.set_title(title)
   ax.legend(loc = 'upper right')

   
def groupedbarplot(x_data, y_data_list, colors, y_data_names="", x_label="", y_label="", title=""):
   _, ax = plt.subplots()
   # Total width for all bars at one x location
   total_width = 0.8
   # Width of each individual bar
   ind_width = total_width / len(y_data_list)
   # This centers each cluster of bars about the x tick mark
   alteration = np.arange(-(total_width/2), total_width/2, ind_width)

   # Draw bars, one category at a time
   for i in range(0, len(y_data_list)):
       # Move the bar to the right on the x-axis so it doesn't
       # overlap with previously drawn ones
       ax.bar(x_data + alteration[i], y_data_list[i], color = colors[i], label = y_data_names[i], width = ind_width)
   ax.set_ylabel(y_label)
   ax.set_xlabel(x_label)
   ax.set_title(title)
   ax.legend(loc = 'upper right')

箱线图 

我们以前研究过直方图,其对于可视化变量的分布非常有用。但是如果我们需要更多的信息呢?也许我们想更清楚地看一下标准差?也许中位数与平均值有很大的不同,因此我们有很多离群值。如果数据有倾斜,许多值集中在一边呢?

那就是箱线图发挥作用的时候了。箱线图给了我们上面所有的信息实线盒的底部和顶部总是第一和第三分位(即数据的25%和75%),以及箱内的实线总是第二分位(中位数)。“胡须”(例如虚线条一端的条线)从箱中延伸出以显示数据的范围。

由于箱线图绘制自每一个组或变量,所以设置起来相当容易。x_data是组/变量列表。Matplotlib中boxplot()函数对y_data的每一列或y_data序列中的每个向量绘制箱线图;因此x_data中每个值对应于y_data中的列/矢量。所有我们要设定的就是绘图的美学。

箱线图示例

def boxplot(x_data, y_data, base_color="#539caf", median_color="#297083", x_label="", y_label="", title=""):
   _, ax = plt.subplots()

   # Draw boxplots, specifying desired style
   ax.boxplot(y_data
              # patch_artist must be True to control box fill
              , patch_artist = True
              # Properties of median line
              , medianprops = {'color': median_color}
              # Properties of box
              , boxprops = {'color': base_color, 'facecolor': base_color}
              # Properties of whiskers
              , whiskerprops = {'color': base_color}
              # Properties of whisker caps
              , capprops = {'color': base_color})

   # By default, the tick label starts at 1 and increments by 1 for
   # each box drawn. This sets the labels to the ones we want
   ax.set_xticklabels(x_data)
   ax.set_ylabel(y_label)
   ax.set_xlabel(x_label)
   ax.set_title(title)

结论 

以上就是使用Matplotlib简单快速实现的5种数据可视化。把事情抽象成函数总能让代码更易于阅读和使用。希望你喜欢这篇文章,并学到一些新的、有用的东西。如果你没有,就随便给它一些掌声吧~

  • Mar 19 / 2018
  • 0
Data, Ideas

技术专栏 | 走进分布式一致性协议

作者:TalkingData 战鹏弘

本文由TalkingData原创,转载请获取授权。

在分布式系统中,每一个机器节点虽然都能明确的知道自己在进行事务操作过程中的结果是成功或失败,但却无法直接获取其它分布式节点的操作结果。因此,当一个事务操作需要跨越多个分布式节点的时候,为了保证事务处理的ACID特性,需要引入一个成为“协调者”的组件来统一调度所有分布式节点的执行逻辑,这些被调度的分布式节点则被称为“参与者”。协调者负责调度参与者的行为,并最终决定这些参与者是否要把事务真正进行提交。基于这个思想,衍生出了二阶段提交(2PC)和三阶段提交(3PC)。

2PC

为了使分布式系统下所有节点在进行事务处理的时候能够保持原子性和和一致性而设计的算法。

两个阶段

阶段一:提交事务请求

协调者向各个参与者发送事务内容,询问是否可以执行事务操作,等待参与者响应。

参与者接收到询问之后,执行事务操作,但是不commit,将undo和redo信息保存到事务日志中。

参与者根据执行情况向协调者返回是否可以执行事务的响应。

阶段二:执行事务提交

阶段一参与者都返回yes

协调者收到所有的yes信号之后,通知参与者执行最后的commit,参与者执行完成之后,想协调者返回ACK信息。

协调者接收到所有的ACK信息之后,完成分布式事务操作

阶段一某个参与者返回no

说明其中一个参与者无法成功执行事务,协调者通知所有参与者回滚事务。

参与者进行事务回滚,完成之后向协调者返回ACK信息

协调者接收到所有的ACK信息之后,事务中断完成

协调者的作用

阶段一

发送给参与者信息

接收参与者反馈,确定下一步需要发送给参与者的信息

阶段二

根据阶段一获得的响应,确定需要发送给参与者的信息(此时如果协调者出问题,无法通知参与者执行commit,参与者的资源会一直被锁住)

接收参与者的反馈,事务结束

注意问题

同步阻塞
第一阶段各个参与者执行事务操作的过程都是阻塞的,各个所有参与者全部完成响应之前,资源都是被加锁的,无法进行其它操作。

协调者的单点问题
两个阶段都需要协调者进行协调,第二阶段中协调者向参与者发送事务commit的新号时,一旦出问题,参与者将无法提交commit操作,资源一直会处于锁定状态,无法释放。

数据不一致
第二阶段协调者发送事务commit信息时,如果与某个参与者的连接出问题,会出现其他参与者成功提交事务,而该参与者事务无法提交,各个参与者的数据会出现不一致的情况。

3PC

阶段一(canCommit)

区别于2PC,3PC的第一阶段会询问所有的参与者是否可以进行事务提交,但是不去执行事务(2PC的第一阶段实际上去执行了事务,但是没有commit而已),这一阶段可以在不锁定资源的前提下,判断各个参与者是否能够执行事务,当然各个参与者返回yes不代表后续执行事务一定会成功。

2PC的第一阶段会真正执行事务,如果某个参与者出现问题,消耗了很长时间返回给协调者no信号,再这个很长时间内,其它的参与者会一直锁定资源,block在那里。3PC的第一阶段有效的解决了该问题。

阶段二(preCommit)

阶段二同2PC的阶段一实际上是相同的,会执行事务但是不提交,但是很大程度上减少了2PC在他的阶段一出现阻塞的问题

阶段一参与者都返回YES

各个参与者执行事务,但是不提交,返回给协调者ACK信号

阶段一有某个参与者返回no

协调者通知参与者中断事务,因为第一阶段中没有执行操作,所以不需要回滚

阶段三(doCommit)

阶段二所有参与者返回yes

说明各个参与者事务执行成功,通知参与者进行commit,返回给协调者ACK,完成事务

阶段二某个参与者返回No

通知所有参与者回滚事务,返回给协调者ACK,中断事务

注意问题

进入阶段三之后,如果协调者出现故障或者与参与者之间的连接出现问题,参与者等待commit信号超时之后,会继续进行事务提交。这种机制一定程度上在协调者故障或者连接出问题时,解决数据不一致问题。

2PC和Paxos

2PC和Paxos作为分布式一致性协议,分别适用于两类一致性:操作原子性和副本一致性。

2PC:保证分布式环境中的多台机器的操作的原子性,要么全部成功,要么全部不成功

Paxos:保证同一个数据分片的多个副本之间的数据一致性

Paxos算法

Paxos算法是莱斯利-兰伯特于1990年提出的一种基于消息传递且具有高度容错性的一致性算法,是目前公认的解决分布式一致性问题最有效的算法之一。

Paxos算法需要解决的问题是如何在一个可能发生机器宕机或者网络异常等异常的分布式系统中,快速且正确的在集群内部对某个数据的值达成一致,并且保证无论发生上述任何异常,都不会破坏整个系统的一致性。

分布式系统的存在为了解决单点问题,例如典型的master slave模式,一旦master宕机之后,需要将slave节点切换为master节点,条件是slave和master节点的数据是一致的,也就是说在master上的一切操作都需要同步到slave节点上,这样的slave才具备选举为master的条件。Paxos算法可以为这种数据一致性提供有效的保障。

Paxos算法可以分为两个阶段,prepare阶段和accept阶段,下面简单阐述一下这两个阶段。

prepare阶段

假设现在分布式集群中有三个节点:A、B、C,A把申请操作的请求发送给A、B、C,发送的请求会携带一个Sequence Number(这个值会不断递增,且是唯一的),接受节点在prepare阶段会拒绝接受到的任何提案号小于当前提案号的请求。

如果接受节点接收到的提案号大于当前提案号,节点会给节点A返回yes,并且不在接受提案号更小的提案,也就是说节点总会对最新的提案号做承诺。

accept阶段

如果提案者A收到了半数以上的节点返回yes,他会再次向接收节点发送accept request,仍会携带一个sequence number(n),当接收节点收到accept request信号之后,如果n是接收者接收到的最新的提案号,那么会最终通过提案,如果发现存在比n更大的提案号,拒绝该request,同时提案者会重新进行第一阶段(prepare阶段)。

具体的执行过程如下图所示:

(图片来自:https://www.cnblogs.com/cchust/p/5617989.html)

分布式一致性算法的工程实践

Chubby

Google Chubby是一个有名的分布式锁服务,Google的GFS和Big Table等大型分布式系统都是用它来解决分布式写作、元数据存储和Master选举等一系列与分布式锁相关的问题。

假设Chubby集群中有5台服务器:A B C D E,其中A是当前的master,另外4台服务器实际上是A的副本。Chubby实际运行过程中,只有作为master的A服务器会对外提供写操作服务,其他四台服务器通过Paxos协议从A服务器中同步数据的操作,Paxos协议能够有效的保证副本节点的数据和master节点之间保持一致性。

Chubby中每次提案value的选定是一个Paxos instance,提案由多个proposer提出,最终得到一个value。每次提案的选举都会计入到底层的log日志中,由于Chubby需要不间断的对外提供服务,因此会不断产生Paxos instance,事务日志也会不断增长。每个Paxos instance负责确定一个value,多个instance之间是互不相关的,可以并发进行。将Paxos每两个阶段的提交prepare→promise→propose→accept记作一个round,每个Paxos instance执行过程中可能会经历多轮round,最终才能确定最后的提案。

上述基本的Paxos算法执行过程存在可优化的地方:多个proposer的活锁问题会严重影响效率,导致一个instance最终选定提案需要执行多轮round。

实际执行过程中,可以将多个instance的prepare阶段合并成一个阶段。首先必须在多个proposer中选举出一个master作为唯一的proposer,原本多个instance之间是互相独立的,只需要保证instance内部的round序号不重复即可。现在为了合并prepare阶段,多个instance之间公用一套序号,具体做法如下:

当某个replica通过选举获得master资格后,用新分配的编号N广播一个prepare消息,这个prepare消息被所有未达成一致的instance和将来还未开始的instance共用。

当acceptor接收到prepare后,现在必须对多个instance同时做出回应,这可以封装在一个数据包中,假设最多允许K个instance同时选举,那么:

当前至多有K个未达成一致的instance,将这些未决的instance各自最新accept的value(若没有用null代替)封装进一个数据包,作为promise消息返回

同时,标记这些未决instance和所有未来instance的highestPromisedNum为N,如果N比它们原先的值大的话。这样,这些未决instance和所有未来instance都不能再accept编号小于N的proposal。

然后master就可以对所有未决instance和所有未来instance分别执行propose→accept阶段,始终使用编号N,如果这个master保持稳定的话,就再也不需要prepare→promise了。但是,一旦发现acceptor返回了一个reject消息,说明另一个master启动,用更大的编号M>N发送了Prepare消息,这时自己就要分配新的编号(必须比M更大)再次进行prepare→promise阶段。

ZooKeeper

在ZooKeeper中,client向ZooKeeper提出一个事务,例如创建一个znode,请求会发送到ZooKeeper中的所有机器上,leader需要协调事务的执行,只要集群中半数以上的机器成功执行了该事务,leader便会通知follower进行事务提交。leader作为ZooKeeper中最重要的角色,协调事务执行过程中会保存一个全局的变更序列,可以保证如果一个状态变更已经被处理了,那么所有以来的状态变更应该已经被提前处理了。
ZooKeeper中使用的分布式一致性协议ZooKeeper Atomic Broadcast(ZAB,ZooKeeper原子消息广播协议),ZAB协议的消息广播过程使用的是一个原子广播协议,类似于一个二阶段提交过程。根据客户端的事务请求,leader服务器会为其生成对应的事务poposal,并发送给集群中其余所有的机器,然后收集各自的选票,最后进行事务的提交。

与二阶段提交不同的是,ZAB协议移除了终端逻辑,所有的follower服务器要么正常反馈leader提出的事务proposal,要么抛弃leader服务器,这意味着leader可以在过半的follower服务器已经反馈ACK信号之后就开始提交事务proposal,而不需要等待所有的follower服务器都反馈响应。当时,这种简化的二阶段提交下,无法处理leader服务器崩溃退出而带来的数据不一致问题,因此ZAB协议添加了崩溃恢复模式来解决这个问题。

ZAB协议的执行过程

ZAB主要包括消息广播和崩溃恢复两个过程,进一步可以分为三个阶段,分别是发现(Discovery)、同步(Synchronization)、广播(Broadcast)阶段。ZAB的每一个分布式进程会循环执行这三个阶段,称为主进程周期。

发现:选举产生PL(prospective leader),PL收集Follower epoch(cepoch),根据follower的反馈,PL产生new epoch(每次选举产生新Leader的同时产生新epoch)。

同步:PL补齐相比follower多数派缺失的状态、之后各Follower再补齐相比PL缺失的状态,PL和follower完成状态同步后PL变为正式leader(established leader)。

广播:leader处理客户端的写操作,并将状态变更广播至follower,follower多数派通过之后leader发起将状态变更落地(deliver/commit)。

在正常运行过程中,ZAB协议会一直运行于阶段三来反复进行消息广播流程,如果出现崩溃或其他原因导致leader缺失,那么此时ZAB协议会再次进入发现阶段,选举新的leader。

leader可能在事务提交完成或者提交了一半的时候崩溃,因此leader选举算法需要确保提交已经被leader提交的事务的proposal,同时丢弃已经被跳过的事务proposal。

如果让leader选举算法能够保证新选举出来的leader服务器拥有集群中所有机器最高编号(ZXID最大)的事务proposal,那么就可以保证这个新选举出来的leader一定具有所有已经提交的提议,更为重要的是如果让具有最高编号事务的proposal机器称为leader,就可以省去leader服务器查询proposal的提交和丢弃工作这一步骤了。

  • Mar 19 / 2018
  • 0
Data

锐眼洞察 | 如何正确构建数据平台

作者:Michelle Knight

原文:Predictive Customer Analytics — Part Ihttp://www.dataversity.net/data-architecture-need-choose-right-data-platform/

译者:TalkingData数据工程师 孙强

本译文禁止商用,转载请注明来源!

做了不够理想的数据架构和数据平台,就像是买东西时找不到钱包或现金。 正如McKnight咨询集团总裁McKnight在其DATAVERSITY Database Now! Online 2017 Conference的主题演讲中提到的:“我们可能会被数据淹没,该选择合适的平台了!”

McKnight是一位经验丰富的信息管理战略家,也是《信息管理:利用数据获得竞争优势的策略》的作者。他在发言中强调:

“我们的经济完全依赖于数据的自然资源。 我们的组织拥有(数据)这个黄金资产。我们的组织在未来十年如何竞争并获得优势,完全取决于我们如何使用数据。”

作为推荐数据平台的专家,McKnight在他的职业生涯中进行了多项成熟的研究。他指出,那些更充分运用数据的行业以及行业内的企业,比那些没有充分运用数据的行业和企业做的更好。 McKnight观察到“这些表现最佳的行业和企业们正在扩展其大数据应用。”

那么,为什么现在要考虑数据架构呢? McKnight表示,我们需要摆脱“快我一些数据”和“高效的给我优质的数据”的思路,转向“快速、高效的提供所有数据”。为了实现这种需求,“是时候做些跳出常规、与众不同的事情了。”McKnight表示:

“要处理超出能力范畴的需求很难。 但是我们必须使平台正确适用于工作负载,并使其与数据集成和数据可视化一起工作。 数据仓库不再是宇宙的中心。 那些非关系型平台实际上为我们提供了有价值的参考。”

选择数据平台时该考虑什么?

对于在组织的整个数据架构中构建更高效的数据平台来说,选择正确的数据存储类型至关重要。

McKnight表示:“过去一切都是数据库。 但是现在还有很多其他的选择,比如“严格来讲不在位和字节级的数据库”的基于文件的扩展系统。 基于文件的扩展系统没有围绕数据的相同框架。他建议这样的系统尤其适用于非结构化或半结构化数据。 其他必要考虑的包括:

  • 数据存储位置:McKnight表示:“并不是必须将数据存储在数据中心。”现在有很多更具性价比的云可供选择。 比如私有云、公有云和很多混合云的选择。
  • 工作负载架构:“区分操作性或分析性的工作负载,”McKnight建议。 “短交易请求和更复杂(通常更长)的分析请求需要不同的体系结构。”分解工作负载的需求并围绕这些工作负载正确设计数据平台至关重要。
  • 内存:McKnight观察到,很多人仍执迷于HDDs(硬盘驱动器),他敦促组织“开放一点点”。现在市场上还有很多选择,比如固态硬盘(SSD) 、内存(In-Memory)以及其他较低成本的存储器。

他举了可提供超快速性能的内存数据存储作为示例: “对于选择性的工作负载,它具有很高的专用功能性,为ROI提供更多机会。 我们现在开始更多探索内存的利用。”

他将内存选择比喻为“吹动风帆的风”,这让帆船行驶的更快,并超越其他竞争对手。他表示,内存可能会“在我们进行设计过程时给出更多的容错空间。

不要忘记Data Profile

所谓数据成熟度,就是“创建一个高效的环境,我们可以向环境里添加内容,而无需每次重新开始。”为此,组织需要查看Data Profile。 “我们中的许多人在排列优先事项时是颠倒的。”McKnight说:

“我可以从Data Profile中获得很多信息。 比如数据的大小和类型、是结构化的还是非结构化的、一些示例记录以及数据输入的频率。数据来自哪里? 被访问的频率如何?数据的质量如何?”

云提供了有吸引力的选择

McKnight表示,当他与客户一起为数据平台选项融资时,“许多公司不想处理资本化支出。 他们更愿意操作他们,这就是云模式,对吧?“在思考云时,紧密集成是势在必行。

McKnight提供了以下例子:

“你可能会把你的数据仓库放到云中。 那商业智能呢,你会把它们放到云端吗?数据集成如何? MDM呢,可以放在云端吗? 以上所有都是可以的。 当开始认真思考数据,这些问题就会随之产生。”

他表示,一个成熟的数据架构“现在不是有一些、而是有很多云可以选择”。McKnight强调说,现在有不同的云模型,重要的是找到适合的。

新的选择维度

除了上述因素之外,还需要为数据平台权衡新的选择维度。 如:

  • SQL的稳健性:“SQL中有一些新发现的功能使其具有重要意义。”
  • 内置优化:全面考虑云和数据虚拟化。 优化器现在有更多的作用。
  • 即时弹性:问问自己,是否真的拥有它? 是否真的需要它?
  • 动态环境适应性:评估同时使用并发使用模式的能力。
  • 将计算从存储中分离出来:这对于云计算来说非常重要,可以分别对这两种情况进行扩展。
  • 支持多种数据:需要考虑到,会有JSON、XML和各种形式的非结构化数据流入企业数据环境。

用数据平台取得成功

基于McKnight过去几年所合作的客户,他指出:“用户数量、性能预期、数据量、分析复杂性等方面需求已经开始大幅增加”。因此,成功建立数据平台至关重要,可以通过以下方式来确定:

  • 性能:McKnight将性能视为首要点。他认为:

“我们可以通过平台决策为用户提供更好的性能。 随着他们在数据中的能力而增长并不会受到限制,因为每个查询将需要5分钟。 如果这些查询出现,他们将进入更深层次。 如果您一段时间没有考虑数据平台,那这些就不会发生。”

  • Provisioning:McKnight将其描述为“可以多快地启动并运行数据平台? 它有多敏捷?“
  • 规模:建议考虑:“我可以从小型开始再逐步扩大吗?”
  • 成本:不要过度消耗成本。 保持在组织所能负担的成本。

用数据平台取得成功

McKnight为成功搭建数据平台提供了七条最终建议:

  1. 针对不同规模的企业,现在有各种数据平台可供选择
  2. 选择正确的平台并按规划进行
  3. 从数据的存储类型、布局和工作负载架构开始
  4. 将Data Profile作为选择正确平台的重要依据
  5. 确保数据平台能够支持现有的和未指定的需求
  6. 分析平台应该是分级操作数据存储(ODS)或数据仓库(DW)或数据集市(来自DW或专门供应)或Hadoop
  7. 云现在能够提供更经济的更有吸引力的选择
  • Mar 19 / 2018
  • 0
Data

重磅!TalkingData2017年移动互联网行业发展报告

本文由TalkingData原创,转载请获取授权。

自2016年第二季度起,中国移动智能终端规模增速连续七个季度低于2%。增长困局下,移动数据的应用场景细化、与线下消费的深度融合成为了破局点。2017年的新零售、无人货架等热点,皆是围绕这两个主题。智慧经济,就是将人工智能、 大数据、互联网自动化能力融入各行各业。移动互联网推动了各行业的数字化进程。从业务数字化到效益数字化,线上线下数据融合后的数据资产将帮助企业和组织实现智能化决策,打造智慧经济。

本报告中,我们将关注增长困局下的人本洞察、移动应用、智能终端,回顾移动数据与各行各业的深化融合,并提出智慧经济趋势下的数字化转型方法论。

移动智能终端低增速时代开启已有七个季度

中国移动智能终端设备规模季度增速放缓,自2016年第二季度起,移动智能终端增速就跌破2%。移动智能终端用户规模步入低增速时代已有七个季度。

移动智能终端用户在经济发达地区集中度更高

截至2017年12月,我国移动智能终端用户TOP10省份占据了整体近六成用户。位居2017省市人均GDP排名前六位的北京、江苏 、浙江、广东作为经济发达地区,移动智能终端用户集中度更高,其智能终端用户占比要高于人口占比,人才吸附能力更强。

城市人生活愈加繁忙,生活半径在增大、通勤距离在增加

通过分析北京地区上班族的活动范围,可以观察到现代人在城市中的生活半径在扩大,长距离通勤的人群比例在增加,都市生活愈加繁忙,人们对于生活、交通便捷性的需求值得被关注。

城市存在时空折叠,均衡的资源不代表将被均衡利用

通过分析北京地区高消费与低消费人群利用商业设施的状况发现,虽然北京不同区域的商业设施配置和分布相对均衡,但两个群体对设施的利用在时间和空间上却鲜少重合。

 

男性用户占比下降,性别分布趋于平衡

2017年,随着移动智能终端用户趋于饱和,移动智能终端用户性别特征逐渐趋近人口学特征,预计2018年中国智能终端用户中男性用户占比将会下降至52.5%。

 

年轻人群仍为用户主体,90后成未来消费主力

2017年,我国移动智能终端用户中35岁及以下用户的比例达69.9%,年轻用户仍然是移动互联网用户的主体。

随着更多90后人群步入职场,他们将成长为消费主力。相比80后,他们的生活状态已被移动互联网深度影响。

90后人群开始逃离北上广深

 相比80后,90后人群城市层级分布中一线城市占比要更低。90后人群开始逃离北上广深,更多的选择郑州、武汉等区域中心城市作为个人发展的起点。

活跃用户规模下降,主流行业应用增长乏力

2017年,通讯社交、视频、游戏等主流行业应用活跃用户规模增长乏力,而教育、旅游、健康美容等行业类别应用覆盖率及活跃率出现双增长,行业潜力正在释放。

每日打开应用数量下降,首屏应用竞争加剧

移动智能终端用户平均安装与平均每日打开应用款数已连续两年出现下滑,设备一个屏幕上的应用已可基本满足日常使用。存量时代移动应用对于用户的争夺更加激烈,现有数据价值的深挖成为运营关键。

头部应用把持主流用户,新应用面临艰巨挑战

2017年,移动互联网头部应用覆盖率领先优势明显,细分行业中的TOP5应用覆盖了行业主流用户。

OPPO、vivo市场份额增长,线下渠道价值得到体现

2017年表现最为亮眼的移动智能设备品牌是主打线下渠道的OPPO与vivo,两个品牌的市场份额分别从2016年12月份的8.6%、7.3%增长至2017年12月份的12.6%、10.3%。

从派生到原生,资源融合丰富用户数据价值

移动互联网已从派生模式发展到原生模式,相比于新闻资讯、搜索、视频等派生模式服务内容,原生模式对于线下资源的融合度更高,实体资源为服务商带来更多的用户流量与交互数据资产。

运营模式过重,原生模式赛道洗牌速度加快

资源融合加重移动互联网原生模式运营成本,行业竞争成为资本之争。头部应用融资、并购速度加快,而缺少资本支持的小玩家迅速走向消亡。

资本热潮之后,共享经济用户向二三线城市下沉

作为2017年原生模式新赛道的代表,共享充电宝、无人货架在经历了初期的资本热潮后,运营模式逐渐向二三线城市倾斜,用户下沉成为验证商业模式的突破口。

双管齐下,互联网巨头布局数据融合生态

通过手机支付、微信小程序等数据融合工具的运营,以及线下对百货商超、零售集团、生鲜超市等零售业态的投资布局,阿里巴巴与腾讯正在围绕线下消费打造数据融合生态。

重构人、货、场,数据融合推动零售新探索

以盒马鲜生等生鲜超市为代表,移动数据正在融入零售各个环节,人、货、场关系被重构,交易、交互等数据的融合在推动零售产业链的数字化探索。

精准触达,移动数据深化金融服务场景

借助移动应用数据,金融服务能够精准触达大货车司机、留学生等细分人群,围绕应用描绘人群理财偏好。线上数据的融入让金融服务触达的服务场景更加细化,金融普惠性得到提升。

从数字到数字,业务决策将走向智能化

以业务数字化为起点,以效益数字化为节点,通过数据资产化、分析模型化、应用场景化、流程自动化四项能力构建,线上线下数据融合后的数据资产将帮助企业和组织实现智能化决策,打造智能化组织。

获取本报告完整版

请点击:http://mi.talkingdata.com/report-detail.html?id=719

  • Mar 16 / 2018
  • 0
Data, Enterprise

锐眼洞察 | 预测性客户分析Part 4——借助聚类和预测分析优化售后服务(翻译)

作者:Ryan Aminollahi

原文:Predictive Customer Analytics — Part 4

译者:TalkingData研发副总裁 阎志涛 

本译文禁止商用,转载请注明来源!

本篇是这个系列文章的最后一个部分,将要说明的重点案例是利用聚类分析对售后问题进行分组,对不同分组进行分析,进而采取针对性的优化或者行动。

如果你读过以前的几篇文章,你知道在故事中,顾客X已经购买了一台笔记本电脑。现在想象一下,他正尝试在家里设置这台电脑。在设置的时候,他发现该电脑无法与无线键盘正常连接。他认为自己搞砸了设置并试图找到解决办法:他浏览产品网站查看是否有任何自助视频可帮助他找出原因,但他并没找到任何有用的信息。然后他打电话给公司,得到了一个自动提示让他提供所有的信息。

他在接下来的15分钟排队等候,最终,他排到了一位客户代表,客户代表再次要求他提供所有信息。正如你可以想象的那样,X变得更加恼火。客户代表在听到他的问题后,通过电话向他提供了一些指示,但X无法理解并按照步骤来操作。他要求提供现场帮助,但客户代表拒绝了他,说他的保修不包含现场服务。X感觉非常沮丧,开始考虑再也不从这家供应商购买任何东西。

这是因低质量服务和支持而感到沮丧的无数顾客中的一个例子。在今天的互联网世界中,更换供应商只需点击一下鼠标即可。企业需要更努力、更聪明地保持现有客户的满意度,并且通过他们的推荐获得新的客户。客户服务流程从为客户提供交互选项开始,从网站自助、电子邮件到电话支持,今天的支持中心运行在全方位的各种渠道上。

一旦客户发起联系,企业就需要为他们提供优质的服务:询问最少的问题并迅速解决问题。

这就要求企业不仅要了解客户,还要了解客户当前问题发生的背景以及与客户交互的整个过程。企业需要让客户感觉到企业真正了解并关心他的问题。

今天的客户服务世界已经开始转向使用交互式语音和聊天机器人的自助服务和自动化的时代。

这些自动化的服务需要智能地预测客户正在经历的事情,并能理解客户问题,提供快速的解决方案。预测性分析肯定会对客户服务领域有所帮助。

预测客户发起联系的目的

让我们思考一下前面做错了什么。假定客户X在销售阶段已经将自己的电话号码提供给了公司,客户支持难道不应该通过他的呼叫ID自动识别他吗?

客户X在笔记本电脑交付给他两天之内打电话,是否意味着这通电话非常有可能与这次购买有关呢?在第一次电话过程中,客户支持针对他的笔记本电脑键盘问题创建了一个问题记录,并且给了他一些建议。

然而,过了两个小时之后他又打电话过来,客户支持能否推测到他的第二个电话非常有可能与第一个问题记录有关系?这个用例的目标是建立一个预测模型,这个预测模型可以预测客户联系企业的可能性原因。知道这个原因可以帮助企业快速将客户对接到能解决相应问题的人那里,从而让问题在第一次交互时得到解决。这个用例中的数据是过去的所有客户和企业之间的交易数据。

这些数据包含销售的交易信息,包括产品、状态以及交付的详细数据。我们将来也会使用客户与企业以往联系的数据。对于每一次联系,我们会使用原因、处理这次联系的客户代表、时长、根本原因、解决方案、状态等数据。这是一个分类问题,因此前面我们使用过的算法就比较适合。让目标分类的数量小于10是非常重要的。

将要使用的算法会被用来产生预测目的模型,我们将会使用销售交易和与以前的联系相关的数据去产生这个模型,并将用模型预测客户联系的目的。行动计划如下:这个分类模型会离线进行构建,当一个客户通过电话或者聊天工具联系企业时,使用呼叫者ID或者用户ID去识别客户,然后使用算法去预测这次呼叫的原因。如果预测呼叫的原因是上一次的购买,则通过IVR回答客户“您好,请问您是因最近购买的笔记本电脑有问题而需要帮助吗”。客户一定会感到非常高兴,因为企业能够猜测他的问题,尽管这不一定是真正的原因。

这恰当地表明了我们理解他并且知道他正在经历什么困难。

寻找不满意的客户

一个企业该如何发现他的客户对于企业的产品或者服务是满意还是不满意呢?

第一, 不满意的客户通常会对调查问卷进行反馈。仔细想一下,因为X先生对服务以及产品感到不满意,他通常更愿意花时间去填写调查问卷和发泄。但是Y女士则未必会如此。

第二, 通常仅仅有10%的客户会对调查进行反馈。那么企业如何能够识别出那些沉默的、想要或者已经转移到其他企业的客户呢?这个用例的目标是构建一个模型,这个模型能够预测企业的所有用户的满意度,不管这个用户是否填写了调查问卷。构建这个模型的数据是从那些真实的已填写调查问卷的客户中得来的。

这份数据包括客户的人口统计学数据以及用户历史行为数据,包括与公司之间的事件和交易数据以及结果。特别需要指出的是,这些数据包括缺陷、退货、客户支持的记录、解决问题的时间以及呼叫服务电话的次数,这些数据构成了特征变量。目标变量是从调查问卷得来的度的分数。比较典型的是这个分数是从0到5或者是从0到10的有一位到两位小数的数字。

如果分数是离散的值,比如1、2、3、4、5,那么我们可以使用Gordon分类来处理。在我们的用例中,我们假定分数值是连续的,因此我们将会使用线性回归算法。利用人口统计学和历史的数据,构建一个可以用来预测客户满意度分数的线性回归方程。这个用例的行动计划是:利用真正回答了调查问卷的客户的数据构建一个预测模型,来预测客户满意度分数。我们需要将调查数据进行规范化,从而去掉可能会影响整体模型的异常值,然后我们将模型应用到所有客户,来发现客户的满意度评分。

然后我们的客户支持团队得到一个最不满意的客户列表,可以去主动联系这些客户,询问他们使用产品的感受和问题或者最终给他们一些折扣。

将问题进行类型分组

客户支持团队每天在处理不同的问题,有些问题会被经常问到并且简单直接,技术工程师甚至可以在客户解释完问题之前就能给出解决方案。另外一些问题则不那么常见并且比较复杂,需要多次的电话沟通以及现场服务才能解决。一个网络连接问题是非常容易诊断的,但是诊断一个笔记本电脑的蓝屏问题则要困难得多。实际上人力资源成本是非常高的,因此企业需要找到优化使用人力资源的方法。

这包含对一些问题提供在线帮助,包括对技术支持团队更严格的培训或者对复杂问题建立新的专家职位。为了帮助企业做这些决策,需要基于相似的属性对问题进行分组。这是这个用例的目标,对于一个问题类型列表,企业需要识别逻辑的问题分组,从而使用它们去开发优化那些消耗最少人力资源的解决方案。

这个用例的数据,是从技术支持团队记录下来的问题库数据中得到的问题统计数据。问题数据按照问题类型做汇总。特征数据是解决问题的平均时间、平均电话的次数、替换率等等。既然我们要创建逻辑分组,我们将要使用K-Means聚类算法或者相关的一些变种算法。通过多次采用不同的K值进行试验来衡量出一个最佳的分组数量。

利用问题统计数据,我们能够将相似的问题进行分组。行动计划如下:当问题类型已经被分组,我们将会分析每个分组去发现分组里边的相似性,比如解决问题花了更长的时间或者非常低的发生率。然后我们就可以得出优化解决方案的计划,例如在我们的网站上提供自帮助、在YouTube提供视频或者对这个问题领域的技术人员做更好的培训。

作为一个企业,我们想要达到客户支持的效率和有效性的最大化。这个用例帮助我们达到这个目标。

问题分组用例

我们如何能够将相似的问题分组到不同的问题类型,然后在组里对它们进行分析来判断是否有任何模式,紧接着采取某些行动去解决效率和有效性问题?

载入数据集

In [1]:

(注:左右滑动即可查看完整代码,下同)

%matplotlib inlinefrom pandas import Series, DataFrame
import pandas as pd
import numpy as np
import os
import matplotlib.pylab as plt
from sklearn.model_selection  import train_test_split
from sklearn.cluster import KMeans
import sklearn.metrics

raw_data = pd.read_csv(“issues.csv”)
raw_data.dtypes

Out [1]:

PROBLEM_TYPE             object
COUNT                     int64
AVG_CALLS_TO_RESOLVE    float64
AVG_RESOLUTION_TIME       int64
REOCCUR_RATE            float64
REPLACEMENT_RATE        float64
dtype: object

这个数据集对于每个唯一的问题类型有一条记录,每个类型包含一些度量值,例如总量,解决问题平均电话次数,解决问题平均时常等等。

raw_data.head()

将数据分到不同的相似聚类组中

现在我们将会使用K-Means聚类去根据属性将数据聚类到不同的组当中。首先,我们需要决定分组的最优的数量,为此,我们采用膝部法来测试确定什么时候这个膝状发生。(参照https://datasciencelab.wordpress.com/2013/12/27/finding-the-k-in-k-means-clustering/)

In [3]:

clust_data = raw_data.drop(“PROBLEM_TYPE”,axis=1)#Finding optimal no. of clusters
from scipy.spatial.distance import cdist
clusters=range(1,10)
meanDistortions=[]

for k in clusters:
model=KMeans(n_clusters=k)
model.fit(clust_data)
prediction=model.predict(clust_data)
meanDistortions.append(sum(np.min(cdist(clust_data, model.cluster_centers_, ‘euclidean’), axis=1)) / clust_data.shape[0])

#plt.cla()
plt.plot(clusters, meanDistortions, ‘bx-‘)
plt.xlabel(‘k’)
plt.ylabel(‘Average distortion’)
plt.title(‘Selecting k with the Elbow Method’)

Out [3]:

<matplotlib.text.Text at 0x27298f49eb8>

观察那些点,我们发现膝状发生在cluster=3的时候,这是聚类的最佳的数量,因此我们在实际操作中将会设置聚类的数量是3。然后我们在原始的数据集上添加聚类的ID。

In [4]:

#Optimal clusters is 3
final_model=KMeans(3)
final_model.fit(clust_data)
prediction=final_model.predict(clust_data)#Join predicted clusters back to raw data
raw_data[“GROUP”] = prediction
print(“Groups Assigned : \n”)
raw_data[[“GROUP”,“PROBLEM_TYPE”]]
Groups Assigned :

对分组进行分析

我们现在可以做一系列的箱型图去看这些不同组在不同的特征变量上的差异。我们从count先开始。

In [5]:

plt.cla()
plt.boxplot([[raw_data[“COUNT”][raw_data.GROUP==0]],
             [raw_data[“COUNT”][raw_data.GROUP==1]] ,
               [raw_data[“COUNT”][raw_data.GROUP==2]] ],
           labels=(‘GROUP 1′,’GROUP 2′,’GROUP 3’))

Out[5]:

{‘boxes’: [<matplotlib.lines.Line2D at 0x27299349ef0>,
<matplotlib.lines.Line2D at 0x27299362390>,
<matplotlib.lines.Line2D at 0x27299375cc0>],
‘caps’: [<matplotlib.lines.Line2D at 0x272993589b0>,
<matplotlib.lines.Line2D at 0x27299358ac8>,
<matplotlib.lines.Line2D at 0x2729936abe0>,
<matplotlib.lines.Line2D at 0x2729936eb38>,
<matplotlib.lines.Line2D at 0x2729937ec50>,
<matplotlib.lines.Line2D at 0x2729937ed68>],
‘fliers’: [<matplotlib.lines.Line2D at 0x2729935db38>,
<matplotlib.lines.Line2D at 0x27299375ba8>,
<matplotlib.lines.Line2D at 0x27299385dd8>],
‘means’: [],
‘medians’: [<matplotlib.lines.Line2D at 0x2729935d320>,
<matplotlib.lines.Line2D at 0x2729936ec50>,
<matplotlib.lines.Line2D at 0x272993855c0>],
‘whiskers’: [<matplotlib.lines.Line2D at 0x27299350940>,
<matplotlib.lines.Line2D at 0x27299350a58>,
<matplotlib.lines.Line2D at 0x27299362b00>,
<matplotlib.lines.Line2D at 0x2729936aac8>,
<matplotlib.lines.Line2D at 0x27299379be0>,
<matplotlib.lines.Line2D at 0x27299379cf8>]}

我们可以看到在不同的分组中问题的数量有明显的区别。
接下来我们看解决问题的平均电话数量。

In [6]:

#Now for Avg. Calls to resolve
plt.cla()
plt.boxplot([[raw_data[“AVG_CALLS_TO_RESOLVE”][raw_data.GROUP==0]],
             [raw_data[“AVG_CALLS_TO_RESOLVE”][raw_data.GROUP==1]] ,
               [raw_data[“AVG_CALLS_TO_RESOLVE”][raw_data.GROUP==2]] ],
           labels=(‘GROUP 1′,’GROUP 2′,’GROUP 3’))

Out[6]:

{‘boxes’: [<matplotlib.lines.Line2D at 0x272993f2ba8>,
<matplotlib.lines.Line2D at 0x27299405da0>,
<matplotlib.lines.Line2D at 0x2729941a710>],
‘caps’: [<matplotlib.lines.Line2D at 0x272993f8cc0>,
<matplotlib.lines.Line2D at 0x272993fdc18>,
<matplotlib.lines.Line2D at 0x2729940fd30>,
<matplotlib.lines.Line2D at 0x2729940fe48>,
<matplotlib.lines.Line2D at 0x27299421f60>,
<matplotlib.lines.Line2D at 0x27299428eb8>],
‘fliers’: [<matplotlib.lines.Line2D at 0x27299405c88>,
<matplotlib.lines.Line2D at 0x27299415eb8>,
<matplotlib.lines.Line2D at 0x2729942ef28>],
‘means’: [],
‘medians’: [<matplotlib.lines.Line2D at 0x272993fdd30>,
<matplotlib.lines.Line2D at 0x272994156a0>,
<matplotlib.lines.Line2D at 0x27299428fd0>],
‘whiskers’: [<matplotlib.lines.Line2D at 0x272993f2a90>,
<matplotlib.lines.Line2D at 0x272993f8ba8>,
<matplotlib.lines.Line2D at 0x2729940acc0>,
<matplotlib.lines.Line2D at 0x2729940add8>,
<matplotlib.lines.Line2D at 0x2729941ae80>,
<matplotlib.lines.Line2D at 0x27299421e48>]}

Group 2基本上不需要任何时间就能解决,这表明问题是非常简单和直接的。企业需要去看看这些问题然后给客户提供一个自服务的路径(产品帮助、在线帮助)而不是浪费客户代表的时间。

In [7]:

plt.cla()
plt.boxplot([[raw_data[“REOCCUR_RATE”][raw_data.GROUP==0]],
             [raw_data[“REOCCUR_RATE”][raw_data.GROUP==1]] ,
               [raw_data[“REOCCUR_RATE”][raw_data.GROUP==2]] ],
           labels=(‘GROUP 1′,’GROUP 2′,’GROUP 3’))

Out[7]:

{‘boxes’: [<matplotlib.lines.Line2D at 0x27299485c88>,
<matplotlib.lines.Line2D at 0x27299499e80>,
<matplotlib.lines.Line2D at 0x272994b07f0>],
‘caps’: [<matplotlib.lines.Line2D at 0x2729948eda0>,
<matplotlib.lines.Line2D at 0x27299494cf8>,
<matplotlib.lines.Line2D at 0x272994a4e10>,
<matplotlib.lines.Line2D at 0x272994a4f28>,
<matplotlib.lines.Line2D at 0x272994bc780>,
<matplotlib.lines.Line2D at 0x272994bcf98>],
‘fliers’: [<matplotlib.lines.Line2D at 0x27299499d68>,
<matplotlib.lines.Line2D at 0x272994a8f98>,
<matplotlib.lines.Line2D at 0x272994c2ef0>],
‘means’: [],
‘medians’: [<matplotlib.lines.Line2D at 0x27299494e10>,
<matplotlib.lines.Line2D at 0x272994a8780>,
<matplotlib.lines.Line2D at 0x272994c20f0>],
‘whiskers’: [<matplotlib.lines.Line2D at 0x27299485b70>,
<matplotlib.lines.Line2D at 0x2729948ec88>,
<matplotlib.lines.Line2D at 0x2729949eda0>,
<matplotlib.lines.Line2D at 0x2729949eeb8>,
<matplotlib.lines.Line2D at 0x272994b0f60>,
<matplotlib.lines.Line2D at 0x272994b6f28>]}

Group 2有非常高的复发率,这些问题需要进行分析去看看产品质量如何改进以防止这些问题再次发生。

In [8]:

plt.cla()
plt.boxplot([[raw_data[“REPLACEMENT_RATE”][raw_data.GROUP==0]],
             [raw_data[“REPLACEMENT_RATE”][raw_data.GROUP==1]] ,
               [raw_data[“REPLACEMENT_RATE”][raw_data.GROUP==2]] ],
           labels=(‘GROUP 1′,’GROUP 2′,’GROUP 3’))

Out[8]:

{‘boxes’: [<matplotlib.lines.Line2D at 0x27299526e10>,
<matplotlib.lines.Line2D at 0x27299538f98>,
<matplotlib.lines.Line2D at 0x2729954e978>],
‘caps’: [<matplotlib.lines.Line2D at 0x2729952ef28>,
<matplotlib.lines.Line2D at 0x27299532e80>,
<matplotlib.lines.Line2D at 0x27299544f98>,
<matplotlib.lines.Line2D at 0x272995497f0>,
<matplotlib.lines.Line2D at 0x2729955a908>,
<matplotlib.lines.Line2D at 0x2729955aa20>],
‘fliers’: [<matplotlib.lines.Line2D at 0x27299538ef0>,
<matplotlib.lines.Line2D at 0x2729954e860>,
<matplotlib.lines.Line2D at 0x2729955fa90>],
‘means’: [],
‘medians’: [<matplotlib.lines.Line2D at 0x27299532f98>,
<matplotlib.lines.Line2D at 0x27299549908>,
<matplotlib.lines.Line2D at 0x2729955f278>],
‘whiskers’: [<matplotlib.lines.Line2D at 0x27299526cf8>,
<matplotlib.lines.Line2D at 0x2729952ee10>,
<matplotlib.lines.Line2D at 0x2729953ff28>,
<matplotlib.lines.Line2D at 0x27299544780>,
<matplotlib.lines.Line2D at 0x27299555898>,
<matplotlib.lines.Line2D at 0x27299555fd0>]}

Group 1具有非常广的替换率,它不能给出任何实际可以操作的模式。

Group 2没有任何的替换,这是非常棒的。现在看到的组级别的一些倾向,我们可以基于这些分析做一些组级别的决策。例如Group 2呼叫了很多次,但是解决基本不需要花时间,因此我们可以对Group 2利用自服务。Group 1则不同,呼叫的次数少,但是花了很多的时间去解决,并且有很高的替换率以及复发率,我们可能需要去看看产品是否有问题或者已修复问题是否还在发生。

这就是我们如何利用聚类和预测分析去将我们的问题进行分组,然后基于组进行分析。

—  本系列文章完结  —

  • Mar 16 / 2018
  • 0
Data, Enterprise

锐眼洞察 | 预测性客户分析Part 3——客户终生价值(翻译)

作者:Ryan Aminollahi

原文:Predictive Customer Analytics — Part 3

译者:TalkingData研发副总裁 阎志涛 

本译文禁止商用,转载请注明来源!

译者注:本文共分四部分,本篇文章为第三部分。

在第二部分,文章介绍了如何用预测分析去获取客户,但由于商业的黄金定律是“从现有客户获取价值的成本比新客户要低的多”,所以就需要了解现有客户的客户终生价值(Customer Lifetime Value,CLV),从而最大化地从现有客户获取足够的收入。

本篇将会介绍如何用线性回归模型,基于老客户历史数据与客户生命周期的关联关系,建立线性回归模型,从而预测新客户的终生价值,进而开展针对性的活动。

客户终生价值

在商业领域所有人都认可一句话:

“我们80%的收入来自于20%的客户。卖给现有客户的成本比寻找一个新的客户低10倍。”

不同的客户为一个企业产生不同水平的销售收入。我们需要识别和培育一些顶级客户从而保证稳定收入。但主要问题是:

  • 过去的收入如何预示未来的收入?
  • 我们过去最好的客户在未来还会是我们最好的客户吗?
  • 这是我们手中的结果吗?

我们想要识别能够给我们带来重要业务的客户并且培育他们,同时确保他们对我们满意。

我们需要一个计算客户终生价值的方法。回到用例,客户刚刚从我们这里购买了一台笔记本电脑。那么,我们期望从他那里得到什么样的未来收入?他刚刚购买了一个笔记本电脑,因此他在接下来的三年可能不会再买,但是等一下,他可能每年都会不定期购买软件版本升级。他可能会根据初始的购买情况,复购比如耗材等等。

当他的孩子们到中学或者高中时,可能需要一个笔记本电脑。当他们进入大学可能需要购买更多的东西。我们需要了解他们的人口统计学和家庭信息才能知道这些生活事件什么时候发生。

一般来说,他可能在感恩节或者圣诞节给他人购买礼物,会送一台笔记本电脑或者其他的,这些就是潜在的年度购买。如果我们能够识别这些事件,我们就能够通过这些重复性购买需求和年度需求估计出他未来总的商业价值。

构建客户周期分类

最早期的基本客户管理流程是,根据他们过去的业务和观察到的未来业务情况,将客户归入不同分类当中,比如青铜客户和黄金客户。然后帮助业务针对性瞄准这些客户。当一个新的或者潜在的客户被识别出来,在业务周期中尽早对其进行分类可帮助企业将更多资源集中在具有重大未来价值的客户上。

根据一个客户(称为X)的人口统计特征,他可能有资格成为黄金客户,因为他会为他和他的家庭购买高端电子产品。另一个客户(称为Y)则可能更关注预算,未来五年可能不会在电子产品上花费太多,因此他将成为一名铜牌客户。鉴于此,我们希望将营销资源专注于X,以产生最大回报。这个用例的目标是建立一个预测模型,将新客户分类为白银、黄金或白金。

鉴于我们专注于新客户,数据集应该是容易从新客户获得的数据集。因此这个数据集就是客户的人口统计学信息,其次是他们的第一次购买信息,如产品、金额、时间、退货、保修等等。训练数据还会有一个客户分类,用于说明老客户属于哪个类别。这是一个经典的分类问题,任何以前的相关算法都可以完成这项工作,如随机森林。

我们将建立一个模型,根据客户属性以及首次购买交易数据预测客户分类,并为每个客户提供他的类别。行动计划是,当客户进行新购买时,我们将使用此算法将他们分类为一个或多个类别。然后,这些分类可以被我们的营销或客户管理团队用来进行差异化的处理,以便在随后的访问中产生更多收入。

我们的客户服务团队还可以借助这个分类来提供高级支持。了解我们最好的收入来源可以帮助培育客户并从客户那里获取更多的收入。

发现响应模式

当客户从我们这里购买了服务或者商品,然后随机切换到另一个企业购买同样的服务或者商品,这对我们是一种伤害。我们希望客户能从我们这里购买更多的产品和服务。因此,我们可以通过优惠券、特殊优惠、促销、套餐、折扣等各种方式与客户保持联系。

所有客户是否都以同样的方式回应这些优惠?不。很有可能X会对圣诞节期间获得的优惠券更感兴趣,以便他为家人购买礼物。

了解客户如何回应我们的优惠有助于将营销资金锁定在最有可能回应的客户身上。这个用例的目标是确定我们的客户响应优惠的不同模式。我们将客户分为不同聚类。然后,确定这些聚类或团体共有的模式,制定营销计划,从而使得每一个集群或者团体都产生更好的收入。用于此用例的数据将是客户人口统计数据以及客户的购买历史记录。

它还包括所提供的优惠的数据,例如提供的优惠活动、优惠针对的产品、提供的折扣、提供优惠的渠道、客户是否检查了优惠以及是否真的使用该优惠?所使用的算法将是K-Means聚类或该算法的任何变种。我们将使用人口统计数据以及优惠相关的数据来构建聚类和群组,然后将其用于我们的分析。

我们会使用客户人口统计数据来建立客户群组。 一旦确定了群组,我们的营销部门可以进一步分析各个群组,了解他们的响应模式以及他们之所以区别于其他分组的因素,它可能是人口统计学因素、购买的产品的因素、季节性因素或其他。 我们对客户行为了解越多,就越能设计相应的产品和优惠,并从客户那里获得更多收入。

预测客户终生价值

客户终生价值是一种货币价值,它表示客户在与企业关系的整个生命周期内提供给企业的收入金额。如果我们提前知道X将在未来五年内带来1万美元的收入,而Y只能产生500美元的收入,那么我们可以在X上花更多的营销资金并收获他的全部潜在预算。使用客户终生价值标记每个客户有助于业务专注于那些能够在未来带来最高收入的客户。

计算客户终生价值时有几种计算方法,但我们只能对与企业有重大购买历史的客户可靠地计算CLV。 但是我们如何才能为最近的客户进行计算呢? 预测分析就在这里提供帮助。这个用例的目标是建立一个回归模型,该模型可以根据他或她最近的购买模式来预测新客户或最近客户的客户终生价值。

随着可用数据越来越多,它将帮助我们更准确地计算CLV。 客户终身价值取决于最近的能够显示购买频率的数据。 因此,我们将创建一个数据集,提供所有老客户的前六个月每个月的购买货币价值, 目标属性是整个生命周期中客户的实际CLV。

根据我们的业务和我们所拥有的历史数据,CLV可以在有限的时间内进行衡量,比如两年左右。 这里使用的算法将是线性回归。 前六个月的数据将成为预测变量,CLV是目标变量。 该分析将提供一个可用于为新客户计算CLV的公式。 通过使用这些数据的子集,我们实际上可以生成这个方程的不同部分,比如只有第一个月,然后是前两个月等。

随着客户生命周期的延长,更多的数据意味着更高的准确性。一旦在我们的系统中捕获到新客户,我们根据第一个月的数据计算CLV,随着越来越多的月份,我们可以通过越来越多的数据来完善CLV。我们的销售人员、服务人员和营销人员可以使用CLV值来识别拥有高CLV的客户,并为他们提供差异化的服务和优惠。

总而言之,本用例显示了如何根据相似的老客户的CLV预测新客户的CLV。

预测CLV的用例

我们将看到如何根据现有客户数据模型来预测新客户的客户终生价值。

我们有这些客户产生的前六个月收入,第一个月到第六个月,他们产生的收入以及客户终生价值。这或许是他们3年产生的总收入,这可以根据客户留在我们业务中的时间来确定。 这即是我们要使用的数据,我们将用它来构建一个线性回归模型,然后用它来预测客户终生价值。

我们首先导入一组Python、Pandas和Skylearn库,然后加载history.csv文件。查看文件以确保所有的数据元素都已被加载为整数,因为这些元素要求它们是整数。在顶部过滤器卡上做一个表头,以确保它们是否都已正确加载。然后,我们进行前六个月的数据和CLV之间的相关性分析。

from pandas import Series, DataFrame
import pandas as pd
import numpy as np
import os
import matplotlib.pylab as plt
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
import sklearn.metrics
raw_data = pd.read_csv(“history.csv”)
raw_data.dtypes

CUST_ID int64
MONTH_1 int64
MONTH_2 int64
MONTH_3 int64
MONTH_4 int64
MONTH_5 int64
MONTH_6 int64
CLV int64
dtype: object

raw_data.head()

进行相关性分析

cleaned_data = raw_data.drop(“CUST_ID”,axis=1)

cleaned_data .corr()[‘CLV’]

我们丢弃掉客户ID列,因为我们的模型构建不需要它。可以看出,相关性分析在不同月份显示出非常好的相关性,我们继续前进并建立一个模型。我们首先通过使用Skylearn类库中可提供的训练测试切分能力将数据切分为90:10的比例。我们打印出大小以确保一切看起来都不错。

predictors = cleaned_data.drop(“CLV”,axis=1)
targets = cleaned_data.CLV
pred_train, pred_test, tar_train, tar_test = train_test_split(predictors, targets, test_size=.1)
print( “Predictor — Training : “, pred_train.shape, “Predictor — Testing : “, pred_test.shape)

Predictor - Training : (906Predictor - Testing : (106)

然后,我们建立一个模型,从线性回归模型开始,通过拟合建立一个模型,打印系数和截距。这给了我们实际的方程,即线性回归方程。然后我们可以利用测试数据对预测进行测试。紧接着我们看看回归模型的自动评分,它告诉我们如何创建模型列表。这个结果的准确率达到了91%,非常赞!

#Build model on training data

model = LinearRegression()

model.fit(pred_train,tar_train)

print(“Coefficients: \n”, model.coef_)

print(“Intercept:”, model.intercept_)

#Test on testing data

predictions = model.predict(pred_test)

predictions

sklearn.metrics.r2_score(tar_test, predictions)

Coefficients: 
[ 34.59195048  11.53796271  15.17878598  11.72051702   8.60555913
  5.44443443]
Intercept: -199.535985333

Out[7]:

0.91592106093124581
它显示了91%的准确度,这是预测CLV的一个极好的模型。

现在我如何预测新客户? 假设有一位与我们在一起3个月的新客户。我们拿出他的前三个月的收入,基于它建立所有价值的数组。我们有前3个月的价值,接下来的3个月将是零, 我们用它来打印CLV。

new_data = np.array([100,0,50,0,0,0]).reshape(1, -1)
new_pred=model.predict(new_data)
print(“The CLV for the new customer is : $”,new_pred[0])

The CLV for the new customer is : $ 4018.59836236

这就是我们如何为CLV建立一个线性回归模型,以及用它对我们的新用户进行CLV的预测。

  • Feb 27 / 2018
  • 0
Data

锐眼洞察 | 预测性客户分析Part 2——推荐触达客户的最佳渠道(翻译)

作者:Ryan Aminollahi

原文:Predictive Customer Analytics — Part 2

译者:TalkingData研发副总裁 阎志涛 

本译文禁止商用,转载请注明来源!

译者注:本文共分四部分,本篇文章为第二部分。

你会变成我的客户吗?

企业如何获取客户?他们需要遵循哪些步骤?

首先,企业需要识别他们的市场以及潜在客户。企业需要识别他们并且将他们作为潜在客户。然后,企业需要通过合适的广告或优惠来触达潜在客户,这需要有效和高效的沟通渠道。企业应该吸引潜在客户去访问在线站点并且查看他们产品和服务。

当潜在客户对产品发生兴趣时,企业应该让客户参与进来,回答他们的问题,并且给出报价来协助他们购买产品。

高倾向潜客

我们有一个产品,例如一个高端的笔记本电脑。谁是更有可能购买我们产品的客户?是那些有家庭和体面收入的中年人?还是那些收入比较低的大学生?这个推论是基于他们的人口统计学特性得来的。所有营销部门面临的第一个巨大挑战就是识别出更有可能购买产品的潜在客户。

这个用例的目标是给我们营销部门识别出的潜在客户生成一个购买倾向评分。倾向评分可以是二进制表示的0或者1,或者可以更好一些,它可以是个从0到1中的连续数值。我们需要使用什么样的数据呢?在这个阶段,唯一可用的数据集是潜在客户的人口统计学特性,比如年龄、薪水、家庭等属性。

关于事件,这些潜在客户可能已经参与或还没参与到我们企业的任何活动当中,因此事件数据变为了可选的数据。使用它的一种方式是用二进制的标识,比如潜客是否浏览过我们的网站:

  • 他/她是否回复过我们的电子邮件?
  • 他/她是否对我们的企业或者产品发过推文?

当然,所有这些历史数据都会打上过去活动最终效果的标签。我们该使用什么样的算法来尝试?我们可以使用回归来生成一个倾向评分或者使用朴素贝叶斯分类来给出一个转化为购买的可能性。

理想情况下,我们希望得分在0和1之间。用这个模型来对我们的潜在客户进行评分。然后营销部门可以整理这个清单,根据分数将其清除或根据分数生成一个top X的列表。

那么这样做的价值是什么呢?我们可以定期执行此用例,或者当我们的市场部准备了一个潜在客户列表。我们使用以前的数据来建立倾向模型,然后基于该模型,我们为每个潜在客户生成一个分数。然后,我们的营销部门将使用这些信息想潜在客户提供优惠和促销。

推荐触达的最佳渠道

一旦我们有一个潜在客户名单,我们需要决定如何与他们进行最佳的沟通。有多种渠道可供使用,例如电话、电子邮件、手机、互联网或者社交媒体上的定向广告。

但不同的人对不同的媒体有不同的反应。有人喜欢关注他收到的营销电子邮件,总会点击并阅读;有的人则相反,他会将这些电子邮件过滤到垃圾文件夹中;也有人倾向于在网页浏览中点击基于其近期搜索推送的弹窗广告。

这个用例的目标是推荐联系潜在客户的最佳渠道。很多媒介以这种方式去锁定客户,因为这样能够获得最高的关注度并且获得最高的投入产出比。那我们该使用什么数据呢?与潜客相关的数据最为常见,我们还应该使用以往成功的营销活动的数据,在这些营销活动中,我们通过特定渠道、触达了特定潜在客户并实现了潜客转化。

这些数据告诉我们哪些人通过哪些渠道转化。利用这些数据,我们可以构建一个模型去预测未来潜客的触达渠道,随后用这个模型对潜客的未来行为进行预测。

我们将要使用什么算法呢?这是一个经典的分类问题,因此我们会采用以前的相关算法去实验其精确度。我们利用过去的数据构建了一个模型,为每个潜在的客户推荐一个进行触达的媒介。

那么这么做的价值是什么呢?我们将会使用过去的数据去构建一个分类模型,用这个模型去对每个潜在客户预测最佳的触达渠道。这将会帮助我们的营销团队去设置针对性的活动,帮助他们通过特定的渠道触达特定的潜在客户。

按照访客购买倾向提供聊天

我们有网上的销售代表随时准备与访问者建立联系,并且吸引客户购买我们的产品。但是通常我们有太多的网站访问者,而且他们大部分是只看不买的人。我们希望我们的销售代表只与那些真正想要购买的访客进行聊天,我们不想浪费我们销售代表的时间。

想象一下,客户比较产品,例如笔记本电脑。这意味着他/她做了决策吗?他/她开始阅读商品评论,他对购买是认真的吗?他/她正在查看我们的售后保证条款,这意味着他/她做了决策吗?我们如何判断呢?

这个用例的目标是根据客户在我们网站上的实时行为,反复预测一个客户的购买倾向。当客户在我们网站进行活动时,我们想要持续计算和修正倾向得分。这个用例的数据源是潜客的属性数据以及潜在客户在访问我们网站时进行的活动数据,包括他检出的产品,他的相关行为。例如,是否查看过评论?比较过商品?对售后保障是否有兴趣?这些是通过在浏览器上的网页点击事件来衡量的。

我们需要使用每个潜在客户过去每次的访问数据,以及访问的最终结果,比如他是否进行了购买。

朴素贝叶斯将会是最适合的算法,因为它提供了一个概率分数。我们会使用过去的数据,包括客户的人口统计学数据、网站行为数据,利用朴素贝叶斯算法构建一个倾向性模型。然后我们使用这个倾向性模型去预测我们现在网站的访问者的购买倾向性。那么,这么做的价值是什么呢?我们基于过去的数据构建一个离线模型去根据一个客户在网站的行为建立一个倾向分。

当一个新的潜客访问我们的网站时,网站点击事件会被持续收集。每次当一个新的事件被收集时,例如查看评论或者比较商品,模型会根据收集到的数据进行运行而重新计算一个倾向分。当倾向分达到特定的阈值时,在线商店可以做出决定去触发聊天,这是我们可以通过原型来验证的东西。

我将会给大家展示如何用Python实现这个用例。

我们将会实现实时预测我们网站访问用户的倾向评分的用例。当访问者到我们的网站时,他们开始浏览产品并且检出不同的链接。我们想要做的是基于他们的活动,实时预测他们的倾向评分,决定我们是否需要提供他们在线聊天。

如下是客户浏览的样例数据:

这个数据包含不同用户过去的所有的会话的信息,它包含一个session id,以及一系列的布尔型变量,这些变量将会变为我们的特征变量。这些布尔型变量是根据访客的行为而生成的1或者0。

images的含义是访问者是否浏览过产品的图片,reviews代表访问者是否真正浏览过产品的评论。类似的,我们有FAQ、specs、shipping、bought_together、comparison of products等等属性。最终,有一个目标变量,代表着访客最终是否购买了产品或者没有购买产品。这将会是我们用户构建这个模型的数据集。

在真实世界,如果我们想要获得真正高精度的预测,我们需要一个非常巨大的数据集。我们从输入一系列python库,以及输入browsing.csv到一个叫做prospect_data的dataframe开始。

`from pandas import Series, DataFrame
import pandas as pd
import numpy as np
import os
import matplotlib.pylab as plt
from sklearn.model_selection  import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import classification_report
import sklearn.metrics
prospect_data = pd.read_csv("browsing.csv")
prospect_data.dtypes`

然后我们会看一下数据类型,确认数据是否被正确装载。

SESSION_ID int64
IMAGES int64
REVIEWS int64
FAQ int64
SPECS int64
SHIPPING int64
BOUGHT_TOGETHER int64
COMPARE_SIMILAR int64
VIEW_SIMILAR int64
WARRANTY int64
SPONSORED_LINKS int64
BUY int64
dtype: object

这份数据包含用户在他浏览网站过程中点击的不同的链接的信息。这是用于构建模型的过去的数据。

  • Session ID:浏览web会话的唯一ID。
  • Buy:潜在用户在结束时是否购买了商品。
  • 其他列: 0或者1表示潜在用户是否访问了特定的页面或者进行了特定的活动。

#对数据进行汇总统计分析

prospect_data.describe()

为此,我们将在这个课程中使用纯粹的测试条方法,我们将按照70/30的比例进行分割。我们会检查比例大小是否与我们预期的一致,350比150应该是正确的。紧接着,我们将进入模型构建过程。我们使用sklearn库中含有的naive_bayes算法——高斯naive_bayes。我们首先创建naive_bayes分类器,然后使用拟合方法构建模型,将其应用于训练预测分析以及训练目标中。

进行关联分析

prospect_data.corr()[‘BUY’]
SESSION_ID 0.026677
IMAGES 0.046819
REVIEWS 0.404628
FAQ -0.095136
SPECS 0.009950
SHIPPING -0.022239
BOUGHT_TOGETHER -0.103562
COMPARE_SIMILAR 0.190522
VIEW_SIMILAR -0.096137
WARRANTY 0.179156
SPONSORED_LINKS 0.110328
BUY 1.000000
Name: BUY, dtype: float64

观察上边的关联信息,我们可以看到一些特征比如REVIEWS、BRO_TOGETHER、COMPARE_SIMILIAR、WARRANTY 和SPONSORED_LINKS与目标变量有一定的关联性。我们将会减少特征去使用这些变量。

#Drop columns with low correlation
predictors = prospect_data[[‘REVIEWS’,’BOUGHT_TOGETHER’,’COMPARE_SIMILAR’,’WARRANTY’,’SPONSORED_LINKS’]]
targets = prospect_data.BUY

训练和测试分片

我们现在将把数据按照70:30切分为训练集和测试机,去构建和验证模型。

pred_train, pred_test, tar_train, tar_test = train_test_split(predictors, targets, test_size=.3)
print( “Predictor — Training : “, pred_train.shape, “Predictor — Testing : “, pred_test.shape )
Predictor - Training :  (3505) Predictor - Testing :  (1505)

构建模型和检查准确度

from sklearn.naive_bayes import GaussianNB
classifier=GaussianNB()
classifier=classifier.fit(pred_train,tar_train)
predictions=classifier.predict(pred_test)
#Analyze accuracy of predictions
sklearn.metrics.confusion_matrix(tar_test,predictions)
array([[7618],
      [2432]])
sklearn.metrics.accuracy_score(tar_test, predictions)
0.71999999999999997

我们可以做一个概率预测来显示一个潜在客户购买产品的概率,而不是做一个Yes/No的预测。

pred_prob=classifier.predict_proba(pred_test)
pred_prob[0,1]
0.35088586866049354

如上的概率可以理解为有35%的可能性这个潜在客户会购买产品。

实时预测

现在模型已经构建好了,让我们将它用在实时预测上。当我们的客户开始一个个访问我们的页面时,我们收集访问的列表然后用它来计算概率。当每一个点击进来时,我们都会做预测。

潜在客户刚刚来到我们的网站,因此没有有用的点击。让我们计算他的概率,传递的数组应该包含REVIEWS、BOUGHT_TOGETHER、COMPARE_SIMILAR、WARRANTY和SPONSORED_LINKS的值,所以这个数字在开始所有的值都是0。

browsing_data = np.array([0,0,0,0,0]).reshape(1-1)
print(“New visitor: propensity :”,classifier.predict_proba(browsing_data)[:,1]
New visitor: propensity : [ 0.03961746]

因此最初的概率是4%。现在假设客户在相似的商品做了比较,数组的值中包含了一个1,因此新的概率将会是:

browsing_data = np.array([0,0,1,0,0]).reshape(1, -1)
print(“After checking similar products: propensity :”,classifier.predict_proba(browsing_data)[:,1] )
After checking similar products: propensity : [ 0.09898671]

概率值上升到了接近10%。紧接着,他查看了评论。

browsing_data = np.array([1,0,1,0,0]).reshape(1, -1)
print(“After checking reviews: propensity :”,classifier.predict_proba(browsing_data)[:,1] )
After checking reviews: propensity : [ 0.57538836]

这个时候概率值超过了50%。我们可以设置一个触发我们和客户聊天的阈值。我们持续地将这个概率与之进行比较,去决定我们是否需要弹出对话框。

这个例子告诉我们如何实时地利用预测分析,去决定一个潜客是否具有高的转化倾向,从而给销售代表弹出一个对话框。

所以,请记住,当这些人继续进来时,倾向是否总是上升并不重要,它甚至可能会下降,这一切都取决于数据是如何。 这样,我们可以随时决定何时提供聊天窗口。

  • Feb 26 / 2018
  • 0
Data

锐眼洞察 | 预测性客户分析Part 1——客户生命周期(翻译)

作者:Ryan Aminollahi

原文:Predictive Customer Analytics — Part I

译者:TalkingData研发副总裁 阎志涛 

本译文禁止商用,转载请注明来源!

译者注:本文分四大部分,将分为四篇发出。

业务是围绕着客户进行构建的,每个企业都需要客户才能生存,客户是企业的收入的来源。勿容置疑,企业的成功与获取客户、培育客户、让客户满意、解决客户的问题、进而从客户那里获取更多收入的能力直接相关。但是企业想要做到这一点,需要能够识别他们的潜在客户。

他们需要弄清楚谁、什么、为什么以及如何(4W)

  • 谁是需要他们产品的潜在客户?
  • 他们需要什么产品?
  • 他们为什么需要这个特定的产品?
  • 客户如何做购买的决定?
  • 企业如何去应对这个?

通常所有的企业都有面向客户的人员,比如销售、市场、以及客户支持人员,他们经常与客户进行交流沟通。

这些人变成了企业面向客户的对外形象。但是企业没办法随时单独联系每一个潜在客户和现有客户,去了解其所需。

可以想象,密切掌握客户所想是非常巨大的挑战。当目标市场非常大时,例如有超过100万的客户,是非常难以保持一对一的关注。而且,随着越来越多的生意转移到线上,企业与客户之间没有了直接联系的方式。

客户散落在全球各地。我们也应该考虑到,比以前更快触达客户所带来的竞争。传统的地域和语言造成的障碍消失了。中国企业也可以非常容易的向美国客户销售产品,例如阿里巴巴。

竞争变得越来越激烈和聪明,。今天的客户对于任何产品和服务都有了更多的选择,而且更换供应商的难度也越来越小。这使得企业面临的处境是需要对其客户将来可能做什么进行理解和计划。

为了这个目标,他们需要预测客户的行为,这里就包含着预测性客户分析。为了领先并且提前行动,企业需要知道他们的客户将来可能做什么。

  • 他们将来会买你的产品吗?
  • 他们会更换为其他供应商吗?
  • 他们对产品满意吗?
  • 他们会不满意吗?
  • 他们会购买更多吗?

企业需要回答这些问题,从而去识别合适的客户、触达他们的正确渠道以及提供正确的方式来他们帮助。

他们需要预测分析。预测性客户分析使用客户数据去构建模型,这些模型帮助预测未来的行为,帮助企业转化和识别客户可能会购买的附加产品,从而达到企业期望达到的目标。

当客户遇到问题时,预测性客户分析将会帮助企业识别解决问题的合适资源,帮助识别可能会离开的客户从而给通过一些措施挽留他们。

利用预测性客户分析,企业可以借助比传统方式更低的成本和更高的效率来实现这一目标。

现在正是进行预测性客户分析的好机会。企业有丰富的数据源可以广泛使用,例如网络博客、社交媒体、聊天、交易记录以及语音记录。另外,今天的大数据技术能够以经济高效的方式进行大规模数据处理、集成以及存储。

我们有不同的方式去理解客户的想法和感受,并且能够通过数据挖掘来建立有效的模型。然后我们可以使用这些模型将业务推向正确的客户并使得他们留在您的业务当中。

客户与企业之间的关系经历一个生命周期。企业为客户提供所需的产品和服务,客户查看企业能够提供给他的需要和需求,所有这一切都开始于需求。想象一下,一个客户需要一个笔记本电脑,他会根据技术规格、成交量以及客户服务评分去进行选择。

然后客户选择了一家店铺去购买笔记本电脑,这是购买过程。当客户完成一个商品购买后,他或者她可能会需要购买附加的东西,例如线缆、充电器、存储等等。客户会持续使用这个产品一段时间,他可能会面临维修和升级配件的问题。当该笔记本电脑的生命周期结束,这个客户可能会从同一家企业购买,也可能会根据他以前的经验和当前的选择从另外一家企业完成购买。

从商业的角度来看,这个生命周期的第一步是获取客户。这个周期涉及广告、针对性营销等等,其目的是为了将客户拉入到自己的店铺。一旦客户购买了产品,企业可能会想要继续推销其他产品,例如线缆、附加服务等等。对现有客户的销售成本要比对全新客户的销售成本低很多。企业需要通过合适的服务和支持来确保客户对产品满意。

当产品的生命周期接近结束时,企业希望通过提供优先交易来重新获取这个客户。请记住,留存客户比获取新客的成本低的多。所以我们看到,这个生命周期对于企业和客户来说都是相似的。客户聚焦于产品的价值而企业更关注收入和客户留存。

将分析应用在客户生命周期中

  • 获取:

客户分析可以通过属性和行为分析来识别出那些更有可能购买产品和服务的客户。客户分析可以识别触达这些潜在客户的正确渠道,如电子邮件、电话或者社交媒体。客户分析还可以用于确定能够打动潜在客户的价格和折扣。

  • 追加销售:

当一个客户购买了一个产品后,他们非常可能会需要一些赠品。例如,一个笔记本电脑购买者可能需要电脑包、线缆以及保修。预测性客户分析可以帮助识别购买这个产品的买家可能会购买的产品和品牌从而帮助企业进行推荐。如果你使用过Amazon或者eBay,你已经体验过这些。在每个产品页的下方,你都会看到一个叫做“购买了这个产品的客户还购买了”的板块。

  • 服务:

分析可以帮助预测产品中的失败模式并指导企业采取主动行动。 它还将帮助选择正确的渠道为各类客户提供服务。 例如,一些客户对电话联系感觉更舒适,而另一些客户喜欢电子邮件。

它可以将客户交于与适合的联络中心代理,来识别最可能不满意的客户并与他们取得联系。

  • 留存:

预测性客户分析可以帮助预防客户流失。它可以识别最有可能离开的客户,并预测他们离开的时间。 这有助于企业在适当的时间采取行动。 预测性客户分析有助于根据客户类型识别获取关注的恰当程序。

因此,预测性客户分析可以帮助企业在客户生命周期的所有阶段以互相作用的方式来吸引客户。

客户数据

预测性客户分析需要承载客户意图和行为信号的数据。识别提供这些信号的正确数据并将它们用于模型构建是非常重要的。

客户与企业之间的关系由下面的四个实体组成:

  • 用户自身
  • 客户购买和使用的产品和服务
  • 与客户沟通的渠道,比如Email、网络聊天
  • 代表公司面向客户的代理,比如销售或者支持人员

对于客户分析,需要两种类型的数据:

  • 实体的属性
  • 实体参与的事件

实体可以是客户、产品、渠道或者代理。

客户的属性包含人口统计学属性、收入、年龄、性别、位置等等。

产品的属性包含类型、价格、质量等等。

渠道的属性包含类型、使用频率以及响应时间等等。

代理的属性包括处理时间、解决率等等。

这些属性包含客户可能会购买什么以及会支付多少钱。

第二类数据是交互数据,这些时间与客户在公司做什么有关。时间带有时间戳,事件包含的交互包括浏览、邮件、聊天、电话等。

它们还包含诸如购买、提交投诉、交付产品和支付等等交易相关的事件。

它们还包含社交媒体活动,客户可能发表推文或者在Facebook上发表关于产品的消息或者回应某个消息,比如点赞或者转发。

例如,客户昨天花了15分钟浏览了公司的网站,查看产品和服务。他或者她昨天发了推文,针对一个合适的产品和服务向他的朋友咨询意见。所有的这些都指向了他具备在近期购买某个产品和服务的意愿。

企业可以借助这些,通过为他或者她提供沟通回答任何问题或者提供一些线索来完成销售。

预测性客户分析的成功之处在于,其决定了企业识别识别属性和活动数据多种数据源,通过获取、挖掘、集成这些数据来构建360度客户认知的能力。

数据越完整,预测越准确。

客户分析过程

预测性客户分析是一个持续优化的模型,它需要在企业内构建一个良好布局的流程来处理和交付。

该流程从确定能够为公司带来帮助的预测性客户分析用例开始。 一旦确定了用例,架构师需要确定可服务于此目的的数据源,然后需要构建数据管道以获取、处理、集成和存储数据。

然后数据科学家需要开展工作来挖掘数据并构建模型。需要在部署之前对模型进行精确度测试。

需要对模型的性能进行监测,并且对模型进行调优。 随着时间的推移,可以添加额外的数据元素以更好的进行预测工作。所有这些工作都需要管理层的认同。一旦有管理层加入,我们将能够获得资源来执行项目。

页面:1234567...20
随时欢迎您 联系我们