image frame

脑洞大开の乱乱想

放下碎碎念,重新出发

vue2.x + ts 经验小结

公司用 ts 写 vue 项目,经过初步的了解记录在此。

重新开始

我们先通过一个全新项目来尝试 ts,通过 vue create ts-vue-demo 再创建过程中选择 ts

初始化之后,看到新增两个依赖:

  • vue-class-component
  • vue-property-decorator

几个开发依赖:

  • @vue/cli-plugin-typescript
  • @vue/eslint-config-typescript
  • typescript
  • vue-template-combiler

其中 vue-class-componentvuejs 官方推出的。

vue-class-component

这里摘录官方的代码,看看怎么用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 固定写法,分别引入 Vue Component
import Vue from 'vue'
import Component from 'vue-class-component'

// 装饰器,本质上是一个函数
@Component({
props: {
propMessage: String
}
})
// class Name 是 App
export default class App extends Vue {
// initial data
msg = 123

// use prop values for initial data
helloMsg = 'Hello, ' + this.propMessage

// lifecycle hook
mounted () {
this.greet()
}

// computed 变成了 get
get computedMsg () {
return 'computed ' + this.msg
}

// method
greet () {
alert('greeting: ' + this.msg)
}
}

看完官方的demo感觉并不复杂,后续有通过基类继承

1
2
3
import Component,{mixins} from 'vue-class-component'
@Component
export class MyComp extends minxins(MyMixin){}

看到这里,github used27.8k star4.2k

从短暂的考察成都来看,官方维护 vue-class-component 还不够强大,实际中使用 vue-property-decorator 更多,作为替代品。

vue-property-decorator

这个是民间维护的,官方推荐的插件。它完全依赖 vue-class-compnent

这个插件提供了几个装饰器和 mixin 函数

  • @Prop
  • @PropSync
  • @Model
  • @Watch
  • @Provide
  • @Inject
  • @ProvideReactive
  • @InjectReactive
  • @Emit
  • @Ref

后两者继承自 vue-class-compnent:

  • @Component
  • Mixins

先看代码 Prop

1
2
3
4
5
6
7
8
// 这里一行代码引入 Vue Componet 和 Prop
impornt { Vue, Component, Prop } from 'vue-property-decorator'

@Component
export defalut class _name_ extends Vue {
@Prop(Number) readonly propA: string
@Prop({ defalut: '' }) readonly propB!:string
}

有一种情况是,通过 prop 获得数据,在页面里 computed 部分使用。

https://github.com/kaorun343/vue-property-decorator

ts 一本通

js 缺什么

  • 类型检查
  • 语言扩展
  • vscode 补全

重塑类型思维。

强类型,弱类型语言。

java C# 等传统高级语言看 js

  • 面向对象,继承,多态,接口,命名空间,变量修饰,构造函数,访问器get set 静态属性
  • 委托
  • 泛型(随意的类型)
  • 反射(看包内的数组,动态分析东西是什么)
  • 集合 数据结构高级动态语言。
  • 动态数组ArrayList Hashtable SortedList Stack Queue 匿名方法
  • 拆箱
  • 多线程 worker

静态语言,动态语言: c++ 和 js

属性偏移量。js动态计算,c++在编译阶段确定属性偏移量。这里放一张图片。

动静语言内部细节对比

动态语言争议大:

  • 类型宽松。语言灵活性。
  • bug可能隐藏。单元测试发现
  • 运行性能差。v8区改善
  • 可读性差。用工具区生成。

试用

1
2
3
npm i -g typescript
touch tsconfig.json
touch index.ts

需要配置webpack ts-loader 等

ts 入门

目前ts 3.7

基本类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// number string boolean
const num: number = 5
const name1: string = "xinbao"

// Array
const list1: number[] = [1, 2, 3] // 常规
const list2: Array<number> = [1, 2, 3] // 数组泛型

const list3: Array<number | string> = [1, 2, 3, "4"]

// tuple 元组  是要求的数组,定义了内部的结构类型

let x: [string, number]

// object
let obj1: { id: number; y: number } = { id: 1, y: 2 }
// 试用联合类型,再 number | undefined

// any

// void

// Null Undefined
const u: undefined = undefined;
const n: null = null;

// never 永不存在的值类型。返回值是抛出异常,不会有返回值的函数表达式,箭头函数的返回值类型

// 类型断言 type assertions
// 明确知道结构
const sV: any = "q";
// let slen: number = (<string>sV).length;
let slen: number = (sV as stirng).length;

枚举

把一组数值 变为 有意义的名字。

用途:抽离常量,单独维护,节省记忆成本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
enum Color {
Red = 1,
Green = 2,
Blue = 4
}
let c: Color = Color.Red

const enum Month {
a = 2,
b = 4,
c
} // 编译之后不显示

let m = [Month.c] // 这部分代码编译之后是 let m = [5 /* c */];

// 也可以反查
let name:string = Color[2]
name // Green

接口 Interface

实现对对象的类型定义,不会编译,再开发阶段起辅助作用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
interface Data {
name: string;
age?: number; // 可选属性
[x: string]: any; // 字符串索引签名
readonly id: number; // 只读
}


function fu(persion: Data){
persion.name
}

interface StringArray {
[index: number]: string
} // 字符串数组
let chars: StringArray = ["a", "b"]

函数类型的接口

1
2
3
4
5
6
7
8
9
10
type Add = (x: number, y: number) => number
let add: Add = (a, b) => a + b

// 混合接口
interface Lib {
(): void
version: string
dost(): void
}
let lib: Lib = (() => { }) as Lib

函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function add4(x: number, y?: number) {
return y ? x + y : x
}
add4(3, 3)
// 默认参数

function add5(x: number, y = 0, z: n) {}

