Fu's Workshop


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 搜索

不平衡样本的样本均衡问题

发表于 2020年05月22

样本分布不均衡将导致样本量少的分类所包含的特征过少,并很难从中提取规律;即使得到分类模型,也容易产生过度依赖于有限的数据样本而导致过拟合的问题,当模型应用到新的数据上时,模型的准确性和鲁棒性将很差。
样本分布不平衡主要在于不同类别间的样本比例差异,如果不同分类间的样本量差异达到超过10倍就需要引起警觉并考虑处理该问题,超过20倍就要一定要解决该问题。

哪些场景容易出现样本不平衡

  1. 异常场景的检测 恶意刷单、信用卡欺诈等
  2. 罕见事件、低频事件

解决思路

1. 上采样和下采样
上采样:通过增加分类中少数类样本的数量来实现样本均衡,最直接的方法是简单复制少数类样本形成多条记录,这种方法的缺点是如果样本特征少而可能导致过拟合的问题;经过改进的过抽样方法通过在少数类中加入随机噪声、干扰数据或通过一定规则产生新的合成样本,例如SMOTE算法。
下采样:通过减少分类中多数类样本的样本数量来实现样本均衡,最直接的方法是随机地去掉一些多数类样本来减小多数类的规模,缺点是会丢失多数类样本中的一些重要信息。
2. 通过组合/集成方法解决样本不平衡
组合/集成方法指的是在每次生成训练集时使用所有分类中的小样本量,同时从分类中的大样本量中随机抽取数据来与小样本量合并构成训练集,这样反复多次会得到很多训练集和训练模型。最后在应用时,使用组合方法(例如投票、加权投票等)产生分类预测结果。
3. 通过特征选择解决样本不均衡
上述几种方法都是基于数据行的操作,通过多种途径来使得不同类别的样本数据行记录均衡。除此以外,还可以考虑使用或辅助于基于列的特征选择方法。
一般情况下,样本不均衡也会导致特征分布不均衡,但如果小类别样本量具有一定的规模,那么意味着其特征值的分布较为均匀,可通过选择具有显著型的特征配合参与解决样本不均衡问题,也能在一定程度上提高模型效果。
4. 无监督
对于从大规模数据中寻找罕见数据的应用场景,亦可使用非监督式的学习方法,例如使用One-class SVM、高斯分布进行异常检测。
大多数数据挖掘或数据工作中,异常点都会在数据的预处理过程中被认为是“噪音”而剔除,以避免其对总体数据评估和分析挖掘的影响。但某些情况下,如果数据工作的目标就是围绕异常点,那么这些异常点会成为数据工作的焦点。 数据集中的异常数据通常被成为异常点、离群点或孤立点等,典型特征是这些数据的特征或规则与大多数数据不一致,呈现出“异常”的特点,而检测这些数据的方法被称为异常检测。 “噪音”的出现有多种原因,例如业务操作的影响(典型案例如网站广告费用增加10倍,导致流量激增)、数据采集问题(典型案例如数据缺失、不全、溢出、格式匹配等问题)、数据同步问题(异构数据库同步过程中的丢失、连接错误等导致的数据异常),而对离群点进行挖掘分析之前,需要从中区分出真正的“离群数据”,而非“垃圾数据”。

LeetCode review 1 LinkedList

发表于 2020年02月20
  1. lc2 两数相加
    给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
    如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
    您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
    temp_sum计算每一位,flag计算进位,注意进位的处理。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
    if not l1:
    return l2
    if not l2:
    return l1
    res = ListNode(0)
    temp = res
    flag = 0
    while l1 or l2:
    temp_sum = 0
    if l1:
    temp_sum += l1.val
    l1 = l1.next
    if l2:
    temp_sum += l2.val
    l2 = l2.next
    temp_res = (temp_sum+flag) % 10
    flag = (temp_sum+flag) // 10
    res.next = ListNode(temp_res)
    res = res.next
    if flag:
    res.next = ListNode(1)
    return temp.next
  2. lc19 删除链表的倒数第N个节点
    给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
    双指针的next指向head,第一个指针先向后移动n个位置,然后两个指针同时移动直到第一个指针移动到链表末端,此时第二个指针指向倒数第n+1个数,删除第二个指针的next节点即可。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
    res = ListNode(0)
    res.next = head
    p, q = res, res

    for _ in range(n):
    q = q.next

    while q.next:
    q = q.next
    p = p.next

    p.next = p.next.next
    return res.next

