Git Cheatsheet

  • 初始化
    git init
  • 克隆远端repo
    git clone <remote_repo_url> <local_repo_name>
  • 添加远端仓库
    git remote add <remote_repo_name> <remote_repo_url>
  • 列出远端仓库
    git remote
  • 获取远端仓库到本地
    git fetch <remote_repo_name>
  • (本地)重命名远端仓库
    git remote rename <old_name> <new_name>
  • (本地)重设远端仓库URL
    git remote set-url <remote_repo_name> <new_url>
  • (本地)删除远端仓库
    git remote rm <remote_repo_name>

  • 列出本地分支
    git branch
  • 切换本地分支
    git checkout <local_branch_name>
  • 删除本地分支
    git branch -D <branch_name>
  • 创建本地分支追中远端分支
    git checkout --track <remote_repo_name/remote_branch_name> 本地创建名为remote_branch_name的分支,追踪
    git checkout -b <local_branch_name> <remote_repo_name/remote_branch_name> 本地创建local_branch_name的分支,追踪
  • 本地分支从某远端分支来pull
    git pull <remote_repo_name> <remote_branch_name>:<local_repo_name/local_branch_name>
  • 本地分支push到远端分支
    git push <remote_repo_name> <local_branch_name> 若local_branch_name不存在,则新建
    git push <remote_repo_name> <local_branch_name>:<remote_branch_name> 远端as remote_branch_name
  • 分支merge其他分支冲突
    git checkout <master>
    git merge <bugfix>
    git mergetool
    git status
    git commit

  • 检查当前修改状态 对比上次commit
    git status
  • 查看未暂存/已暂存的修改 对比上次commit
    git diff [--staged]
  • 查看提交历史
    git log
    -数字 最近若干次
    -p 显示差异
    --stat 文件变化情况

  • 添加内容到下一次提交中 添加对文件(可以是目录)的跟踪;暂存已修改文件
    git add <file_name>

  • 提交
    git commit
    -m <msg> 附带提交信息
    -a 跳过add暂存直接commit

  • 取消已修改未缓存的文件
    git checkout -- <file_name>

  • 取消已缓存的文件 取消已经staged的文件(比如为了从分成多次提交,下次再提交)
    git reset HEAD <file_name>
  • reset到某次commit
    git reset --hard <commit_hash>
    --soft 保留当前修改
  • 修改最后一次commit 修改commit文件或信息,使用当前的暂存区域快照更新后,提交。
    git commit --amend
  • push时文件大小超出限制
    git rm --cached <file_path/file_name>
    .gitignore
    git commit --amend

  • 修改已经提交的commit message
    1. git rebase -i HEAD~8 //8为距最后提交的倒数第8次
    2. pick -> edit
    3. git commit —amend
    4. git rebase —continue
    5. git push -f

Scala Cheatsheet

1.1. 变量

使用关键词var声明变量,使用关键词val声明常量。

1
2
var myVar : String = "aaa"
val myVal : String = "bbb"

1.2. 运算符

基本与java相同,但无++

2.1. 条件控制

2.1.1. if条件

与java相同

1
2
3
4
5
6
7
if(condition1){
statement(s);
}else if(condition2){
statement(s);
}else {
statement(s);
}

2.1.2. 不支持switch

2.2. 循环

2.2.1. while循环

与java相同

1
2
3
4
5
6
7
8
while(condition)
{
statement(s);
}

do {
statement(s);
} while(condition);

2.2.2. for循环

普通形式:

1
2
3
for(x <- Range){
statement(s);
}

Range可以是

  • 可迭代结构
  • i until j
  • i to j

x之前并没有var指定。其类型是由Range决定的。

多范围:

1
2
3
for(x <- Range1; y <- Range2){
statement(s);
}

带守卫:

1
2
3
for(x <- Range if condition_x1; if condition_x2...; y <- Range2 if condition_y1; if condition_y2...){
statement(s);
}

生成新List:

1
var retVal = for{x <- List if condition1; if condition2...} yield x

2.2.3. 不支持continue、break

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 导入以下包
import scala.util.control._

// 创建 Breaks 对象
val loop = new Breaks;