// 剩余参数
function add6(x: number, ...rest: number[]) {
return x + rest.reduce((pre, cur) => pre + cur)
}
console.log(add6(1, 2, 3))

// 函数重载
function add8(...rest: number[]): number
function add8(...rest: string[]): string
function add8(...rest: any[]): any
{
let first = rest[0]
if (typeof first === "string") {
return rest.join("")
}
if (typeof first === "number") {
return
}
}

也包含了 继承 抽象 接口 setter getter等。

类里的属性方法默认是 public。也可以被设置成 private protected.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 类

class Dog {
constructor(name: string) {
this.name = name
}
name: string
run() {}
}

//log Dog.prototype 没有name
let dog = new Dog("w^w")
//log dog

class Husky extends Dog {
constructor(name: string, color: string) {
super(name)
this.color = color
}
color: string
}

// 修饰符 默认 Public
// private protected

class Husky2 extends Dog {
constructor(name: string, public color: string) {
super(name)
this.color = color
}

// 通过添加public 省略
// color: string
}

抽象类 多态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 抽象类,只能被继承,而不能实例化的类
abstract class Animal {
// constructor() {}
eat() {}
}

// let a = new Animal() // 失败,

class Dog extends Animal {
name: string
constructor(name) {
super()
this.name = name
}
run() {}
}

var dog = new Dog("xx")
dog.eat()

类和接口的关系

包含关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 接口约束类的公有成员
// impl - element
// implelement

interface Human {
name: string
eat(): void
}

// 可以定义自己的属性
class A implements Human {
name: string
constructor(name: string) {
this.name = name
}
eat() {}
}

// 接口Man 拓展了另一个接口
interface Man extends Human {
run(): void
}

interface Child {
cry(): void
}

interface Boy extends Man, Child {}

// let boy: Boy = {}
// Type '{}' is missing the following properties from type
// 'Boy': run, name, eat, cry

class Auto {
state = 1
// private state2 = 0
}
interface AutoInterface extends Auto {}
class C implements AutoInterface {
state = 1
state2 = 1
}
class Bus extends Auto implements AutoInterface {}

泛型

实现一个打印函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 可以使用联合类型

function log_a(value: string | string[]): string | string[] {
return value
}

function log_b(value: any) {
return value
}
// 可以使用 any
// 但这样丢失了一些信息,不知道约束关系

// 传入T 返回T
function log<T>(value: T): T {
return value
}

log<string[]>(["1"])

// 类型推断,自动获取
log(["a"])

// 定义函数类型
type TypeLog = <T>(value: T) => T

// 泛型函数
let myLog: TypeLog = log

// 泛型接口,和类型别名等价
interface Log2 {
<T>(value: T): T
}

interface Log3<T> {
(value: T): T
}
let myLog2: Log3<number> = log

泛型类和泛型约束。确实有点难

  1. 函数和类可以借助泛型,支持多种类型,增强程序的扩展性
  2. 不必写多条函数重载,长长的联合类型,增强代码的可读性
  3. 灵活控制类型之间的约束
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 泛型可以约束类的成员
// 泛型类与泛型约束
class Log<T> {
// 不能约束静态成员 静态成员不能引用类类型参数。
run(val: T) {
return val
}
}
let log1 = new Log<number>()
log1.run(1)

// 泛型约束
interface Length {
length: number
}
function log3<T extends Length>(val: T): T {
console.log(val, val.length)
return val
}
log3([1])

基本概念就都结束了。


类型推断

会自动进行推断,从右到左。

上下文类型推断。

1
2
3
4
5
6
7
8
9
// 类型断言
interface Foo {
bar: number
}
// let foo = {} as Foo
let foo: Foo = {
bar: 0
}
foo.bar

兼容性

类型保护

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 类型保护
enum Type {
Strong,
Week
}

class Java {
helloJava() {}
}
class JavaScript {
helloJs() {}
}

// 类型保护函数
function isJava(lang: Java | JavaScript): lang is Java {
return (lang as Java).helloJava !== undefined
}

function getLanguage(type: Type) {
let lang = type === Type.Strong ? new Java() : new JavaScript()

// ugly code.
// if ((lang as Java).helloJava) {
// ;(lang as Java).helloJava()
// }
// 第一种方法 instanceof
// if (lang instanceof Java) {
// lang.helloJava()
// } else {
// lang.helloJs()
// }

// 第二种方法,给class添加 静态
// typeof 类型保护

// if(isJava()){}
}

// 类型断言
// 类型保护
// 能够在特定的区块中保证变量是某种特定的类型。
1
2
3
4
5
6
7
8
9
10
11
// 交叉类型 联合类型
interface DogInterface {
run(): void
}
interface CatInterface {
jump(): void
}
let pet: DogInterface & CatInterface = {
run() {},
jump() {}
}

脱离技术,进入工程化

模块系统

  • es6模块系统

可以导出值和接口。
可以导入。

  • node模块
1
2
3
exports

require()
1
2
npm i -g ts-node
ts-node a.ts

可以通过配置修改编译模式。

编写类库

jquery是amd类库。jquery不支持ts,需要声明文件。

1
npm i @types/jquery -D

DefinitelyTyped 是最大的公共存储库,包括1000多个库文件。也有一个用来管理 TypeScript 定义的 Node.js 流行模块,叫 Typings。

如何写声明文件。

*.d.ts

1
declare function globalLib(options:flobalLb.Options):viod

new in 3.7

optional chaining 可选链

1
2
3
4
5
6
7
8
let x = foo?.bar.baz()

let x = (foo === null || foo === undefined)?undefined: foo.bar.baz()

// before
if(foo&&foo.bar&&foo.bar.baz){}
// after
if(foo?.bar?.baz){}

nullish coalescing
??