使用Charles对微信小程序抓包

发表于 2020年02月14

Charles是一种常用的网络封包截取工具,Charles通过将自己设置成系统的网络访问代理服务器,使得所有的网络访问请求都通过它来完成,从而实现了网络封包的截取和分析。

电脑中的设置

选择菜单中的Proxy -> Windows Proxy来将Charles设置成系统代理。
设置完成后可以看到电脑上所有的网络请求都被Charles获取。

iPhone中的设置

  1. 先获取运行Charles电脑的IP地址,win输入ipconfig。
  2. 在iPhone的设置 -> 无线局域网中选择当前连接的无线网,在最底端有一个HTTP代理选项。将其切换为手动,输入电脑的IP地址及端口号8888.
    Charles
    Charles

解决乱码问题

在菜单Proxy -> SSL Proxying Settings中设置制定的Location。
Charles
Charles

原理

Charles 作为一个中间人来进行 HTTPS 的代理,让我们检测到浏览器和 SSL web 服务端之间的明文通信。
Charles 把自己变成一个中间人来达到这一目的。你的浏览器是收不到服务端证书的,Charles 会用自己的根证书动态签发一张证书,然后 Charles 来接受服务端的证书,你的浏览器接受 Charles 的证书。

结果

抓取了南京2ZHONGSHAN AIR JORDAN店发售球鞋的小程序,提前获取了明天要发售球鞋的货量。

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
{
"code": 20000,
"content": {
"skId": 191,
"productName": "AIR JORDAN 1 HI 85",
"productCode": "NKBQ4422-600",
"colorTitle": "颜色",
"sizeTitle": "尺码",
"productOriginPrice": "1499.00",
"productPrice": "1499.00",
"beforeBeginTime": 1581655337,
"actBeginTime": 1581728400,
"actEndTime": 1581732000,
"colorItems": [{
"colorCode": "999",
"colorName": "均色"
}],
"sizeItems": ["7", "7.5", "8", "8.5", "9", "9.5", "10", "10.5", "11", "11.5", "12", "12.5", "13", "14", "15", "16"],
"skuItems": [{
"sku": "194275079776",
"specVal": "均色 7",
"originPrice": 1499,
"price": 1499,
"size": "7",
"colorCode": "999",
"sizeCode": "7",
"sizeName": "7",
"stock": 1
}, {
"sku": "194275079783",
"specVal": "均色 7.5",
"originPrice": 1499,
"price": 1499,
"size": "7.5",
"colorCode": "999",
"sizeCode": "7.5",
"sizeName": "7.5",
"stock": 0
}, {
"sku": "194275079790",
"specVal": "均色 8",
"originPrice": 1499,
"price": 1499,
"size": "8",
"colorCode": "999",
"sizeCode": "8",
"sizeName": "8",
"stock": 2
}, {
"sku": "194275079806",
"specVal": "均色 8.5",
"originPrice": 1499,
"price": 1499,
"size": "8.5",
"colorCode": "999",
"sizeCode": "8.5",
"sizeName": "8.5",
"stock": 2
}, {
"sku": "194275079813",
"specVal": "均色 9",
"originPrice": 1499,
"price": 1499,
"size": "9",
"colorCode": "999",
"sizeCode": "9",
"sizeName": "9",
"stock": 3
}, {
"sku": "194275079820",
"specVal": "均色 9.5",
"originPrice": 1499,
"price": 1499,
"size": "9.5",
"colorCode": "999",
"sizeCode": "9.5",
"sizeName": "9.5",
"stock": 4
}, {
"sku": "194275079837",
"specVal": "均色 10",
"originPrice": 1499,
"price": 1499,
"size": "10",
"colorCode": "999",
"sizeCode": "10",
"sizeName": "10",
"stock": 3
}, {
"sku": "194275079844",
"specVal": "均色 10.5",
"originPrice": 1499,
"price": 1499,
"size": "10.5",
"colorCode": "999",
"sizeCode": "10.5",
"sizeName": "10.5",
"stock": 2
}, {
"sku": "194275079851",
"specVal": "均色 11",
"originPrice": 1499,
"price": 1499,
"size": "11",
"colorCode": "999",
"sizeCode": "11",
"sizeName": "11",
"stock": 1
}, {
"sku": "194275079868",
"specVal": "均色 11.5",
"originPrice": 1499,
"price": 1499,
"size": "11.5",
"colorCode": "999",
"sizeCode": "11.5",
"sizeName": "11.5",
"stock": 0
}, {
"sku": "194275079875",
"specVal": "均色 12",
"originPrice": 1499,
"price": 1499,
"size": "12",
"colorCode": "999",
"sizeCode": "12",
"sizeName": "12",
"stock": 1
}, {
"sku": "194275079882",
"specVal": "均色 12.5",
"originPrice": 1499,
"price": 1499,
"size": "12.5",
"colorCode": "999",
"sizeCode": "12.5",
"sizeName": "12.5",
"stock": 0
}, {
"sku": "194275079899",
"specVal": "均色 13",
"originPrice": 1499,
"price": 1499,
"size": "13",
"colorCode": "999",
"sizeCode": "13",
"sizeName": "13",
"stock": 0
}, {
"sku": "194275079905",
"specVal": "均色 14",
"originPrice": 1499,
"price": 1499,
"size": "14",
"colorCode": "999",
"sizeCode": "14",
"sizeName": "14",
"stock": 0
}, {
"sku": "194275079912",
"specVal": "均色 15",
"originPrice": 1499,
"price": 1499,
"size": "15",
"colorCode": "999",
"sizeCode": "15",
"sizeName": "15",
"stock": 0
}, {
"sku": "194275079929",
"specVal": "均色 16",
"originPrice": 1499,
"price": 1499,
"size": "16",
"colorCode": "999",
"sizeCode": "16",
"sizeName": "16",
"stock": 0
}],
"productImages": ["https://ssa.picture.realclub.cn/47dae7e0-4ee4-11ea-bfe2-c9da6f900614", "https://ssa.picture.realclub.cn/4aec1f80-4ee4-11ea-be59-d9d7725c5a4a"],
"maxBuyerNum": 1,
"state": 1,
"isReminder": 1,
"skActState": 1,
"skActTime": 61946
}
}

