儒冠多误身
2019.04.20个人总结
pd.read_csv('demo.csv',na_values=['XYZ','NA','-999',0])
基本框架
.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'})
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])
df1.join(df2)
,按照index连接
df1.combine_first(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])
map函数
a = {'col1_1':'a','col1_3':'c'}
df['col1'].map(a)
是否有缺失值
诊断
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()# 缺失值占比
舍弃
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()
统计
df.duplicated(subset=['col1','col3']).value_counts()
先排序,再去重
df.sort_values(by='col1').dropduplicates(subset=['col2','col3'])
去重的用法
DataFrame.drop_duplicates(subset=None, keep='first', inplace=False)
'first','last','False'
,False:一行都不保留要注意判断,是否包含不能转换的元素
df.col.astype()
拆分字符串
Series.str.split(pat=None,
n=-1,
expand=False)
统计长度不为N的元素的个数
df1 = df['col'].str.split('_').map(len) # 判断切割后的元素长度N
(df1 != N).sum()
df['col'].str.contains('子字符')
(~df.col1.str.contains('元/平米')).sum()
较慢的法子
df['col'].map(
lambda x:round(float(x.replace('子字符',''))/1000,2))
推荐
round(df['col'].str.replace('子字符','').dropna().astype(np.float32).map(lambda x:x/1000),2)
分类字符串,转换为离散变量
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
le.fit(df['col5']) # 遍历一遍
le.transform(df['col5']) # 将分类字符串转换为离散变量
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)
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行
降采样
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= # 聚合到时期或时间戳
)
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')
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')
八类产品两个指标val1,val2,权重分别为0.6,0.4
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)
df['col'].isnull().sum()
df['col'].dropna()
df['col'].fillna()
趋势
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() # 众数
箱线图
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)]
方法一:
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() # 饼图
散点图
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')
sns.regplot(x='col1',
y='col2',
data=df,
fit_reg=False,# 不添加预测线,拟合直线
y_jitter=0.5 # 类别值,添加数据浮动
)
df.corr()
# 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]))
连续数据离散化
gcut = pd.cut(df['col1'],bins=10,right=False)
gcut_count = gcut.value_counts(sort=False)
df["%s分组区间"%kcol1]=gcut
帕累托分析
先由大到小排序
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))
定量字段分布
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')
# 折线图
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='--')# 辅助线
假设:要检验的统计量(近似)满足正态分布
常见用途:检测总体平均值是否等于某个常量
python
零假设:复旦大学男生平均身高175cm
备择假设:复旦大学男生平均身高不是175cm
conda install statsmodels
z, pval = statsmodels.stats.weightstats.ztest(X,values=175)
适用于样本量较少(n<30)
自由度:样本数量减去1
t分布比正态分布宽(不确定性更高)
python
零假设:复旦大学男生平均身高175cm
备择假设:复旦大学男生平均身高不是175cm
conda install scipy
t,pval = scipy.stats.ttest_1samp(X,popmean=175)
零假设:复旦大学和上海大学男生平均身高一样
备择假设:复旦大学和上海大学男生平均身高不一样
t, pval = scipy.stats.ttest_ind(X1,X2)
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)
皮尔逊系数
[-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))