1
2
3
4
5
6
7
// after
let x = foo ?? bar()

// before
let x = (foo!==null&&foo!==undefined)? foo: bar()

// 也可以替代使用 ||
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// 函数部分

// 函数重载
function info(a:{name: string}): string
function info(a: string):
{name:string}
function info(){}

// void 定义返回类型 在函数里定义返回类型,就是必须定义返回
function sayMyName(name: string): string {
return name;
}
console.log(sayMyName("gogo"));



// 实现和继承
// implements extends

class dev1 implements IDev {
name = "x";
age = 20; // 可把这行注释掉
}


// extends 是继承父类


// 声明文件和命名空间 declare namespace
// declare 使用第三库需要引入它的声明文件,才能获得代码补全,接口提示等功能


// declare var a
// declare function


// 命名空间
// namespace x{}


// 也可以为其他js库定义 .d.ts 声明文件


declare namespace D3 {
export interface Sele {
Base: string;
}
}
declare var d3: D3.Sele;


// 访问修饰符
// private public protected
// 默认 public
// private 不能再类之外访问
class Anim {
private name: string;
constructor(theName: string) {
this.name = theName;
}
}
// let a = new Anim('cat').name // 私有的无法访问


// protected 和 private 类似。protected 成员可以在派生类中访问
// 从父类继承的自雷里,可以访问 protected


// 可选参数 ?: 非空断言操作费 !.
function aa1(firstName: string, lastName?: string) {}
// 这里传参第二个参数可以省略


// let s = e!.name // 不为空继续访问name属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 泛型 generics
// 定义函数 接口 类 的时候,不预先指定具体的类型,使用的时候再执行类型,增加代码通用性

// 不适用泛型
interface R{
ok: 0 | 1,
data: Future[]
}
//使用泛型
interface Result<T>{
ok: 0|1;
data: T;
}
function g<T>():Result<T>{
const data:any={}
return {data}
}

function gen_fun1<T>(arg: T) {
return arg;
}
// gen_fun1<stirng>("go");


// 带any参数的方法
// 传入参数不一定有length,会报错
function any_func(arg: any): any {
console.log(arg.length);
return arg;
}
// array 泛型
// 参数类型是 array的泛型类型,肯定有length
function any_func2<T>(arg: Array<T>): Array<T> {
console.log(arg.length);
return arg;
}

redis一本通

docker 一条龙

1
2
3
4
5
6
7
8
docker run -p 6379:6379 -d redis:latest
redis-server #跑

docker exec -it xxx redis-cli -h 0.0.0.0 -p 6379 # id要换成自己的
> ping #Pong 测试
> set name xinbao # 设置 获取值
> get name
> info # 查看信息
阅读更多...

axios

概念

axios 有一点好,可以在浏览器和node环境中使用。

在浏览器中使用 ajax,在node中使用 http 发送请求。支持promise,可拦截可取消

快速入门

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const axios = require('axios')
// url get
axios.get('/user?v=2').then(res=>{}).catche().finally()
// get 带参数
axios.get('/user',{params:{ID:1}}).then().catch().then()
// async/await
async go(){
try{
const res = await axios.get('/user?v=2')
}catch(err){log(err)}
}

// post
axios.post('/user',{
a:2,b:1
}).then().catch()

// 执行多个请求
function a1(){return axios.get()}
function a2(){return axios.get}
axios.all([a1(),a2()]).then(axios.spread((acct,perms)=>{}))

api

axios(config)

1
2
3
4
5
6
7
axios({
method:'post',
url:'',
data:{
a:1
}
})

使用 stream 下载图片

1
2
3
4
5
6
7
axios({
method:'get',
url:'',
responseType:'stream'
}).then(res=>{
res.data.pipe(fs.createWriteStream(a.jpg))
})

axios(url[,config])

默认get

1
axios(url)

其他

  • axios.request(config)
  • axios.get(url[,config])
  • axios.delete(url[,config])
  • axios.head

创建一个实例

1
2
3
4
5
6
const i = axios.crate({
baseURL:'',
timeout:1000,
headers:{}
})
i.get()

返回的结构

1
2
3
4
5
6
7
8
var res = {
data:{},
status:200,
statusText:'OK',
headers:{},
config:{}
request:{}
}

默认情况下,axios把 Javascropt 转为json,如果要使用application/x-www-form-urlencoded发送数据。

浏览器可以使用 qs库来编码

node里可以使用 querystring

【持续更新】node.js 里的核心模块

先列举常用的模块

  • fs 文件系统,读写目录,文件
  • Buffer 内置模块,把一些数据变成二进制方便读取和存储
  • http 创建web服务器模块
  • stream 流,数据交互。一边读取一边写入
1
2
3
var b= Buffer.form('a')
b.toString() // 读取
Buffer.concat([a,b]) // 合并buffer

buffer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 创建一个长度为10字节以0填充的Buffer
const buf1 = Buffer.alloc(10)
console.log(buf1)

// 创建一个Buffer包含ascii.
const buf2 = Buffer.from('a')
console.log(buf2,buf2.toString())

// 创建Buffer包含UTF-8字节
const buf3 = Buffer.from('中文')
console.log(buf3)

// 合并Buffer
const buf4 = Buffer.concat([buf2,buf3])
console.log(buf4,buf4.toString())

HTTP

1
2
3
4
5
6
7
8
const http = require("http")

const server = http.createServer((req, res) => {
console.log(req)
res.end("sss...")
})

server.listen(4002)

stream

二进制友好,图片操作

1
2
3
4
const fs = require('fs')
const rs = fs.createReadStream('./img.png')
const ws = fs.createWriteStream('./img2.png')
rs.pipe(ws) // 二合一

node里的签名