// 在 breakable 中循环
loop.breakable{
// 循环
for(...){
....
// 循环中断
loop.break;
}
}

3.1. 方法和函数

Scala中,方法是类的一部分,而函数是一个对象可以赋值给一个变量。
Scala的方法跟Java的类似,方法是组成类的一部分。
Scala的函数则是一个完整的对象,Scala的函数其实就是继承了Trait的类的对象。

Scala中使用def语句定义方法,val语句可以定义函数。

1
2
3
4
class Test{
def m(x: Int) = x + 3
val f = (x: Int) => x + 3
}
  • 如果方法不写等号和主体,那么该方法会被隐式声明为抽象,包含它的类型也是一个抽象类型。
  • 定义函数时,可以指定默认参数。
  • 调用函数时,可以指定函数参数名传参,不一定要按顺序传参。
  • 可变参数,在参数的类型之后放一个星号来设置,def printStrings(args: String*)
  • 函数中可以嵌套函数。
  • 在Scala中无法直接操作方法,如果要操作方法,必须先将其转换成函数。方法转函数:val f1 = m _
  • 如果函数不带参数,可以不写括号。

3.1.1. 函数传值/传名调用

Scala的解释器在解析函数参数(function arguments)时有两种方式:

  • 传值调用(call-by-value):先计算参数表达式的值,再应用到函数内部。
  • 传名调用(call-by-name):将未计算的参数表达式直接应用到函数内部。

在进入函数内部前,传值调用方式就已经将参数表达式的值计算完毕,而传名调用是在函数内部进行参数表达式的值计算的。
这就造成了一种现象,每次使用传名调用时,解释器都会计算一次表达式的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
object Test {
def main(args: Array[String]) {
delayed(time());
}

def time() = {
println("获取时间,单位为纳秒")
System.nanoTime
}
def delayed(t: => Long) = {
println("在 delayed 方法内")
println("参数: " + t) //计算t,打印"获取时间,单位为纳秒"
t //计算t,打印"获取时间,单位为纳秒"
}
}

以上实例中我们声明的delayed方法,在变量名和变量类型使用=>符号来设置传名调用。

3.1.2. 高阶函数

高阶函数可以使用其他函数作为参数,或者使用函数作为输出结果。

1
2
3
4
5
6
7
8
9
10
object Test {
def main(args: Array[String]) {
println( apply( layout, 10) )
}

// 函数 f 和 值 v 作为参数,而函数 f 又调用了参数 v
def apply(f: Int => String, v: Int) = f(v)

def layout[A](x: A) = "[" + x.toString() + "]"
}

f: Int => StringInt为入参类型,String为返回值类型。

3.1.3. 匿名函数

箭头左边是参数列表,右边是函数体。

1
2
3
var inc = (x: Int) => x + 1

var userDir = () => { System.getProperty("user.dir") }

总结一下:

t: => Long 参数声明,传名调用
f: Int => String 参数声明,传函数
(x: Int) => x + 1 定义匿名函数

3.1.4. 偏应用函数

不需要提供函数需要的所有参数,只需要提供部分,或不提供所需参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.Date

object Test {
def main(args: Array[String]) {
val date = new Date
val logWithDateBound = log(date, _ : String)

logWithDateBound("message1" )
Thread.sleep(1000)
logWithDateBound("message2" )
Thread.sleep(1000)
logWithDateBound("message3" )
}

def log(date: Date, message: String) = {
println(date + "----" + message)
}
}

log()方法接收两个参数:datemessage。我们在程序执行时调用了三次,参数date值都相同,message不同。我们可以使用偏应用函数优化以上方法,绑定第一个date参数,第二个参数使用下划线(_)替换缺失的参数列表,并把这个新的函数值的索引的赋给变量。

3.1.5 函数柯里化

柯里化(Currying)指的是将原来接受两个参数的函数变成新的接受一个参数的函数的过程。新的函数返回一个以原有第二个参数为参数的函数。

首先定义一个函数:

1
def add(x: Int, y: Int) = x + y

柯里化:

1
def add(x: Int)(y: Int) = x + y

实质上最先演变成这样一个方法:

