python-数据处理

本文最后更新于:July 15, 2022 am

一、缺失值处理

1
2
3
4
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
删除记录 数据插补 不处理
1
2
3
4
5
6
7
8
9
10
#  判断是否是缺失值
s = pd.Series([12,33,45,23,np.nan,66,54,np.nan,99])
df = pd.DataFrame({'value1':[12,33,45,23,np.nan,np.nan,66,54,np.nan,99,100],
'value2':['a','b','c','d','e',np.nan,np.nan,'f','g',np.nan,'g']})
# 创建数据
print(s.isnull())
print(df.notnull())
print(df['value1'].notnull())

print(s[s.isnull() == False])
1
2
3
4
5
6
7
8
9
10
11
12
13
#  删除缺失值

# 判断是否是缺失值
s = pd.Series([12,33,45,23,np.nan,66,54,np.nan,99])
df = pd.DataFrame({'value1':[12,33,45,23,np.nan,np.nan,66,54,np.nan,99,100],
'value2':['a','b','c','d','e',np.nan,np.nan,'f','g',np.nan,'g']})
# 创建数据

s.dropna(inplace = True)
df.dropna(inplace= True)
print(s)
df
# 注意inplace参数,默认为False - 生成新的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#  填充/替换缺失值   - fillna\  replace

s = pd.Series([12,33,45,23,np.nan,66,54,np.nan,99])
df = pd.DataFrame({'value1':[12,33,45,23,np.nan,np.nan,66,54,np.nan,99,100],
'value2':['a','b','c','d','e',np.nan,np.nan,'f','g',np.nan,'g']})
# 创建数据
s.fillna(0,inplace = True) # value为填充值
print(s)
print('---')

df['value1'].fillna(method = 'pad',inplace =True)
print(df)
print('---')
# pad/ffill - 用之前的数据填充
# backfill / bfill - 用之后的数据填充

s = pd.Series([1,1,1,1,2,2,2,3,4,5,np.nan,np.nan,66,54,np.nan,99])
s.replace(np.nan,'缺失数据',inplace = True)
print(s)
print('----')
缺失值插补
几种思路: 均值 中位数 众数插补 临近值插补 插值法
均值 中位数 众数插补
1
2
3
4
5
6
7
8
9
10
11
12
13
s = pd.Series([1,2,3,np.nan,3,4,5,5,5,5,np.nan,np.nan,6,6,7,12,2,np.nan,3,4])
#print(s)
print('---')

u = s.mean()
me = s.median()
mod = s.mode()
print('均值为:%.2f,中位数为:%.2f'%(u,me))
print('众数为:',mod.tolist())
print('---')

s.fillna(u,inplace=True)
s
1
2
3
4
#  (2)  临近值插补
s = pd.Series([1,2,3,np.nan,3,4,5,5,5,5,np.nan,np.nan,6,6,7,12,2,np.nan,3,4])
#print(s)
s.fillna(method = 'ffill',inplace = True) # 用前值插补
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#  (3)   拉格朗日插值法

from scipy.interpolate import lagrange
x = [3,6,9]
y = [10,8,4]
plt.scatter(x,y)
print(lagrange(x,y))
print(type(lagrange(x,y)))
# 输出值为多项式的n个系数
# 这里输出3个值,分别为 a0 a1 a2

print('差值10为:%.2f'% lagrange(x,y)(10))
print('---')

df = pd.DataFrame({'x':np.arange(15)})
df['y'] = lagrange(x,y)(df['x'])
plt.plot(df['x'],df['y'],linestyle = '--',color = 'k')
拉格朗日插值法的应用步骤:
1、 创建数据
2、 缺失值的数量
3、 密度图查看确实的情况 (直接生成图会自动删除相应的缺值)
4、 直接拿缺失值的前5个和后五个数据就可以完成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 5
df f(s,n,k=5):
y = s[list(range(n-k))]
y = y[y.notnull()]
return(lagrange(y.index,list(y))(n))

for i in range(len(data)):
if data.isnull()[i]:
data[i] = f(data,i)
print(f(data,i))


// 6
data.dropna(inplace =True)
data.plot(kind = 'kde',style = '--k',ax = axes[3] ,grid =True , title = '拉格朗日插值法后',xlim = [-50,150])
print('Finished')

二、异常值处理

1
2
3
4
5
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy import stats
%matplotlib inline
# 异常值(离群值)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#  异常值分析
# (1) 3(西格玛)原则 - 超过它的值为异常值

data = pd.Series(np.random.randn(10000)*100)
data.head()

u = data.mean()
std = data.std()
stats.kstest(data,'norm',(u,std))

fig = plt.figure(figsize = (10,6))
ax1 = fig.add_subplot(2,1,1)
data.plot(kind='kde',grid = True,style = '-k',title = '密度图')
plt.axvline(3*std,color='r',linestyle='--',alpha=0.8)
plt.axvline(-3*std,color='r',linestyle='--',alpha=0.8)
# 绘制密度曲线

error = data[np.abs(data - u) > 3*std]
data_c = data[np.abs(data - u) <= 3*std]
ax2 = fig.add_subplot(2,1,2)

plt.scatter(data_c.index,data_c,color='k',marker='.',alpha=0.3)
plt.scatter(error.index,error,color='r',marker='.',alpha=0.8)
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
# (2)  箱型图分析(更加标准,能够筛选出相对多一点的异常值)

