tonglin0325的个人主页

特征预处理——异常值处理

pandas是python特征预处理常用的框架

1.查看数据

加载数据

1
2
3
4
5
6
#-*- coding: utf-8 -*-
import pandas as pd

train_data = pd.read_csv("./data/train.csv")
print(train_data)

pandas显示DataFrame数据的所有列,set_option其他参数参考:Pandas函数set_option()学习笔记

1
2
3
4
5
6
7
8
pd.set_option('expand_frame_repr', False) # 不换行
#pd.set_option('display.width', 200) # 列最多显示多少字符后换行

pd.set_option('display.min_rows', 20) # 至少显示20行数据
pd.set_option('display.max_columns', None) # 显示所有列

print(train_data)

2.查看空值

在pandas中的空值为NaN,isna()等同于isnull()

1
2
print(train_data.isna()) # 判断所有值是否是na,转换成boolean值

对于csv字符串NA,用pandas读取的时候,会转换成NaN,对于字符串None,则不是NaN

统计字段中Nan空值的总数

1
2
print(train_data.isna().sum())

查看某列是NaN的行

1
2
print(train_data[train_data.MiscFeature.isnull()])

查看有NaN值的列名

1
2
3
4
print(train_data.columns[train_data.isnull().any()].tolist())

['LotFrontage', 'Alley', 'MasVnrType', 'MasVnrArea', 'BsmtQual', 'BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinType2', 'Electrical', 'FireplaceQu', 'GarageType', 'GarageYrBlt', 'GarageFinish', 'GarageQual', 'GarageCond', 'PoolQC', 'Fence', 'MiscFeature']

对有Nan值的列的空值比例进行排序

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
total = train_data.isna().sum().sort_values(ascending=False)
percent = (train_data.isna().sum() / train_data.isnull().count()).sort_values(ascending=False)
missing_data = pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])
print(missing_data.head(20))

Total Percent
PoolQC 1453 0.995205
MiscFeature 1406 0.963014
Alley 1369 0.937671
Fence 1179 0.807534
FireplaceQu 690 0.472603
LotFrontage 259 0.177397
GarageYrBlt 81 0.055479
GarageCond 81 0.055479
GarageType 81 0.055479
GarageFinish 81 0.055479
GarageQual 81 0.055479
BsmtFinType2 38 0.026027
BsmtExposure 38 0.026027
BsmtQual 37 0.025342
BsmtCond 37 0.025342
BsmtFinType1 37 0.025342
MasVnrArea 8 0.005479
MasVnrType 8 0.005479
Electrical 1 0.000685
Id 0 0.000000

3.删除和替换空值

删除某一列为NaN值的行,只要有一列是NaN,该行数据就会被删除

1
2
print(train_data.dropna(how='any'))

删除subset中某一列为NaN值的行,只要有一列是NaN,该行数据就会被删除

1
2
print(train_data.dropna(subset=['Fence', 'MiscFeature'], how='any'))

删除所有列都是NaN值的行

1
2
print(train_data.dropna(how='all'))

删除subset中所有列都是NaN值的行

1
2
print(train_data.dropna(subset=['Fence', 'MiscFeature'], how='all'))

其他

1
2
3
4
df.dropna(axis=1) #丢弃有缺失值的列
df.dropna(axis=1, how = 'all') #丢弃所有列中所有值均缺失的列
df.dropna(axis=0, subset=['name', 'age'])#丢弃name和age这两列中有缺失值的行

替换某列中的Nan值

1
2
3
train_data['Alley'].fillna(value='Not Found', inplace=True)
print(train_data)

替换None字符串

1
2
print(train_data.replace('None', np.nan))

替换字符串的时候,如果替换改变原数据的值

1
2
train_data.replace('None', np.nan, inplace=True)

4.缺失值填充

参考:数据转化

6.4 缺失值插补

也可以使用sklearn对特征的缺失值进行填充,方法有2种:

  • 单变量:对第 i 个特征中的缺失值只使用该特征的某些信息来进行填充(impute.SimpleImputer)
  • 多变量:对第 i 个特征中的缺失值使用整个数据集的信息来填充(impute.IterativeImputer)