1
def add(x: Int) = (y: Int) => x + y

3.1.6 闭包

闭包是一个函数,返回值依赖于声明在函数外部的一个或多个变量。
闭包通常来讲可以简单的认为是可以访问一个函数里面局部变量的另外一个函数。

1
2
3
4
5
6
7
8
object Test {
def main(args: Array[String]) {
println( "muliplier(1) value = " + multiplier(1) )
println( "muliplier(2) value = " + multiplier(2) )
}
var factor = 3
val multiplier = (i:Int) => i * factor
}

函数变量multiplier成为一个“闭包”,因为它引用到函数外面定义的变量,定义这个函数的过程是将这个自由变量捕获而构成一个封闭的函数。

4.1. 数组

1
2
3
var z: Array[String] = new Array[String](3)
var z = new Array[String](3)
var z = Array("aaa", "bbb", "ccc")

创建多维数组:

1
var myMatrix = ofDim[Int](3,3)

import Array._ 引入包

  • def ofDim[T]( n1: Int ): Array[T],创建(指定维度长度)的一维数组
  • def ofDim[T]( n1: Int, n2: Int ): Array[Array[T]],创建二维数组
  • def ofDim[T]( n1: Int, n2: Int, n3: Int ): Array[Array[Array[T]]],创建三维数组

4.2. 集合

4.2.1 List

列表是不可变的,值一旦被定义了就不能改变。
列表具有链表结构。

1
2
3
val site: List[String] = List("Runoob", "Google", "Baidu")
// 空列表
val empty: List[Nothing] = List()

在Scala中,列表要么是Nil(及空表),要么是一个head元素加上一个tail,而tail是一个列表(或者一个init加上一个last元素,而init是一个列表)

  • head返回列表第一个元素
  • tail返回一个列表,包含除了第一元素之外的其他元素
  • isEmpty在列表为空时返回true
:: 连接元素至列表
::: 连接列表至列表
def +:(elem: A): List[A] 元素加列表前面,生成新列表
def :+(elem: A): List[A] 元素加列表后面,生成新列表
List.fill() 创建重复元素的列表,例如val site = List.fill(3)("Runoob")
List.tabulate() 通过给定函数来创建列表,例如val l = List.tabulate(6)(n => n * n)
def apply(n: Int): A 通过列表索引获取元素,同site(3)
def drop(n: Int): List[A] 丢弃前n个元素,并返回新列表
def dropRight(n: Int): List[A] 丢弃最后n个元素,并返回新列表
def exists(p: (A) => Boolean): Boolean 某元素是否存在,例如site.exists(s => s == "Baidu")
def filter(p: (A) => Boolean): List[A] 输出符号指定条件的所有元素,例如site.filter(s => s.length == 3)
def forall(p: (A) => Boolean): Boolean 检测所有元素,例如site.forall(s => s.startsWith("H"))
def foreach(f: (A) => Unit): Unit 将函数应用到列表的所有元素

4.2.2. Set

集合分为可变的和不可变的集合。
默认情况下,Scala使用的是scala.collection.immutable.Set,不可变集合。
如果想使用可变集合,需要引用scala.collection.mutable.Set。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
val set = Set(1,2,3)
println(set.getClass.getName) //

println(set.exists(_ % 2 == 0)) //true
println(set.drop(1)) //Set(2,3)


import scala.collection.mutable.Set // 可以在任何地方引入 可变集合

val mutableSet = Set(1,2,3)
println(mutableSet.getClass.getName) // scala.collection.mutable.HashSet

mutableSet.add(4)
mutableSet.remove(1)
mutableSet += 5
mutableSet -= 2

println(mutableSet) // Set(5, 3, 4)

val another = mutableSet.toSet
println(another.getClass.getName) // scala.collection.immutable.Set

虽然可变Set和不可变Set都有添加或删除元素的操作,但是有一个非常大的差别。
对不可变Set进行操作,会产生一个新的set,原来的set并没有改变,这与List一样。
而对可变Set进行操作,改变的是该Set本身,与ListBuffer类似。

4.2.3. Map

映射分为可变的和不可变的映射。
默认情况下为不可变映射。
如果想使用可变映射,需要引用scala.collection.mutable.Map。