这两天用node做二次开发,里面有一个签名的过程,看着和微信开发差不多,这里记录一下具体实践方法。

  1. 把接口参数,按照key升序排列
  2. 按照 k1=v1&k2=v2 的格式拼字符串
  3. 第二步的字符串后拼 secret 值
  4. 对结果进行md5计算

我是这么做的:

  • 配置一个对象
  • 借助 URLSearchParams 排序和拼接
  • md5 计算

技术要点

掌握 URLSearchParams用法

把一个对象作为参数传入实例。
其实也可以引入 querystring 内置库

1
2
3
const qs = require('querystring');
qs.encode({a:1}) //对象转参数
qs.decode('a=1') // 参数转对象

具体代码大致如下:

1
2
3
4
5
6
7
// 总的流程
function fetchSign(obj) {
let rawStr = objectSortAndParse(obj)
rawStr += ENV.secret
const signStr = md5Sign(rawStr)
return signStr
}
1
2
3
4
5
6
// 拼接 升序
function objectSortAndParse(obj) {
const _url = new URLSearchParams(obj)
_url.sort()
return decodeURIComponent(_url.toString()) // 这里有点坑需要转义回去
}
1
2
3
4
5
6
7
8
// md5 计算
const crypto = require("crypto")
function md5Sign(data) {
return crypto
.createHash("md5")
.update(data)
.digest("hex")
}
1
2
3
4
5
// 获取八位随机字符串
const randomString = require("randomstring")
function rString(number) {
return randomString.generate(number)
}

创建一个自己的cli

要使用到的库

  • download-git-repo 下载仓库
  • ora 等待进度条
  • commander
  • chalk
    package.json .bin/a:b npm link
    如果要删除 ls /usr/local/bin rm /usr/local/kkb

ora

1
2
3
4
5
const ora = require('ora');
const process = ora(`正在下载....${repo}`);
process.start();
process.fail()
process.succeed()

commander

1
2
3
4
5
6
#!/usr/bin/env node
const program = require('commander')
program.version(require('../package').version, '-v', '--version')
.command('init <name>', 'init project')
.command('refresh','refresh routers...')
program.parse(process.argv)

预览

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env bash
npm config get registry # 检查仓库镜像库
npm config set registry=http://registry.npmjs.org
echo '请进行登录相关操作:'
npm login # 登陆
echo "-------publishing-------"
npm publish # 发布
npm config set registry=https://registry.npm.taobao.org # 设置为淘宝镜像
echo "发布完成"
exit

简单的参考案例

github.com/su37josephxia/vue-template

Node.js之基础概念

简介

js单线程,不用在意状态的同步问题,没有死锁

Node.js 不擅长cpu密集服务?

单线程,如果有长时间运行的计算,会让cpu时间片不能释放,不能处理后续,可以适当调整和分解,就能让运算适时释放。
js的一个弱点是位运算,java有int,但js只有double

回答的核心,单线程计算不行,需要及时调整和分解。

如果是纯计算场景,应该采取多线程方式进行计算,可以私用node的c c++拓展,可以比java还快。也可以使用子进程,把一部分node进程常主任吴,进程传递信息。

异步I/O

node.js 是一个 异步 的 事件驱动的 js 运行时。

异步,非阻塞。实际效果都达到了并行I/O的目的。

异步/同步阻塞/非阻塞,是两回事。

操作系统内核对 I/O 只有阻塞和非阻塞。

读取文件天然的会阻塞。阻塞会让CPU等待I/O,浪费性能和实践。

为了解决这个问题,内核提供了非阻塞I/O ,调用之后会立即返回。后面轮询重复调用判断来获取完整数据。

轮询本质还是同步,浪费时间,node提供 libuv 作为抽象层,跨平台地实现了异步I/O

node的异步I/O

异步api:

  • 定时器 setTimeout setInterval
  • process_nextTick() setImmediate

定时器有问题。时间是非精确的,如果上一次循环占用时间多,会推迟下一次任务。

使用process.nextTick() 会把回调函数放入队列。时间复杂度比较低。

setImmediate() 和nextTick 类似,都是延迟回调函数。区别是, setImmediate 慢于 nextTick

process.nextTick属于 idle观察者, setImmediate 属于check观察者
先后关系:idle观察者 > I/O观察者 > check 观察者

如何运行和调试

推荐 nodemon 和 vscode debugger

模块

commonJS 的模块

1
2
3
var math = require('math')
// 另一个文件引入
exports.add=function(){}

内置模块

  • os
  • fs
  • buffer
  • http

fs 模块可以拓展到 util.promisify ,如果别人问你,node12 就开放了 await fs.promise.readFile

buffer

http 模块,可以创建一个服务器

stream 流


本文参考资料:

  • 狼书:更了不起的node.js
  • 深入浅出node.js 朴灵 编著
  • 开课吧资料

开课吧夏老师的id su37josephxia

数据分析师八大能力培养

今天开始看 天善学院,数据分析师八大能力培养

https://edu.hellobi.com/course/272/lessons

这个课程感觉很不一样,不讲工具技术的使用,更多的是从企业角度观察数据分析这个岗位。

以下是零碎笔记,内容已经打散重组。

前置知识

给出一句话,一个场景:“这些7分的90后太拽了”。

这是评价,是感受,不是结论,而且不客观。没有来源,没有采集方式,没有评价标准。

从Data到DataAnalysis

什么是数据:

  • 有数据来源。才哪里来
  • 有采集方式。如何搜集。
  • 有记录格式。如何记录,单位,字段。

因为现实生活中获取真实数据需要花费很大成本,或者不可行,所以要利用技术,利用业务手段去找出规律,预测和总结。

数据分析是一个: 假设-检验-总结-再假设的过程。
数据分析的本质,是把思维建立在事实基础上,通过分析和推理接近答案。