数值型单变量缺失值填充

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np
from sklearn.impute import SimpleImputer

# 数值型单变量缺失值填充
imp = SimpleImputer(missing_values=np.nan, strategy='mean')
imp.fit([[1, 2], [np.nan, 3], [7, 6]])
>> SimpleImputer()

# 缺失值填充 (1+7)/2=4和(2+3+6)/3=3.66666667
X = [[np.nan, 2], [6, np.nan], [7, 6]]
print(imp.transform(X))
[[4. 2. ]
[6. 3.66666667]
[7. 6. ]]

标称型单变量缺失值填充

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import numpy as np
from sklearn.impute import SimpleImputer
import pandas as pd

# 标称型变量缺失值填充
df = pd.DataFrame([["a", "x"],
[np.nan, "y"],
["a", np.nan],
["b", "y"]], dtype="category")
# 使用出现次数最多的值来填充缺失值
imp = SimpleImputer(strategy="most_frequent")
print(imp.fit_transform(df))

[['a' 'x']
['a' 'y']
['a' 'y']
['b' 'y']]

多变量填充

多变量填充是使用全部数据建模的方式进行填充缺失值:含有缺失值的特征被视为 y,而其他特征当作 x,对 (x, y)拟合回归模型,然后利用这个模型来预测 y 中的缺失值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer

imp = IterativeImputer(max_iter=10, random_state=0)
imp.fit([[1, 2], [3, 6], [4, 8], [np.nan, 3], [7, np.nan]])
>> IterativeImputer(random_state=0)

# 拟合出第2个变量是第1个变量的2倍
X_test = [[np.nan, 2], [6, np.nan], [np.nan, 6]]
print(np.round(imp.transform(X_test)))

[[ 1. 2.]
[ 6. 12.]
[ 3. 6.]]

最近邻填充

全文 >>

go学习笔记——pprof性能分析工具

可以使用pprof来分析golang程序的CPU性能,内存占用,block死锁,Goroutine性能等,pprof一般是在需要分析代码性能的时候才加入

1.分析Gin web服务的性能

可以使用 gin-contrib/pprof 这个工具,参考:Gin框架中使用pprof

添加依赖

1
2
go get github.com/gin-contrib/pprof@v1.4.0

在gin的路由上添加 pprof.Register(app)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
"net/http"

"github.com/gin-contrib/pprof"
"github.com/gin-gonic/gin"
)

func main() {
app := gin.Default()

// 性能分析
pprof.Register(app)

app.GET("/test", func(c *gin.Context) {
c.String(http.StatusOK, "test")
})
app.Run(":3000")
}

启动web应用后访问如下path

1
2
http://localhost:3000/debug/pprof/

可以看到如下页面

使用go tool pprof命令采集20s的goroutine(Goroutine 是 Go 语言中的一种轻量级线程,提供了并发执行代码的能力)指标数据,如果不设置采集时间是默认采集30s,每10ms采集一次

1
2
go tool pprof --seconds 20 http://localhost:18080/debug/pprof/goroutine

采集完毕后可以直接输入 web 来可视化查看数据,不过需要提前安装graphviz,否则会报

全文 >>

Java多线程——其他工具类CyclicBarrier、CountDownLatch和Exchange

CyclicBarrier

适用于:创建一组任务,它们并行地执行任务,然后在进行下一个步骤之前等待,直至所有任务完成。它使得所有的并行任务都将在栅栏处列队,因此可以一致地向前移动。

表示大家彼此等待,大家集合好后才开始出发,分散活动后又在指定地点集合碰面,这就好比整个公司的人员利用周末时间集体郊游一样,先各自从家出发到公司集合后,再同时出发到公园游玩,在指定地点集合后再同时开始就餐…

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
package java_thread;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CyclicBarrierTest {

public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final CyclicBarrier cb = new CyclicBarrier(3);
for(int i=0;i<3;i++){
Runnable runnable = new Runnable(){
public void run(){
try {
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"即将到达集合地点1,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));
cb.await();

Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"即将到达集合地点2,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));
cb.await();
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"即将到达集合地点3,当前已有" + (cb.getNumberWaiting() + 1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));
cb.await();
} catch (Exception e) {
e.printStackTrace();
}
}
};
service.execute(runnable);
}
service.shutdown();
}
}