1
2
3
4
5
// 空哈希表,键为字符串,值为整型
var A:Map[Char,Int] = Map()

// Map 键值对演示
val colors = Map("red" -> "#FF0000", "azure" -> "#F0FFFF")

4.2.4. Tuple

与列表一样,元组也是不可变的

1
2
3
4
5
6
7
8
9
10
object Test {
def main(args: Array[String]) {
val t = (4,3,2,1)
val t2 = new Tuple3(1, 3.14, "Fred")

val sum = t._1 + t._2 + t._3 + t._4

println( "元素之和为: " + sum )
}
}

A->B,->方法调用的结果是返回一个二元的元组(A,B)

4.2.5. Option

Option(选项)类型用来表示一个值是可选的(有值或无值)。
Option[T]是一个类型为T的可选值的容器:如果值存在,Option[T]就是一个Some[T];如果不存在,Option[T]就是对象None

1
2
3
4
5
6
7
8
9
10
11
12
13
object Test {
def main(args: Array[String]) {
val sites = Map("runoob" -> "www.runoob.com", "google" -> "www.google.com")

println("show(sites.get( \"runoob\")) : " + show(sites.get( "runoob")) )
println("show(sites.get( \"baidu\")) : " + show(sites.get( "baidu")) )
}

def show(x: Option[String]) = x match {
case Some(s) => s
case None => "?"
}
}

可以使用 isEmpty() 方法来检测元组中的元素是否为 None

1
2
3
4
5
6
7
8
9
object Test {
def main(args: Array[String]) {
val a:Option[Int] = Some(5)
val b:Option[Int] = None

println("a.isEmpty: " + a.isEmpty) // false
println("b.isEmpty: " + b.isEmpty) // true
}
}

4.2.6. 迭代器

1
2
3
4
5
6
7
8
9
object Test {
def main(args: Array[String]) {
val it = Iterator("Baidu", "Google", "Runoob", "Taobao")

while (it.hasNext){
println(it.next())
}
}
}

5.1 继承

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
import java.io._

class Point(val xc: Int, val yc: Int) {
var x: Int = xc
var y: Int = yc
def move(dx: Int, dy: Int) {
x = x + dx
y = y + dy
println ("x 的坐标点 : " + x);
println ("y 的坐标点 : " + y);
}
}

class Location(override val xc: Int, override val yc: Int,
val zc :Int) extends Point(xc, yc){
var z: Int = zc

def move(dx: Int, dy: Int, dz: Int) {
x = x + dx
y = y + dy
z = z + dz
println ("x 的坐标点 : " + x);
println ("y 的坐标点 : " + y);
println ("z 的坐标点 : " + z);
}
}

object Test {
def main(args: Array[String]) {
val loc = new Location(10, 20, 15);
// 移到一个新的位置
loc.move(10, 10, 5);
}
}
  • 类定义可以有参数,称为类参数,如上面的xc,yc。类参数在整个类中都可以访问。
  • 子类只有主构造函数才可以往父类的构造函数里写参数。
  • 子类重写一个非抽象方法必须使用override修饰符;重写抽象方法时不需要。

5.2 单例/伴生对象

Scala不能定义静态成员,而是定义单例对象。以object关键字定义。
对象定义了某个类的单个实例,包含了“静态”特性:

1
2
3
4
object Accounts {
private var lastNumber = 0
def newUniqueNumber() = {lastNumber += 1; lastNumber}
}

当单例对象与某个类共享同一个名称时,它就被称为是这个类的伴生对象。
类被称为是这个单例对象的伴生类。
类和它的伴生对象必须定义在同一个源文件中。
类和它的伴生对象可以互相访问其私有成员。

1
2
3
4
5
6
7
8
9
10
11
class Account {
val id = Account.newUniqueNumber()
private var balance = 0.0
def deposit(amount: Double){ balance += amount }
...
}

object Account {
private var lastNumber = 0
def newUniqueNumber() = { lastNumber += 1; lastNumber}
}
  • 类的伴生对象可以被访问,但并不在作用域当中。Account类必须通过Account.newUniqueNumber()来调用伴生对象的方法。