从DA到DA岗位

简单说:

  • 数据分析有用
  • 不是所有企业都需要分析师岗位,数据分析师多有用取决于岗位产生的价值
  • 技能不是关键,分析产生的价值是关键

要了解数据分析在企业的应用,从企业部门说起。

必要性。举例,如果超市要做策划,需要考虑很多问题,策划,系统,供应,业务,宣传等。其中用到数据分析。

数据分析的价值。学习数据分析技能,比如 esp(excel sql python)是一个人的事;从事数据分析师一群人的事,需要理解和谁打交道,要做什么工作。

之所以叫数据分析部门,而不是esp部门,是因为不光是跑数的问题。数据分析的价值是作用决定,而不是技能决定的。

企业不需要esp,需要的是钱:现在的,未来的,包括融资等。相比之下,产品完成之后,销售,营销,供应链,运营才是企业真正关心的问题。

数据分析是企业的刚需,数据分析岗位不是。所以很多传统企业,数据分析岗位是附在某些部门下面,比如销售部门的数据分析,运营部门的数据分析,负责各方数据。

数据分析的工作地位,是岗位发挥的作用决定的。比如:

  1. 公司本身是计算广告行业,岗位就是产品
  2. 辅助其他部门,降低成本,提升利润。推荐系统,外呼系统等
  3. 岗位服务其他部门,去争取资源,减少负担,减轻责任,一个中立的岗位
  4. 按照需求表,跑数据

数据分析就像是给企业看病。有病人,有医生。

病人有的理解配合,有的不配合不尊重数据分析。
医生有的崇拜模型,算法狂热,大数据迷信。不考虑实际情况,只要数据资源。有的知识摆指标,不分析问题。

反例,增长黑客的AARRR,五棍流。经典名言:
运营就是一句话,AARRR够啦
开场插起五根棍,哪根短了就搞他
新客少了狂派券,活跃不足转盘拉
要是手头没经费,写篇文案忽悠下

数据分析是一套组合拳,想解决问题要先理解问题,不要着急翻书,不着急建模。

到底哪八大能力

岗位需要的八大能力,也就是接下来的章节:

日积月累:搜集信息,理解业务背景

分析前: 把问题转化为需求,定义问题选择方法

分析过程:梳理流程,认清现状。明确评判标准。寻找问题解决问题。评估方案给出建议。

分析总结: 阶段性汇报

岗位要做的四大基本工作

临时性取数,报表,专题分析,建模

课程五个案例

销售,活动策划,用户运营,小贷风控,企业招聘案例。感受数据分析如何助力业务,帮助决策。

推荐了 人人都爱数据科学家Python科学实战

1 搜集信息能力

不同岗位负责不同业务

理解业务是最重要的基础。不同岗位负责业务不同。

业务能力等级

业务能力的等级:

  • 理解。理解业务

  • 操作。动手操作一遍

  • 设计。针对需求设计流程

  • 创新。对现有流程进行改进

  • 创造。创造不存在的东西

理解业务

分析师到理解就可以了,不需要过于深入。

要避免的误区:一定要下场。看机器学习,不需要懂业务,只需要懂代码。

  • 为什么不需要下场。做得好不等于分析的好。比如帮助销售,关注的是销售计划,fab,工具使用等。
  • 不理解业务,入门都入不了,给不出专业建议
  • 技术手段也不是万能药。模型,3w神经网络,回归模型,sql等高阶知识,期望值高受挫越大

如果不懂业务,可能会出现一些场景:

客户订单客单价。看销售业绩昨天没达标,原因是客户少。

经典废话,一线工作人员销售看得出来,业绩结果对分析师来说是数字,对销售来说就是钱。

别人买的好,爆款。

销售也想卖,但是没货,没库存。

客户少,做客单价。

为啥人少,能卖就不错了,价高成交率下降。

最终,分析师只是一个跑数工具,没有专业性,对业务没有帮助。工作是理所应当的。

如果不懂业务,进行数据分析会有坑:

案例,卖运动服,运动休闲款,怎么推演需求场景。

没有数据,要采集数据。比如:除了销售数据,还有什么字段。分场景广告有没有跟踪,顾客留言,特定的柜台合作渠道有没有差别。可不要只有pos机流水数据。要根据线索,采集信息,工作才能开展。

案例,互联网金融公司,想引入数据分析,介入人工智能客服,提升客服效率。

三问:客服有销售任务吗。客服有多少人。客服考核kpi是什么。要理解业务模式,如果不是能挣钱的部门,维护产品核心部门,都倾向于降低成本投入。工作的价值要抵得上降低成本的回报。

案例,手机销量受因素影响,做一个综合模型预测备货。

因为市场部权限高,预测不准随意修改了指导方案。给市场部看到,市场部可以提意见但是要留字据。要理解组织架构,分析部开发部知识一个小部门话语权不高。

单纯数据分析岗,碰不到业务,业务知识不会有人教,这需要从业经验积累。

看业务只能看到结果,广告,销售过程看不到。

直接沟通,业务部门和分析师的关注点不同。业务部门说出来的不一定是你关注的。

所以,必须要自己懂业务。

如何懂业务

关注:

  • 哪些业务流程会产生数据。
  • 哪些业务流程会使用数据。
  • 哪些业务流程会影响数据。

理解了数据的来源才能分析。

了解了业务用途才能方便助力。比如做销售计划,使用哪些话术

了解业务效果,才能形成分析思路。比如销售改不了价格,靠话术和技巧,完成任务需要毅力和技巧,需要外貌好看等,找到更多指标。为什么银行柜台需要100w存款,筛选家庭背景好的。

谁(业务部门) 做什么(主要业务动作) 有什么(产生什么数据) 看什么(哪些环节需要数据) 为什么(哪些行为对数据有影响)
业务部门1