全文 >>

Java多线程——可阻塞的队列BlockingQueue

阻塞队列Semaphore有些相似,但也不同,阻塞队列一方存放数据,另一方释放数据,Semaphore通常则是由同一方设置和释放信号量。

ArrayBlockingQueue

  只有put方法和take方法才具有阻塞功能

用3个空间的队列来演示阻塞队列的功能和效果。

用两个具有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
35
36
37
38
39
40
41
42
43
44
45
46
47
package java_thread;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class BlockingQueueTest {
public static void main(String[] args) {
final BlockingQueue queue = new ArrayBlockingQueue(3);
for(int i=0;i<2;i++){ //2个线程放数据
new Thread(){
public void run(){
while(true){
try {
Thread.sleep((long)(Math.random()*1000));
System.out.println(Thread.currentThread().getName() + "准备放数据!");
queue.put(1); //如果队列满的话,将在这里阻塞
System.out.println(Thread.currentThread().getName() + "已经放了数据," +
"队列目前有" + queue.size() + "个数据");
} catch (InterruptedException e) {
e.printStackTrace();
}

}
}

}.start();
}

new Thread(){ //1个线程取数据
public void run(){
while(true){
try {
//将此处的睡眠时间分别改为100和1000,观察运行结果
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "准备取数据!");
queue.take(); //如果队列空的话,将在这里阻塞
System.out.println(Thread.currentThread().getName() + "已经取走数据," +
"队列目前有" + queue.size() + "个数据");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

}.start();
}
}

全文 >>

Java排序算法——堆排序

堆排序

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
package sort;

public class Heap_Sort {

public static void main(String[] args) {
// TODO 自动生成的方法存根
Heap_Sort qs = new Heap_Sort();
int[] Arr = {10,9,8,7,6,5,4,3,2,1};
qs.heapSort(Arr);
for(int i=0;i<Arr.length;i++){
System.out.println(Arr[i]);
}
}

//调整函数
public void headAdjust(int[] elements,int pos,int len){
//将当前节点值进行保存
int swap = elements[pos];

//定位到当前节点的左边的子节点
int child = pos * 2 + 1;

//递归,直至没有子节点为止
while(child < len){
//如果当前节点有右边的子节点,并且右子节点较大的场合,采用右子节点和当前节点进行比较
if(child + 1 < len &amp;&amp; elements[child] < elements[child + 1]){
child += 1;
}

//比较当前节点和最大的子节点,小于则进行值交换,交换后将当前节点定位于子节点上
if(elements[pos] < elements[child]){
elements[pos] = elements[child];
pos = child;
child = pos * 2 + 1;
}
else{
break;
}

elements[pos] = swap;
}
}

//构建堆
public void buildHeap(int[] elements){
//从最后一个拥有子节点的节点开始,将该节点连同其子节点进行比较,
//将最大的数交换与该节点,交换后,再依次向前节点进行相同交换处理,
//直至构建出大顶堆(升序为大顶,降序为小顶)
for(int i=elements.length/2; i>=0; i--){
headAdjust(elements, i, elements.length);
}
}

public void heapSort(int[] elements){
//构建堆
buildHeap(elements);

//从数列的尾部开始进行调整
for(int i=elements.length-1; i>0; i--){
//堆顶永远是最大元素,故,将堆顶和尾部元素交换,将
//最大元素保存于尾部,并且不参与后面的调整
//alert(elements);
int swap = elements[i];
elements[i] = elements[0];
elements[0] = swap;
//alert(elements);
//进行调整,将最大的元素调整至堆顶
headAdjust(elements, 0, i);
//alert(elements);
}
}

}

全文 >>