nohup缺陷及screen命令

发表于 2020年01月29

nohup的缺陷

在开发Discord Monitor过程中需要将Monitor挂起到后台,最开始使用的是nohup命令:

1
nohup python3 *.py > *.log 2>&1 &

将标准错误(2)重定向到标准输出(&1),标准输出(&1)再被重定向到指定的log文件中。
&指在后台运行,但当用户退出(挂起)的时候,命令也跟着退出。将nohup和&组合在一起:

1
nohup COMMAND &

理论上是可以将命令永久的放在后台执行,但是在实际中不是这样。因为是租用的Azure,必须使用SSH远程登录后进行操作,在使用nohup命令中发现关闭SSH后程序依旧挂断了,即使使用exit退出帐号再用

1
jobs

命令查看刚刚nohup的操作都被结束了。
原因是当网络断开或终端窗口关闭后,控制进程收到SIGHUP信号(挂断信号,默认的动作是终止程序)退出,会导致该会话期(Session, 一个或多个进程组的集合)内其他进程退出。

screen

screen是一个可以在多个进程之间多路复用一个物理终端的窗口管理器。screen中有会话的概念,用户可以在一个screen会话中创建多个screen窗口,在每一个screen窗口中就像操作一个真实的telnet/SSH连接窗口那样。
可以通过直接输入

1
screen

创建一个窗口。如果想要将窗口挂起,可以使用Ctrl+a d命令。
常用的命令还有:

1
2
3
screen -ls // 查看screen会话
screen -list // 同 -ls
screen -r * // 重新连接screen会话

HTTP状态码及扩展

发表于 2020年01月24

在Snrks Discord Monitor中的日志截取到如下,对中间一些知识点做整理。