5.3. 特征

相当于抽象类。

1
2
3
4
trait Equal {
def isEqual(x: Any): Boolean
def isNotEqual(x: Any): Boolean = !isEqual(x)
}

通过with关键字,一个类可以扩展多个特质:

1
2
3
4
class BMW extends Car with Shiny {
val brand = "BMW"
val shineRefraction = 12
}

5.4. 匹配

5.4.1. 选择器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
object Test {
def main(args: Array[String]) {
println(matchTest("two")) # 2
println(matchTest("test")) # many
println(matchTest(1)) # one
println(matchTest(6)) # scala.Int

}
def matchTest(x: Any): Any = x match {
case 1 => "one"
case "two" => 2
case y: Int => "scala.Int"
case _ => "many"
}
}

5.4.2. 样例类

使用了case关键字的类定义就是就是样例类。
样例类是种特殊的类,经过优化以用于模式匹配。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
object Test {
def main(args: Array[String]) {
val alice = new Person("Alice", 25)
val bob = new Person("Bob", 32)
val charlie = new Person("Charlie", 32)

for (person <- List(alice, bob, charlie)) {
person match {
case Person("Alice", 25) => println("Hi Alice!")
case Person("Bob", 32) => println("Hi Bob!")
case Person(name, age) => println("Age: " + age + " year, name: " + name + "?")
}
}
}

// 样例类
case class Person(name: String, age: Int)
}

Python Cheatsheet

1.1. 标识符

  • 标识符由字母、数字、下划线组成,不能以数字开头。
  • 以下划线开头的标识符是有特殊意义的。
    • 以单下划线开头_foo的代表不能直接访问的类属性protected,需通过类提供的接口进行访问,不能用from xxx import *而导入。
    • 以双下划线开头的__foo代表类的私有成员private。
    • 以双下划线开头和结尾的__foo__代表Python里特殊方法专用的标识,如__init__()代表类的构造函数。

1.2. 变量

  • Python 中的变量赋值不需要类型声明。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建。
  • 多变量赋值
    • a = b = c = 1
    • a, b, c = 1, 2, "john"
  • 删除对象的引用
    • del var_a, var_b

1.3. 标准数据类型

Number数字

  • 整型 int,例如:10
  • 长整型 long,例如:10L
    • long类型只存在于Python2.X版本中,int型数据溢出后会自动转为long型。在Python3.X版本中long类型被移除,使用int替代。
  • 浮点型 float,例如:10.0
  • 复数型 complex,例如:10+3.14j
    • 复数的实部和虚部都是浮点型

String字符串

  • 引号
    • Python 可以使用引号'、双引号"、三引号'''"""来表示字符串,引号的开始与结束必须的相同类型的。
    • 其中三引号可以由多行组成(字符串中换行)。
    • 原始字符串:例如r"\n",不对字符串进行转义。
  • 注释
    • 单行注释采用#开头。
    • 多行注释使用三个单引号'''或三个双引号"""
    • # -*- coding: UTF-8 -*-
  • 截取与拼接
    • 索引下标:从左到右索引从0开始,最大范围是n-1;从右到左索引从-1开始,最大范围-n。
    • 使用[头下标:尾下标]来截取相应的字符串,截取区间左闭右开[)。
    • 使用加号+来拼接字符串,使用乘号*来生成重复拼接的字符串。
  • 格式化
    • 例如:a = "%d, %s" % (111, "test")

List列表

  • []标识,元素类型可以不同,支持列表嵌套。
  • 支持截取、拼接,参考字符串截取。
  • [下标]取值。

Tuple元组

  • ()标识,元组不能二次赋值(指定下标赋值),相当于只读列表。
  • 新建元组中只包含一个元素时,需要在元素后面添加逗号tup1 = (50,)

Dictionary字典

  • {}标识,key-value结构。
  • [key]取值。
  • 字典值可以没有限制地取任何python对象,既可以是标准的对象,也可以是用户定义的。但键必须不可变(可以用数字、字符串或元组充当,用列表就不行)。

