儒冠多误身
2019.04.20个人总结
- 第一步:备份源数据到其他盘符、硬盘、u盘、网盘等
- 需求分析
- 数据提取
- 数据清洗
- 数据分析
- 报告撰写
- 报告分享
- 投入应用收集反馈
文章目录
1. 目标确定
2. 数据获取
数据来源
- 数据可信度
3. 数据清洗
3.1 预处理
3.1.1 读取
pd.read_csv('demo.csv',na_values=['XYZ','NA','-999',0])
3.1.2 观察
-
基本框架
.shape .info() .head() pd.value_counts(df['col']) df['col'].value_counts()
-
数据特征
- 连续型数据
- 离散型数据
-
索引值是可以重复的
df.index.is_unique
-
重命名
df.rename(index=str.lower,columns={'col1':'a','col2':'b'})
3.1.3 关联
-
pd.merge(),相当于SQL的join
pd.merge(left,right,left_on=,right_on=,suffixes=('_x','__y'))
-
pd.concat(),堆叠
pd.concat([df1,df2,df3,s1],axis=1)# index pd.concat([s1,s2,s3])
- axis=0,columns
-
df1.join(df2)
,按照index连接 -
df1.combine_first(df2)
,修补- 结果会同时包含df1和df2的行与列
- df1的缺失值NaN,会被df2对应位置的数值修补
def func(x): a = str(x) return pd.Series(a+'_a') df_new=df['col'].apply(func) df_new.rename(columns={}) df.combine_first(df_new)
-
s1.combine_first(s2)
修补 -
np.concatenate([arr1,arr2])
- axis=1,左右连接
- axis-0,堆叠
-
map函数
-
a = {'col1_1':'a','col1_3':'c'} df['col1'].map(a)
-
3.2 缺失值
3.2.1 缺失值统计
-
是否有缺失值
- 缺失的原因
-
诊断
len(df['col'].unique()) len(df) df['col'].duplicatd() df['col'].drop_duplicates() df.drop_duplicates(subset=['col1','col3'],keep=False,inpalce=True) df.isnull().values.any() df.isnull().any() df['col'].isnull() df['col'].isnull().values.any()
-
统计
df.isnull().sum() df.isnull().sum().sum() df.isnull().sum() / df.count()# 缺失值占比
3.2.2 缺失值填充
-
舍弃
df.dropna() df.dropna(how='any') df.dropna(thresh = 3)# 每行缺失值超过3个的都舍弃 df.dropna(how='all',axis=1)# 列
-
填充
df.fillna(0) df.fillna({'col1':1,'col3':11}) df.fillna(method='ffill') df.fillna(method='bfill',limit=3)# 限制填充数量 df['col'].fillna(df['col'].mean()) df['col'].fillna(df.groupby('col')[].transform('mean'))#其结构与df的结构一致
-
内插法补齐[处理有规律数据,时间戳等]
df.interpolate()
3.3 重复值
-
统计
df.duplicated(subset=['col1','col3']).value_counts()
-
先排序,再去重
df.sort_values(by='col1').dropduplicates(subset=['col2','col3'])
- 排序会将col1列NaN值放在最下面,可确保去重时不会将该列为NaN的值保留
- 因为去重时,默认保留第一次出现的行
-
去重的用法
DataFrame.drop_duplicates(subset=None, keep='first', inplace=False)
- keep,默认:删除重复项并保留第一次出现的元素
'first','last','False'
,False:一行都不保留
- keep,默认:删除重复项并保留第一次出现的元素
3.4 转换
3.4.1 格式转换
-
要注意判断,是否包含不能转换的元素
df.col.astype()
3.4.2 字符串转换
3.4.2.1 拆分字符串
-
拆分字符串
Series.str.split(pat=None, n=-1, expand=False)
- pat:分隔符,默认为所有空字符,包括空格、换行符\n、制表符\t
- n:切几刀,默认-1,有多少切多少
- expand=
- False,返回Series
- True,返回DataFrame
- 结合df1.combine_first(df_new)
- 注意column的名称
-
统计长度不为N的元素的个数
df1 = df['col'].str.split('_').map(len) # 判断切割后的元素长度N (df1 != N).sum()
3.4.2.2 诊断是否包含
-
df['col'].str.contains('子字符') (~df.col1.str.contains('元/平米')).sum()
3.4.2.3 替换
-
较慢的法子
df['col'].map( lambda x:round(float(x.replace('子字符',''))/1000,2))
- round(a,2)函数,保留a,2位小数
-
推荐
round(df['col'].str.replace('子字符','').dropna().astype(np.float32).map(lambda x:x/1000),2)
3.4.2.4 类别字符串转换为离散变量
-
分类字符串,转换为离散变量
from sklearn.preprocessing import LabelEncoder le = LabelEncoder() le.fit(df['col5']) # 遍历一遍 le.transform(df['col5']) # 将分类字符串转换为离散变量
apply
df['col'].apply(str.upper)
df['col'].apply(自定义函数)
def func(x):
a = x.strip().split(',')
return np.Series(a[1],a[3])
df['col'].apply(func)
3.5 逻辑错误值清洗
3.6 选取行列
3.6.1 sample()
-
DataFrame.sample(n=None, frac=None, replace=False,weights=None, random_state=None, axis=None*) s.sample(n=3)# 选3个随机元素 df.sample(frac = 0.1) # 随机取10%的元素 df.sample(n=3) # 随机取3行
3.6.2 时间采样
-
降采样
s.resample('M').mean()
-
升采样,填充
s.resample('H').ffill() s.resample('H').bfill()
-
s1.resample(freq=, # 采样频率字符串 axis=, # 采样的轴,默认axis=0 fill_method=,#升采样插值 closed=, # 降采样中,各时间段的哪一端是闭合的,right(默认) label=, # 降采样中,如何设置聚合值的标签 loffset=, # 面元标签的时间校正值 limit=, # 填充最大量 kind= # 聚合到时期或时间戳 )
3.6.3
- 结合业务,先删除和分析无关的指标
- 查看相关系数矩阵
- 判断各个变量相关性
- 相关性太大的可以考虑删除此列
- 如果变量比较重要,可以考虑主成分/因子分析进行降维处理
3.7 关联性验证
4. 数据整理
4.1 数据规范化
4.1.1 离散化
4.1.2 归一化
- Z-score标准化:
- 在分类、聚类算法中,需要使用距离来度量相似性的时刻,Z-score表现更好
- 经过处理的数据符合标准正太分布,即均值0,标准差1
- 数学意义:
- 一个给定分数 距离平均数 多少个标准差
4.1.2.1 0~1标准化
-
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_nc = f(df,'col1','col2')
4.1.2.2 Z标准化
-
z = (x- u) / std
-
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_zn = f_z(df,'col1','col2')
4.1.2.3 权重叠加
-
八类产品两个指标val1,val2,权重分别为0.6,0.4
- 权重统计 =(a *3 + b*2 + c *1)/6
- 先对其0~1标准化,再指标权重叠加
df_nv = f(df,'val1','val2') df_nv['f'] = df_n['val1_n']*0.6 + df_n['val2_n']*0.4 df_nv.sort_values('f',inplace=True,ascending=False) df_nv['f'].plot(style='--.k',alpha=0.8,grid=True)
4.2 指标计算
4.2.1 统计计算
4.3 格式转换
- 转换为制图、指标所需格式
5. 数据分析
5.1 单属性(变量)分析
5.1.1 异常值分析
5.1.1.1 缺失值
df['col'].isnull().sum()
df['col'].dropna()
df['col'].fillna()
5.1.1.2 集中趋势、离散趋势
-
趋势
df['col'].mean() # 均值 df['col'].median() # 中位数 df['col'].quantile(0.25) # 分位数 df['col'].std() # 标准差 df['col'].kurt() # 峰度 df['col'].skew() # 偏度 df['col'].describe() df['col'].mode() # 众数
5.1.1.3 离群值
-
箱线图
- 上边缘:Q1 - 1.5IQR
- 箱体:Q1(第一分位数),Q3(第三分位数)
- 中横线:中位数
- 四分位差IQR: Q3-Q1
- 下边缘:Q3 + 1.5IQR
Q3 = df['col'].quantile(0.75) Q1 = df['col'].quantile(0.25) a = Q3 - Q1 # k 取 1.5~3 df['col'][(df['col']>Q1-k*a)&(df['col']<Q3+k*a)]
切比雪夫定理
- 前提(无),经验公式:
- 至少有75%的数据,位于平均数2个标准差范围内
- 至少有89%的数据,位于平均数3个标准差范围内
- 至少有96%的数据,位于平均数5个标准差范围内
- 切比雪夫定理v2.0
- 在正态分布中
- 正态分布中,至少有68%的数据,位于平均数1个标准差范围内
- 正态分布中,至少有95%的数据,位于平均数2个标准差范围内
- 正态分布中,至少有99.8%的数据,位于平均数3个标准差范围内
5.1.2结构分析
5.1.2.1 静态结构分析
-
方法一:
sns.distplot(df['col'],kde=False)# 查看其分布
-
方法二:
df['col'].value_counts() df['col'].value_counts(normalize=True) # 显示为比例 df['col'].value_counts(bins=np.arange(df['col'].min(),df['col'].max()+10,10)) # bins为左闭右开 np.histogram(df['col'].values,bins=np.arange()) # bins为左开右闭
-
方法三:可视化
sns.boxplot() # 箱线图 sns.pointplot() # 折线图 sns.countplot() # 柱状图 sns.displot() # 直方图、密度图 plt.pie() # 饼图
5.2 双变量
5.2.1 两个变量间的分布关系
5.2.1.1 散点图
-
散点图
sns.jointplot(x='col1', y,=col2' , data=df, kind='scatter', stat_func=<function pearsonr at 0x089DA6A8>, color=None, size=6, ratio=5, space=0.2, dropna=True, xlim=None, ylim=None, joint_kws=None, marginal_kws=None, annot_kws=None)
-
类别值间的散点图
# 方法一 sns.stripplot(x='col1', # 类别值 y='col2', # 类别值 data=df, jitter=True # 让绘图点有浮动效果 ) # 方法二 sns.swarmplot(x='col1', y='col2', data=df, hue='col3' ) sns.swarmplot(x='Survived',y='Age',data=df,hue='Sex')
5.2.1.2 相关性
-
sns.regplot(x='col1', y='col2', data=df, fit_reg=False,# 不添加预测线,拟合直线 y_jitter=0.5 # 类别值,添加数据浮动 )
-
df.corr()
5.3 分布分析
- 定性字段分布:柱状图 + 饼图
- 定量字段分布:直方图
5.3.1 极值差
# apply法
df[['col1','col2']].apply(lambda x:x.max() - x.min())
# 自定义函数法
def d_range(data,*cols):
krange=[]
for col in cols:
crange=df[col].max() - df[col].min()
krange.append(crange)
return(krange)
kcol1='col1'
kcol2='col2'
dr = d_range(df,kcol1,kcol2)
print('%s极差为:%f\n%s极差为:%f'%(kcol1,dr[0],kcol2,dr[1]))
5.3.2 频率分布
-
连续数据离散化
gcut = pd.cut(df['col1'],bins=10,right=False) gcut_count = gcut.value_counts(sort=False) df["%s分组区间"%kcol1]=gcut
5.3.2.1 累计频率-帕累托分析指标
-
帕累托分析
-
先由大到小排序
-
p = df.cumsum() / df.sum() key = p[p>0.8].index[0] key_num = df.index.tolist().index(key) p.plot(style='--ko',secondary_y=True) plt.axvline(key_num,color='r',linestyle='--') plt.text(key_num+0.2,p[key],'累计占比为%.3f%%'%(p[key]*100),color='r')#累计占比超过80%的节点
-
-
a = pd.DataFrame(gcut_count).rename({gcut_count.name:'频数'},inplace=True) # 创建分组DataFrame a['频率']=a['频数'] / a['频数'].sum() # 频率 a['累计频率']=a['频率'].cumsum() # 累计频率 # 转换百分数 a['频率']=a['频率'].apply(lambda x:"%.2f%%"%(x*100)) a['累计频率']=a['累计频率'].apply(lambda x:"%.2f%%"%(x*100))
5.3.2.2 可视化
-
定量字段分布
- 柱状图
- 堆积柱状图
- 百分比柱状图
plt.rcParams['font.sans-serif']=['SimHei'] # 全局设置为黑体 plt.rcParams['axes.unicode_minus'] = False # 显示负座标 plt.rcParams['font.size']=20 # 字号 a['频率'].plot.bar(figsize=(12,3),alpha=0.7,grid=True) # 添加标签 x=len(a) y=a['频率'] m=a['频数'] for i,j,k in zip(range(x),y,m): plt.text(i-0.1,j+0.01,'%i'%k,color='k') # 百分比柱状图 df.div(df.sum(1).astype(float),axis=0).plot.barh(stacked=True,color=['b','r','k','g'],fontsize=15,figsize=(12,6))
-
定性字段分布
# 柱状图 cxx['频率'].plot.bar(figsize=(12,3)) # 添加标签 x=len(cxx) y=cxx['频率'] m=cxx['频数'] for i,j,k in zip(range(x),y,m): plt.text(i-0.1,j+0.01,'%i'%k,color='k') # 饼图 plt.figure(num=2) # 饼图在直方图下方显示 plt.pie(cxx['频数'], labels=cxx.index, autopct='%.2f%%',shadow=True) plt.axis('equal')
5.1.3 对比
5.4 对比分析
- 对比分析:两个互相联系的指标进行比较
5.4.1 绝对值比较(相减)
-
# 折线图 df.plot(kind='line', style='--', alpha=0.8, figsize=(10,3) title=('AB产品销量对比——折线图') ) # 柱状图 df.plot(kind='bar', width=0.8, alpha=.8, figsize=(10,3), title='AB产品销量对比-柱状图') # 相减 x=range(len(df)) y1=df['A'] y2=-df['B'] fig3 = plt.figure(figsize=(10,6)) plt.subplots_adjust(hspace=0.3) ax1=fig3.add_subplot(2,1,1) plt.bar(x,y1,width=1,facecolor='r') plt.bar(x,y2,width=1,facecolor='g') ax2 = fig3.add_subplot(2,1,2) y3 = df['A']-df['B'] plt.plot(x,y3,'--go') plt.grid() # 添加网格 plt.axhline(0,color='r',linstyle='--')# 辅助线
5.4.2 相对值比较(相除)
5.4.3 结构分析
5.4.4 比较分析
5.4.5 空间比较分析
5.4.6 动态比较分析
5.1.4 预测
5.1.5 洞察结论,制图-看图说话
- 根据描述分析结论,形成洞察结果
5.2 数据建模
- 模型选择
- 模型测试
- 迭代优化
- 模型加载
5.2.1 线性回归(初学者)
5.2.2 聚类模型(初学者)
5.2.3
6. 可视化
1 分析图表
单维度
- 柱状图
- 折线图
- 饼图
- 散点图
多维度
- 热力图
- 箱线图
- 矩阵
- 散点图
空间图表
关系图表
2 动态交互
- Echarts
- 百度图说
- Python与Echarts的结合
3 商业智能
- BDP
- Tableau
- power BI
- 脉策数据-Datamap
7. 业务理解
8 验证型分析
- 基本概念
- 随机变量
- 离散随机变量:取值可能性有限
- 连续随机变量:有无限个可能取值的随机变量
- 概率分布
- 连续随机变量概率分布
- 概率密度函数
- 连续随机变量概率分布
- 假设检验
- P-value
- 5%
- 1%
- 0.1%
- 中心极限定理
- 大量相互独立的随机变量,其均值的分布以正态分布为极限
- 随机变量
8.1 假设检验基本流程
- 提出零假设(我们希望推翻的结论),及备择假设(我们希望证明的结论)
- 在零假设的前提下,推断当前样本统计量出现的概率
- 统计量可符合不同分布,及对应不同的检验方法
- 设定一个拒绝零假设的阈值(常见5%,即统计学意义“显著”,significant),如果目前样本统计量在零假设下出现的概率小于阈值,则拒绝零假设,承认备择假设。
- 单样本
- z检验
- t检验
- 双样本
- t检验
8.2 单样本z检验
-
假设:要检验的统计量(近似)满足正态分布
-
常见用途:检测总体平均值是否等于某个常量
-
python
零假设:复旦大学男生平均身高175cm
备择假设:复旦大学男生平均身高不是175cmconda install statsmodels z, pval = statsmodels.stats.weightstats.ztest(X,values=175)
- X:样本集
8.4 单样本t检验
-
适用于样本量较少(n<30)
-
自由度:样本数量减去1
-
t分布比正态分布宽(不确定性更高)
-
python
零假设:复旦大学男生平均身高175cm
备择假设:复旦大学男生平均身高不是175cmconda install scipy t,pval = scipy.stats.ttest_1samp(X,popmean=175)
- 比z检验更常用
8.5 双样本t检验
-
零假设:复旦大学和上海大学男生平均身高一样
备择假设:复旦大学和上海大学男生平均身高不一样t, pval = scipy.stats.ttest_ind(X1,X2)
- 双样本t检验最常见的用法就是比较两组样本的平均值是否一致
可视化
-
sns.distplot(df['col1']) # 分布图 sns.regplot(x='col1',y='col3',data=df) # 连续变量间的相关性 sns.boxplot(x='col2',y='col3',data=df) # 离散变量与连续变量的相关性 # 热力图 info=['col1','col3','col5','col8'] sns.set(font_scale=0.7) # 设置字体大小 sns.heatmap(df[info].corr(), 相关性 annot=True, # 显示参数值 vmin=0, # vmax=1)
9.6.1 相关性系数
-
皮尔逊系数
-
[-1,1],[负相关,正相关]
-
from scipy.stats.stats import pearsonr pearsonr(x,y)
-
df.corr()
-
交叉检验
-
多模型交叉检验
from sklearn.linear_model import LinearRegression from sklearn.ensemble import RandomForesRegressor from sklearn.model_selection import cross_val_score info=['col1','col3','col4','col5'] lr = LinearRegression() rf = RandomForestRegressor() models = [lr,rf] for model in models: scores = cross_val_score(model,df[info],df['col10'],cv=5,scoring='neg_mean_absolute_error') print(type(model).__name__,np.mean(scores))