以下零碎笔记

理解业务的起点,了解最基础的业务形态

  • 甲方
    • 互联网,找大厂。产品,运营,市场,开发。数据。
    • 传统企业,自身集中核心业务。销售,市场,财务,营运。
  • 乙方。数据分析师核心地位
    • 服务,服务咨询,it咨询,财务调研广告
    • 产品。crm,erp,bi,舆情

要克服不想,不敢沟通的心态。

理解业务的七步成诗法

  1. 业务模式。摸清业务模式,照猫画虎,挣得什么钱。
  2. 四大角色。储备知识,深入讨论的基础。
    1. 产品
    2. 渠道
    3. 用户
    4. 运营
  3. 部门。突破的关键看看请谁,为什么,提这个需求。这些部门kpi是什么,这是工作的核心动力。
  4. kpi。突破的关键看看请谁,为什么,提这个需求。

以经验换情报,锁定部门和kpi,围绕困难点,切磋思路,挖掘真实需求。

理解业务模式

我们挣得什么钱,挣钱模式差异,决定了业务模式的差异。

  • 现金公司。销售产品和服务,卖一份产品,挣一分钱。关键:销量 收入 毛利
  • 圈资金。做产品是为了融资,上市套现。关键:市场潜力,增长速度,估值
  • 骗现金。没有明确的产品,忽悠下家加入。

大部分传统公司都是赚现金公司:

  • b2b 产品服务
  • b2b2c 商场
  • b2c 耐用 快消

现金关注利润。

  • 利润=收入-成本

  • 收入=客户*付费率*客单价

  • 成本=生产成本 销售成本 营销成本 运作成本

  • 提升收入,增加客户数量,高端客户,增加频次

大部分互联网公司是圈资金企业:

增长速度,用户趋势,业务前景,预期收益

关注的是成长:

  • 整体市场空间,占有率,集中度
  • 成长速度,成长质量 用户量 活跃率 转化率
  • 技术壁垒 人才资源 用户池

利润知识一个指标,所以补贴烧钱。

目前,多种模式结合。要理解这种复杂的商业模式,要关注部门的任务。比如腾讯的那个部门,kpi是什么

四大角色

名称可能不同,但角色是有的:产品 渠道 用户 运营。

为什么要理解四大角色:

深入理解业务,弄清任务和分工。

产品看什么:

  • 设计前
    • 有哪些新的需求。有哪些改进点有哪些优化点
    • 同一个产品,分析重复购买和使用量。
    • 多个产品,交叉购买分析
  • 设计中
    • 概念 功能 规格 体验等一系列测试
    • 市场调查,产品测试,了解实物产品使用,体验情况
    • 互联网产品访问行为分析 abtest
  • 设计后
    • 商业效果 销量
    • 市场反馈 口碑
    • 预期实现 用户群
    • 热销榜

一个产品有三类数据: 标签数据,销售数据,使用行为数据

影响产品表现的分析切入点:

  • 长期。用户群体洞察:产品线布局
  • 中期。单品竞争力: 功能 设计
  • 短期。营销和运作:营销包装 渠道支持 宣传配合

渠道。

销售,商务,新媒体广告位等。

为了更好地卖,需要

  • 选择更好的渠道,优化渠道组合
  • 寻找标杆,培养队伍,复制经验
  • 激励士气,鼓舞人心
  • 监督执行,检查效果,末尾淘汰
  • 重奖成功者

渠道有什么

  • 建立接触点。位置标签,销售线索来源从哪里来
  • 展示产品。门店陈列,装修风格,网络广告
  • 促成交易。话术,网络推广词,落地页
  • 跟进订单。跟进数量,时机,跟进形式标签,成果

关注业绩,拆分业绩。 客户数,转化率,客单价。

进行销售分析,做什么,做多少,做到没有。

用户。

产品服务的使用者。

用户消费。首次消费,重复消费

用户转介绍。口碑传播,带动消费

用户互动。线上,线下互动。

用户有什么:

  • 企业用户
    • 企业规模,经营状况,资金情况
    • 需求部门,需求周期,预算范围
    • 采购流程,采购周期,决策机制 比价标准
    • 合同流程 履约情况
  • 个人用户
    • 物理特征 性别 年龄 地域
    • 社会属性,家庭 婚姻
    • 职业特征,从业 收入
    • 需求特征,消费品类 消费习惯

然而,法规保护,个人不想提供。比如换一个身份购买。

用户数据怎么采集,很难:

  • 用户自己填。老子打死不填。可以提交给服务窗口
  • 渠道来填。怎么有利怎么填,数据不真。不会产生直接利益,自己人也会图省事。保留服务记录
  • 第三方提供。合法的无所谓,有用的都犯罪。通过联盟合作授权获取,和渠道合作。花钱买数据
  • 采集数据。爬虫抓取。犯法。花钱买数据,比如填信息给额度优惠。
  • 网站埋点。幸存者偏差,比如优惠吸引,用户围绕优惠互动,没有优惠就流失了,不是正常用户。记录用户行为

所谓大数据,都是运作出来的。比如银行知道你的流水,蚂蚁花呗就不知道。

对数据分析的启示

  • 好数据是运营做出来的
  • 多和渠道 运营沟通合作,相互帮助,提升数据质量,比如接待时候就打好标签。
  • 不要迷信数据,要把问题缩小到用数据解决的范围内

用户分析切入点

做好用户分层,打标签。

  • 潜在客户。低潜力,高潜力
  • 客户。低价值。高价值。生命周期。互动频率。响应度