fig = plt.figure(figsize=(10,6))
ax1 = fig.add_subplot(2,1,1)
color = dict(boxes='DarkGreen',whiskers='DarkOrange',medians='DarkBlue',caps='Gray')
data.plot.box(vert = False,grid = True,color = color,ax = ax1) # ,label = '样本数据'
# 以内限为界

s = data.describe()
q1 = s['25%']
q3 = s['75%']
iqr = q3 - q1
q1,q3,iqr
mi = q1 - 1.5*iqr
ma = q3 + 1.5*iqr

ax2 = fig.add_subplot(2,1,2)
error = data[(data<mi)|(data>ma)]
data_c = data[(data>=mi) & (data<=ma)]
print('异常值共%i条'% len(error))
# 筛选出异常值error, 删除异常值之后的数据data_c

plt.scatter(data_c.index,data_c,color='k',marker='.',alpha=0.3)
plt.scatter(error.index,error,color='r',marker='.',alpha=0.5)
plt.xlim([-10,10010])
plt.grid()
# 图像表达

三、数据归一化处理

1
2
3
4
5
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy import stats
%matplotlib inline
数据标准化
0-1 标准化
将数据的最大值记录下来,并通过max-min作为基数(0,1)进行数据的归一处理
x = (x - min) / (max - min)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
df = pd.DataFrame({'value1':np.random.rand(10)*20,
'value2':np.random.rand(10)*100})
print(df.head())
print('---')
# 创建数据

def f(df,*cols):
df_n = df.copy()
for col in cols:
ma = df_n[col].max()
mi = df_n[col].min()
df_n[col+'_n'] = (df_n[col] - mi) / (ma - mi)
return(df_n)

df_n = f(df,'value1','value2')
df_n
数据标准化(变成正态分布)
(2) Z-score标准化
Z分数是一个分数与平均数的差再除以标准差的过程
以标准差为计算单位,在原始分数低于平均值Z为负,反之则为正
一个给定分数距离平均数多少标准差
什么情况用Z-score标准化:
在分类、聚类算法中,需要使用距离来度量相似度的时候,会表现更好
相似性 平均水平
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
df = pd.DataFrame({'value1':np.random.rand(10)*100,
'value2':np.random.rand(10)*100})
print(df.head())
print('---')
# 创建数据

def f_z(df,*cols):
df_n = df.copy()
for col in cols:
u = df_n[col].mean()
std = df_n[col].std()
df_n[col+'_zn'] = (df_n[col] -u) / std
return(df_n)
df_z = f_z(df,'value1','value2')
u_z = df_z['value1_zn'].mean()
std_z = df_z['value2_zn'].std()
print(df_z)
案例
八类产品两个指标value1(权重为0.6),value2(权重为0.4),
判断哪一个产品指标状况最好
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
df = pd.DataFrame({'value1':np.random.rand(10)*30,
'value2':np.random.rand(10)*100},
index = list('ABCDEFGHIJ'))
print(df.head())
print('---')
# 创建数据

df_n = f(df,'value1','value2')
# 进行数据标准化处理

df_n['f'] = df_n['value1_n'] *0.6 + df_n['value2_n']*0.4
df_n.sort_values(by = 'f',inplace =True,ascending = False)
df_n['f'].plot(kind='line',style = '--.',alpha=0.8,grid=True)
df_n
# 查看综合指标状况

四、连续数据离散值处理

1
2
3
4
5
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy import stats
%matplotlib inline
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#  等宽法 - 将数据均匀划分为n份,每份的间距相等
# cut方法

ages = [20,22,25,27,21,37,31,61,45,41,32]
# 有一组年龄数据,将这些数据划分为‘18-25’ ‘26-35’ ‘36-60’ ‘60以上’ 几个面元

bins = [18,25,35,60,100]
cats = pd.cut(ages,bins)
print(cats,type(cats))

print(cats.codes,type(cats.codes)) # 0-3对应分组后的四个区间
print(cats.categories,type(cats.categories)) # 四个区间,结果为index
print(pd.value_counts(cats)) # 按照区间计数
print('---')

print(pd.cut(ages,bins,right = False)) # 左闭右开
1
2
3
4
5
6
7
8
9
10
11
df = pd.DataFrame({'ages':ages})
group_names = ['Youth','YoungAdult','MiddleAged','Senior']
s = pd.cut(df['ages'],bins)
df['ages_a'] = s
cut_counts = s.value_counts(sort = False)
cut_counts


# 散点图格式化
plt.scatter(df.index,df['ages'],cmap = 'Reds',c = cats.codes)
plt.grid()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#  等频法 - 以相同数量的记录放进每个区间
# qcut 方法

data = np.random.rand(1000)
s = pd.Series(data)
print(s.head())
cats = pd.qcut(s,4) # 按四分位分数进行切割,可以试试pd.qcut(data,10)
print(cats.head())
print(pd.value_counts(cats))
print('---')
# 不能保证每个面元都有相等的个数
# 也可以自定义

plt.scatter(s.index,s,cmap = 'Greens',c = pd.qcut(data,4).codes)
plt.xlim([0,1000])
plt.grid()
# 颜色按照codes分类