1.4. 运算符

  • 算术运算符:+-*/、次幂**、取模%、地板除//(即处理浮点时,1.//2=0.0)。
    • =及运算符与=连用。
    • ++,因为在 Python 里的数值和字符串之类的都是不可变对象,对不可变对象操作的结果都会生成一个新的对象,而不是把某内存地址数据值增加 。
  • 位运算符:&|^~<<>>
  • 比较运算符:==!=、另一种不等于<>><>=<=
  • 逻辑运算符:andornot
    • 可加括号,表达更清楚。
  • 成员运算符:innot in
    • 字符串,列表或元组中是否包含某元素。
  • 身份运算符:isis not
    • 是否引用同一内存。
    • 例如a为List,b=a与b=a[:]的区别,前者为传递引用,后者为拷贝。

2.1. 缩进

Python的代码块不使用大括号{}来控制类,函数以及其他逻辑判断。Python最具特色的就是用缩进来写模块

2.2. 条件控制

1
2
3
4
5
6
if expression : 
suite
elif expression :
suite
else :
suite

2.3. 循环

  • 支持continuebreak
  • pass为空语句,占位语句。

while循环

1
2
3
4
while expression : 
suite
else :
suite
  • else为非break退出循环的分支。

for循环

1
2
3
4
for iterating_var in sequence:
suite
else :
suite
  • 直接迭代元素:for letter in 'Python';或迭代下标:for index in range(0, 10)
  • 使用for index, item in enumerate(sequence),同时获取下标和值。

2.4. 函数

1
2
3
4
def functionname( parameters ):
"函数_文档字符串"
function_suite
return [expression]
  • 参数传递
    • 数字、字符串、元组是不可变类型,而列表、字典等则是可变类型。参数传递时,不可变类型的对象传值,可变类型的对象传引用。
    • 默认参数,例如def printinfo( name, age = 35 ):
    • 不定长参数,加了星号*的变量名会存放所有未命名的变量参数,例如def printinfo( arg1, *vartuple ):
  • 全局变量想作用于函数内,需加关键字global
  • 匿名函数lambda
    • lambda [arg1 [,arg2,.....argn]]:expression
    • lambda函数拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。

2.5. 异常处理

1
2
3
4
5
6
7
8
9
raise [Exception [, args [, traceback]]]
try:
<语句>
except
<语句>
else:
<语句>
finally:
<语句>

2.6. 模块

  • 模块导入
    • import module1,使用函数:module1.func1()
    • from module1 import func1,使用函数:func1()
    • from module1 import *,使用函数:func1()

3.1. 面向对象

定义类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/python
# -*- coding: UTF-8 -*-

class Employee:
'所有员工的基类'
empCount = 0

def __init__(self, name, salary):
self.name = name
self.salary = salary
Employee.empCount += 1

def displayCount(self):
print "Total Employee %d" % Employee.empCount

def displayEmployee(self):
print "Name : ", self.name, ", Salary: ", self.salary
  • empCount变量是一个类变量,它的值将在这个类的所有实例之间共享。在内部类或外部类使用Employee.empCount访问。
  • 方法__init__()是构造函数。
  • self代表类的实例,self在定义类的方法时是必须有的,但在调用时不必传入相应的参数。
    • 类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是self

使用实例

1
2
3
emp1 = Employee("Zara", 2000)
emp1.displayEmployee()
print "Total Employee %d" % Employee.empCount
  • new关键字,使用的是构造函数__init__
  • 用点号.访问属性、方法。

继承

1
2
class SubClassName (ParentClass1[, ParentClass2, ...]):
...
  • 在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。
  • 调用方法时,先在本类中查找调用的方法,找不到才去基类中逐个查找。

KPI Check Note

依据

  • 当前曲线变化趋势与baseline应该相似
    • 周期性
    • 同质性
  • 当前曲线变化趋势应该较平缓
    • 可发现激增毛刺造成的影响
  • 当前曲线相较baseline全局无过高值
    • 可发现缓增趋势造成的影响

数据预处理

[线性插值]

[周期性判断]

利用自相关函数来进行判断


毛刺检测

[数据自身 + k-sigma准则]

[对比滤波 + k-sigma准则]