认识用户的忌讳:

  • 把自己当用户。我体验发现xxx
  • 把客户单该用户。比如小孩想买,家长不给买,爷爷奶奶偷着买,要考虑复杂决策的场景
  • 把想象当成用户。想象中用户是xx品味和阶层
  • 把id当用户。客户喜欢一次买两瓶。是因为新顾客买两瓶立减。

运营。

帮产品做商品管理,产品运营。改善产品体验,优化使用过程。

帮渠道销售前宣传,品牌推广打响知名度,提升档次。销售中,促销吸引购买拉动业绩。售后,小恩小惠提升忠诚度,促进持续消费。

帮用户。提供服务窗口,线下售后服务中心专卖店。线上服务号,app,网站,社群

不同部门,不同服务对象的运营。负责用户 产品 销售。

总结就三件事:

  • 传递信息,能直接推送到用户。
  • 拉动业绩,促销资源。
  • 服务用户,能用户互动。

做好三件事,需要考虑的因素:

  • 用户群特征和需求。用户画像
  • 接触用户的渠道或者用户行为路径,事件节点和机会点。用户行为
  • 响应和转化。用户行为
  • 传递信息:题材和文案包装。拉动业绩:促销方案和方式。服务用户:服务内容。方案评估

大量的分类标签

  • 传递信息。
    • 话题 风格 投放时机 阅读行为标签
  • 拉动业绩
    • 产品动销标签,活动时机,活动主题,促销形式,促销偏好
  • 服务用户
    • 用户分级,需求偏好,行为偏好,行为预测

看什么,和任务有关

  • 传递信息
    • 信息到达率,响应率。知名度,美誉度
  • 拉动业绩
    • 短期业绩提升
    • 长期业绩提升
    • 成本控制
    • ROI
  • 服务用户
    • 用户数量
    • 用户使用率
    • 用户满意度

这三类培训都是专门的课,比如逼格高的文案课。拉动业绩。现场培训

分析指标,标签库,不同的模型

总之,理解业务层面,要了解业务流程。

组织架构和kpi

如何认识组织架构。在岗最简单,看钉钉 oa啥的

不管名字怎么变,找到对应的角色。

入职,了解信息搜集能力。

入职了就内部观察。

面试,打标。

业务模式,可以自己走

  • xxx 行业 十大品牌,找到同行
  • xxx行业 盈利 收入 投资情况,赚什么钱
  • xx行业 发展问题
  • xx行业 201x 展望
  • xx行业 机遇

了解到行业在面对什么,经历什么,看到专有名词就记下来,逐个攻破

入职之后,尽快搞清架构图。如果能接触到监控报表,经营图标,搞定kpi,至少搞明白本部门kpi

从讲的上话的人搞起,搞清楚kpi,做什么。

表中的部门搞清楚。

如果能接触到数据库,看数据是由哪些系统产生的,需求方式谁,使用人事谁,反推业务流程产生什么数据

数据字典,功秋万代。

报表,日报。

还没入职,面试。靠猜,了解业务模式。

自己走一遍流程。

针对渠道的的: 门店,app走起,天猫走起

针对运营的: 服务号,公众号,微博

针对产品的,现场体验,看看身边的使用者,上门

沟通需要过程,设立一个进度表。慢慢推进。

行业特点,运作方式,行业基本数据,排名,走势

企业特点,已经发生的公布的数据 政策 行动

以上是公开的

行业的经营数据,个人隐私,竞争对手相关的计划等。这些是秘密。

说大不说小,不说具体企业。说公开的。

2 沟通需求能力

很忙,很多人投诉,销量好,赶紧做等都是数据需求,给数据。

在处理数据的时候,就可以打标签了。

列出数据,分析问题,分析过程,分析结论

问一个问题,先问是什么,沉住气。弄清基本情况。

谁,什么部门提需求,需求发时间,期望需求完成时间,需求的背景,需求的标题(方便归类合并)

为什么要忙,不走流程,需求单。

这和医院看病要先花钱挂号,合理安排资源,过滤无效不重要请求。

需求:

  • 是什么,评估类。比如 各渠道表现如何,推广效果如何,用户群体特征
  • 为什么,原因类。为什么销量不好,为什么推广效果不好,为什么女性用户偏多
  • 会怎样,预测。预计活动有多少人,会有多少人来。

标准。比如这个月比上个月指标低,标准是什么

需求:

  • 是什么
    • 评价的维度,评价标准,评价权重
  • 为什么
    • 问题是否真实存在。是否有假设。考虑与行动有关的关键因素
  • 会怎样
    • 预测的前提要清晰。假设获得业务方认可。考虑与行动有关的关键因素。

需求单需要正是确认,如果有修改需要注明。如果对方不谢,自己写让对方确认,留字据。

需求排班管理

不是随便丢需求,要合理调度。

我们需要一个排期表。需要

编号。需求部门。需求人。提出时间。期望完成时间。需求目的。复杂度评估。预计工时。

自己也要统计每天关注的问题,每周,每月

升级需求:

临时性取数 统计数据 指标体系 监控报表 分析专题

  • 从一个指标,到一组指标。信息补全
  • 从原始数据,到一个统计结果。比如名单完成率,方便统筹
  • 从孤立的结果,到一系列监控指标
  • 记录经验的管用范围。比竞品好不好,给产品加标签定量分析
  • 主动探索经验背后的逻辑。做促销,分析促销的力度,参与群体,响应群体。
  • 当经验解决不了,一步步探索可行性。经验不管用,就可以分析标签属性
  • 不管什么情况,不要放弃获取更多数据的机会
  • 在业务认可的背景下,争取资源做产品。把常用模板模型固定起来。

基本原则:

  • 有数据清单,就一定能做统计
  • 统计指标为某个事情服务,就一定有关联指标
  • 只要不是一次性发生的,就可以做报表监控
  • 有了监控报表,解读波动需求,引发专题分析
  • 专题分析有分析成果,选择成果做成产品
  • 数据不满足,能多获取就多获取