1
2
3
4
2020-01-23 15:01:54,486 - /home/araid/.local/lib/python3.6/site-packages/urllib3/connectionpool.py[line:959] - DEBUG: Starting new HTTPS connection (1): api.nike.com:443
2020-01-23 15:01:54,891 - /home/araid/.local/lib/python3.6/site-packages/urllib3/connectionpool.py[line:437] - DEBUG: https://api.nike.com:443 "GET /snkrs/content/v1/?country=CN&language=zh-Hans&orderBy=published&offset=0 HTTP/1.1" 400 127
2020-01-23 15:02:04,904 - /home/araid/.local/lib/python3.6/site-packages/urllib3/connectionpool.py[line:959] - DEBUG: Starting new HTTPS connection (1): api.nike.com:443
2020-01-23 15:02:05,013 - /home/araid/.local/lib/python3.6/site-packages/urllib3/connectionpool.py[line:437] - DEBUG: https://api.nike.com:443 "GET /snkrs/content/v1/?country=CN&language=zh-Hans&orderBy=published&offset=0 HTTP/1.1" 200 96165

  1. GET请求
    整个Monitor的原理是经抓包得到的Nike Snkrs的API,通过URL发起GET请求。Query String Parameters包括四个:country(国家), lanuage(语言), offset(偏移量,一页有50条数据), orderBy(排序方式published和lastUpdated)。GET用于请求指定的页面信息,并返回实体主体。

  2. HTTP状态码
    当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含HTTP状态码的信息头(server header)用以响应浏览器的请求。日志中出现的有200(请求成功), 400(Bad Request 客户端请求的语法错误)。还有其他常见的如404 Not Found(服务器无法根据客户端的请求找到资源), 403 Forbidden(服务器拒绝执行客户端请求), 500 Internal Server Error(服务器内部错误,无法完成请求), 504 Gateway Time-out(充当网关或代理的服务器,未及时从远端服务器获取请求)。

  3. HTTP/1.0和HTTP/1.1的区别

  • HTTP/1.0 每次请求都需要建立新的TCP连接,连接不能复用。HTTP/1.1 新的请求可以在上次请求建立的TCP连接之上发送,连接可以复用。优点是减少重复进行TCP三次握手的开销,提高效率。
  • HTTP1.1在Request消息头里头多了一个Host域, HTTP1.0则没有这个域。
  • HTTP1.1增加了OPTIONS, PUT, DELETE, TRACE, CONNECT这些Request方法。
    等

Docker批量删除REPOSITORY、TAG为none的镜像

发表于 2019年12月24
  1. 第一次构建镜像时生成的镜像ID为A,此镜像会被标记为TAG-A
  2. 第二次构建镜像时生成的镜像ID为B,此镜像的标签仍为TAG-A
  3. Docker会移除ID为A的标签,此时A镜像就变成了dangling images,在docker images中显示为</none>:</none>

官方给出的解决方案是:

1
docker image prune

还可以这样做:

1
docker images|grep none|awk ‘{print $3}’|xargs docker rmi

grep: 查找images中符合none的字符串
awk: 输出
xargs: 给命令传递参数

LeetCode 21 合并两个有序链表

发表于 2019年11月15

第一次在python里用到链表这个数据结构,和cpp里很像,但还是要借用cpp中指针的概念。题目的重点是合并两个链表的过程。
非递归的答案:

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
class ListNode:
def __init__(self, x):
self.val = x
self.next = None

class Solution:
def mergeTwoLists(self, l1, l2):
newList = ListNode(-1)
if l1 is None and l2 is None:
return None

pre = newList
while l1 and l2:
if l1.val > l2.val:
pre.next = l2
l2 = l2.next
else:
pre.next = l1
l1 = l1.next
pre = pre.next
if l1 is not None:
pre.next = l1
if l2 is not None:
pre.next = l2
return newList.next

如果把第一个判断条件的and改为or会有一个测试用例无法通过:

Testcase

[]
[0]

Answer

[]

Expected Answer

[0]

goroutine的优点与比较

发表于 2019年11月06

goroutine的优点:

  1. goroutine可以在用户空间调度,避免了内核态和用户态的切换导致的成本。
  2. goroutine是语言原生支持的,提供了非常简洁的语法,屏蔽了大部分底层实现。
  3. goroutine有更小的初始栈空间,goroutine消耗的资源更小,允许用户创建成千上万的实例。

Java Thread

Java里的Thread使用的是线程模型的一对一模型,每一个轻量级进程都对应着一个内核线程。Java使用的线程调度方式主要是抢占式调度。