曲线可以小幅度震荡。(高频低通)滤波后曲线与真实曲线的差值(绝对值),在k-sigma以外的点为异常。

滤波:

  • 中值滤波 Median Filter
    • 某点的值为该点周围一个窗口的中值,迭代滑动窗口。
  • 滑动平均 Moving Average
    • 某点的值为该点前面一个窗口的平均值,迭代滑动窗口。
  • 指数平滑 Exponential Smoothing
    • 一次指数平滑:适用于趋势无明显变化的时间序列(平滑值$s_t$)$$\begin{aligned} s_t &= \alpha x_{t} + (1-\alpha)s_{t-1}\\ &= \alpha x_{t} + \alpha (1-\alpha)x_{t-1} + (1 - \alpha)^2 s_{t-2}\\ &= \alpha \left[x_{t} + (1-\alpha)x_{t-1} + (1-\alpha)^2 x_{t-2} + (1-\alpha)^3 x_{t-3} + \cdots + (1-\alpha)^{t-1} x_{1} \right] + (1-\alpha)^{t} x_0 \end{aligned}$$
    • 二次指数平滑:适用于线性趋势的时间序列
  • 卡尔曼滤波 Kalman Filter

k-sigma准则,通过统计理论检测异常点:

  • $3-\sigma$:在正态分布中,数值分布在$(\mu - 3\sigma, \mu + 3\sigma)$中的概率约为0.9974。$\mu$为均值、$\sigma$为标准差。

周期性数据横向对比

[对比同时刻点 + k-sigma准则]

不同周期中同时刻的点相差不大。对同时刻各点,通过k-sigma准则确定阈值,过滤异常。

[FFT提取频域特征 + KS检验]

同一时刻各点,以及之前若干点,组成时间窗。

不同周期中,同时刻时间窗的点,频域的统计分布应类似。对同时刻各时间窗做FFT变换,统计分布,不符合同一分布则为异常。

快速傅里叶变换 FFT:

  • 时域转频域。

KS检验 Kolmogorov-Smirnov Test:

  • 基于CDF检验一个观测是否符合某一分布,或两个观测是否符合同一分布。

参数选择

  • 网格搜索 Grid Search
    • 遍历
  • 模拟退火 Simulated Annealing
    • 若移动后得到更优解,则总是接受该移动;若移动后的解比当前解要差,则以一定的概率接受移动,而这个概率随着时间(迭代次数)推移而逐渐降低。初始时设置一个初始温度T和降温速度r,降温到一定程度则停止迭代。
    • 具体实现时,一定概率接受体现为:比较random(0,1)与计算出来的(接受移动)概率值。
    • 对比贪心策略:若移动后得到更优解,则总是接受该移动;否则,不移动。模拟退火能够一定程度上避免局部最优解困局。

异常点检测方法

[统计]

  • k-sigma准则选取阈值,[使用场景shape=(时刻, 单指标)]
    • $\mu$为均值、$\sigma$为标准差。
    • k-sigma准则:在$(\mu - k \times \sigma, \mu + k \times \sigma)$范围外的数值为outlier。
    • $k = 3$:在正态分布中,数值分布在$(\mu - 3\sigma, \mu + 3\sigma)$中的概率约为0.9974。
  • Tukey Fences选取阈值,[使用场景shape=(时刻, 单指标)]
    • When there are no outliers in a sample, the mean and standard deviation are used to summarize a typical value and the variability in the sample, respectively. When there are outliers in a sample, the median and interquartile range are used to summarize a typical value and the variability in the sample, respectively.
    • Interquartile Range $ IQR = Q3 - Q1$
    • Tukey Fences: Outliers are values below $Q1 - k \times IQR$ or above $Q3 + k \times IQR$, where $k = 1.5$ indicates an “outlier”, and $k = 3$ indicates data that is “far out”.
    • Q3 is positioned at $0.675\sigma$ for a normal distribution. The $IQR$ represents $2 \times 0.675\sigma = 1.35\sigma$. The outlier fence is determined by adding $Q3$ to $1.5 \times IQR = 0.675\sigma + 1.5 \times 1.35\sigma = 2.7\sigma$. This level would declare 0.7% of the measurements to be outliers.
  • 基于$\chi^{2}$检验的分布相似度检测,[使用场景shape=(时刻, 多指标)]
    • 检测各指标出现频次的分布,相较于(训练)基线数据,是否产生了变动。如果某时刻的指标分布与基线不符,则该时刻异常。
    • 代码示例给出了计算各个指标的卡方值,将卡方值较大的指标判定为异常的指标。此外,也可以累加了各个指标的卡方值,这样不关注哪个指标是异常的,而是关注哪个(按行累加的行)时刻是异常的。
  • 基于KS检验的频域分布相似度检测,[使用场景shape=(时刻, 单指标)]
    • 加窗FFT变换,获取(一段)序列的频域信息。
    • KS检验,基于CDF检验两序列是否来自同一分布。