如果业务部门不理睬

定期搜集行业数据,发布,业务部门会谈需求

常规报表和kpi绑定

项目结束的背会会,数据分析可以做背书

大屏展示。

模型。

逻辑模型 pest aarrr

推演模型 业绩=abc

查询模型 rfm

算法模型。

  • 时间序列,可以在excel可操作。

有已知,明确的结果。预测(回归,神经网络),分类(决策树,相似度模型),二元响应(逻辑回归)。

无明确的结果。分类(k均值聚类),关联关系(关联分析)。

预测向量 肉眼观测,推算模型,时间序列。

针对已经入职的数据分析师。

编排自己的需求管理表。

需求沟通,需求管理。

根据xx部门业务,xx需求,是什么 为什么 怎么样 数据制作相关分析报告。

  • 是什么:监控了哪些指标,发现了什么问题

  • 为什么:找到了哪些原因,改进了多少

  • 会怎样,预测了什么业务的走势,准确度如何,预测以后做了什么改进

  • 搭建了xx企业销售监控指标体系。
  • 提供30分销售月报,季度专题分析报告
  • 发现并诊断5次重大销售波动,提供优化建议3次
  • 3次新商品上市销售专题分析,提供销售方案优化建议3次以上

3 定义问题能力

定义问题,设计方案。

内行服务外行,不要轻易相信外行的要求,要理解处境,分析需求。

  • 清晰的描述问题
    • 清晰描述问题,分析事情本身
    • 划分清楚问题边界,数据分析能不能解决
    • 细分问题类型
    • 明确输出产物

了解问题的背景,需求。

4 实例流程建立指标

业务发展流程,了解业务流,是分析问题的起点。

事情发生形态,管理流,了解可以怎样影响结果,灌流过程,才能分析

记录事情的数据,数据流。

实例流程,建立指标体系。

部门领导解决问题的两种基本方式:

  • 分块解决,分解目标,各部门承担
  • 线性配合,活跃用户 用户运营 产品运营 活动运营

如果构建指标:

具体到一个部门可以负责,可衡量的kpi。拆解目标,可分解可考核。

aarrr,适合创业公司,圈钱公司的指标体系。盈利不是那么重要。

增长速度,增长质量,盈利能力,传播能力

增长速度(市场推广,销售)

增长质量(运营:产品 用户 社群 内容 活动)

利润:商品运营,销售

传播能力,用户 内容 社群,市场推广

aarrr更常见的形态,转化漏斗。

互联网企业应用比较多,都有记录。可拆解。

销售流程类指标构建

客户,付费,客单价。

真正影响销售结果的东西,你看不到,只能看到促成。

toB的销售流程:

  • 产品培训,公司培训,技能培训
  • 整理名单,分析需求,指定计划
  • 邀约 沟通 示范 促成
  • 跟进

toC的销售流程:

  • 产品培训 公司培训 技能培训
  • 产品铺货,门店陈列,宣传预热
  • 迎客,沟通,示范,促成
  • 跟进

数据少。如果中间过程没有数据,没办法分析。

乱瞎填。数据造假。

乱管理。

靠的是渠道管理+数据简化

加强渠道管理,弱化数据要求。

了解销售过程,多做标签。比如话术 培训 fab 渠道 邀约方式 标签。

用于运营,crm指标体系

数据不好拿。

用户运营流程

  • 监控用户状况 设定目标 圈定目标用户 分析需求
  • 设计用户任务 设计用户奖励
  • 选择沟通渠道 选择沟通内容 投放信息
  • 跟踪数据

有了指标能做什么。注意幸存者偏差。

消费和互动数据基于交易,相对靠谱。

常规的 消费率,客单价,页面访问,跳出等指标。

对目标有用的特征: 30天未消费,xx品类爱好者(连续消费x次,累积消费单品x元)

对页面大表情,促销类,产品类,对访问行为贴标签(促销爱好者)

解决问题的关键2 问题找指标

吸引新用户,激活沉睡用户,延长活跃程度,挽留流失用户。

案例,短信通知,落地页,全流程。 可以分析转化路径。

商品管理类指标

一边卖一边补货。

商品管理:

进。宽度sku,深度数量。

销。热销 滞销 动销率 售罄率 销售分布

存。库龄,看库存数量。库存周转率。库存结构。

推荐了一本书,数据化管理,将商品管理

权威准确标准版,国建2025电商行业指标体系规范。企业流程不同,目标不同。

5 定义标准 判断分类

对标准敏感,凡是有归类 ,有好坏判断的,都涉及标准。

越接近结果,越具体,越容器找到含义,容器切分。

等不到结果就得管控过程。管控到什么程度,需要有个微妙的平衡,要综合考虑。

用多少指标衡量问题,业务复杂,技术含量高,素质高,可以多做指标,否则少。

为了指标好理解,还需要分级,权重,多个指标压缩。

平均法,简单,公平。要注意极值。

中位数。

分摊法和平均法使用。看个人贡献比例,多劳多得。还要看以往均值和增速,避免摊派太多。

二八法则,十分位法。

二位

三维。rmf 杜邦分析 漏斗。 量收利, 注册活跃转化。

多维指标,进行权衡。可以考虑数量达标,权重。

77 讲 不同分析方法的适用场景。

从跑表的到行业专家: 针对xx问题考查xx指标,发现指标有xx异动,可以用xx措施解决。

问题,指标,标准,解决。

问题。报表给谁看,谁看。

指标。针对xx问题一共xx个指标。

标准。对比社区发现问题。

解决。通报,竞品分析。

6 寻找原因 探索答案

甩锅路径: 环境 对手 队友

外部环境。PEST

请我喝杯咖啡吧~