扩展点

  1. 用户态和内核态
    内核态:进程能访问所有的内存空间和对象
    用户态:进程能访问的内存空间和对象受到限制
    用户态切换到内核态有三种方法:
    (1) 系统调用,实质是中断机制,如Linux中的INT 80H
    (2) 异常:如果当前进程运行在用户态,如果这个时候发生了异常事件,就会触发切换。如:缺页异常
    (3) 中断:软中断硬中断
  2. goroutine中的栈管理:

goroutine

发表于 2019年10月22

并发和并行

并发意味着程序在任意时刻都是同时运行的,在规定时间内多个请求都得到执行和处理,分时操作系统就是一种并发设计。
并行意味着程序在单位时间内是同时运行的,在任一粒度时间内都具备同时执行的能力,最简单的例子就是多台机器并行处理。

协程 coroutine

协程是一种用户态的轻量级线程,操作执行者是用户自身程序。协程的执行是非抢占式多任务处理,由协程主动交出控制权,多个协程可能在一个或多个线程上面运行。
不同语言对协程的支持:

  1. C++: Boost.Coroutine
  2. Java: 不支持
  3. Python: async def(e.g. Discord中向频道用户发送消息)

    goroutine

    操作系统本身具备并发处理能力,但是进程切换的代价过高。所以Go语言在语言层面再构筑一级调度,将并发的粒度降低(编译器/解释器/虚拟机层面)。
    goroutine是建立在线程之上的轻量级的抽象,它允许我们以非常低的代价在同一个地址空间中并行地执行多个函数或者方法。在golang中创建一个goroutine只要使用go+匿名/有名函数的形式就可以启动。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    package main  

    import (
    "fmt"
    "runtime"
    "time"
    )

    func main() {
    for i := 0; i < 1000; i++{
    go func(i int) {
    for{
    fmt.Printf("Hello from" +
    "goroutine from %d\n", i)

    // 设置或查询可以并发执行的goroutine数目
    fmt.Println("GOMAXPROCS=", runtime.GOMAXPROCS(0))
    }
    }(i)
    }
    time.Sleep(time.Minute)
    }

goroutine特性

  • go的执行是非阻塞的,不会等待。
  • go后面函数的返回值会被忽略。
  • 调度器不能保证多个goroutine的执行次序,所有的goroutine是平等地调度和执行的。
  • Go程序会单独为main函数创建一个goroutine

Go语言的错误处理:panic, recocer, error, error wrapping

发表于 2019年10月17

panic和recover

panic

func panic(v interface{})
引发panic有两种情况,一种是程序主动调用panic函数(e.g. panic(xxx), panic的参数是一个空接口类型,任意类型的变量都可以传递给panic),另一种是程序产生运行时错误。
发生panic后,程序会从调用panic的函数位置或发生panic的地方立即返回,逐层向上执行函数的defer语句,然后逐层打印函数调用堆栈,直到被recover捕获或运行到最外层函数而退出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main  

import "fmt"

func tryDefer(){
for i := 0; i < 100; i++{
defer fmt.Println(i)
if i == 30 {
panic("print end")
}
}
}

func main() {
tryDefer()
}

当i循环到30时,系统会从30倒序进行Println操作,最后打印“panic: print end”。

recover

func recover() interface{}
recover用来捕获panic,阻止panic继续向上传递。recover()只有在defer后面的函数体内被直接调用才能捕获panic终止异常,否则返回nil,异常继续向外传递。

1
2
3
4
defer func(){
fmt.Println("function body")
recover()
}

记得主动在程序的中使用recover()拦截运行时错误。

error

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Package errors implements functions to manipulate errors.  
package errors

// New returns an error that formats as the given text.
func New(text string) error {
return &errorString{text}
}

// errorString is a trivial implementation of error.
type errorString struct {
s string
}

func (e *errorString) Error() string {
return e.s
}

error的底层实现非常简单,所以功能也比较弱,只能返回一个字符串。Golang 1.13中引入了一个新功能Error Wrapping。

123

Fu Hanlin

SEU

29 日志
7 分类
36 标签
RSS
GitHub E-Mail Facebook Instagram
© 2020 Fu Hanlin
由 Hexo 强力驱动
|
主题 — NexT.Pisces v5.1.4