[聚类]

  • k-means/x-means,通过聚类检测异常点,[常用场景shape=(时刻, 多指标)]
  • DBSCAN,通过聚类检测异常点,[常用场景shape=(时刻, 多指标)]
    • 检测“邻域半径内的点个数”(即密度)。对满足密度要求的核心点,其邻域半径内所有点为新核心点,递归拓展“邻域-核心点”。

[离群点识别]

  • 局部异常因子 Local Outlier Factor, LOF,[常用场景shape=(时刻, 单指标)或(时刻, 多指标)]
    • 算法介绍
    • 在LOF之前的异常检测算法大多是基于统计方法、或借用聚类算法。但是,基于统计的异常检测算法通常需要假设数据服从特定的概率分布,这个假设往往是不成立的。而聚类的方法通常只能给出0/1判断(即是否为异常点),不能量化每个数据点的异常程度。相比较而言,基于密度的LOF算法要更简单、直观。它不需要对数据的分布做太多要求,还能量化每个数据点的异常程度。

Install Hexo

[Github Pages]

创建Repo,名称为username.github.io。

[Git]

安装

[NodeJs]

安装

[Hexo]

管理员打开cmd

  • (如需代理)npm config set proxy http://username:password@hostname:8080
  • (国内加速)npm config set registry "https://registry.npm.taobao.org"
  • npm install -g hexo-cli

进入本地username.github.io目录

  • (如需代理)git config --global http.proxy http://username:password@hostname:8080
  • (如需代理)git config --global http.sslverify false
  • hexo init
  • npm install

[配置]

配置 _config.yml 文件

1
2
3
4
deploy:
type: git
repo: https://github.com/lichenyu/lichenyu.github.io.git
branch: master

[测试]

[部署]

安装 hexo-deployer-git 插件

1
npm install hexo-deployer-git --save
  • hexo clean
  • hexo generate
  • hexo deploy

deploy步骤,如有必要需设置一下git的代理

[添加Latex公式支持]

  • npm install hexo-math --save
  • npm install hexo-renderer-mathjax --save
  • 配置 _config.yml 文件

内容如下

1
2
3
4
5
6
7
8
9
10
11
math:
engine: 'mathjax' # or 'katex'
mathjax:
src: "//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"
config:
# MathJax config
katex:
css: #custom_css_source
js: #custom_js_source # not used
config:
# KaTeX config

支持行内公式

  • npm uninstall hexo-renderer-marked --save
  • npm install hexo-renderer-kramed --save
  • node_modules\kramed\lib\rules\inline.js,把第11、20行的escape变量的值做相应修改

内容如下

1
2
3
4
5
//escape: /^\\([\\`*{}\[\]()#$+\-.!_>])/,
escape: /^\\([`*\[\]()#$+\-.!_>])/,

//em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
em: /^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,

此外,若想把mathjax的CDN设为国内的,需修改_config.yml配置、(以及渲染所用工具包文件node_modules/hexo-renderer-mathjax/mathjax.html)。

[代码高亮]

1
2
3
<link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
  • 相应themes目录的head.ejs中添加highlight.js相关配置。
  • (相应themes目录的highlight.styl,highlight-background = #f6f8fa。)
  • (_config.yml中关闭highlight相关选项。)

[CDN优化]

  • mathjax相关,上文已经说了
  • themes/landscape/layout/_partial/after-footer.ejs中的jquery.min.js