版本:
21.8.30
下载地址:
小程序数据库内搜索 EDA方法记录
已将本文档整理成PDF文档分享(无水印,可编辑)
后续文档仍将继续更新
数据探索的目的:及早发现数据的一些简单规律或特征
数据清洗的目的:留下可靠数据,避免脏数据的干扰。
两者没有严格的先后顺序,经常在一个阶段进行。
分为:
(1)数据质量分析(跟数据清洗密切联系):缺失值分析、异常值分析、一致性分析、重复数据或含有特殊符号的数据分析
(2)数据特征分析(分布、对比、周期性、相关性、常见统计量等):
遍历文件夹,读取指定文件夹下文件的名称
os.listdir()方法:用于返回指定的文件夹包含的文件或文件夹的名字的列表。这个列表以字母顺序。
使用read_csv
pandas.read_csv可以读取csv(逗号分隔)文件、文本类型的文件text、log类型到DataFrame(可以理解为pandas中的一类数据格式)
# 示例
import pandas as pd
df = pd,read_csv('name.csv')
函数方法:
pandas.read_csv(filepath_or_buffer, sep=', ', delimiter=None, header='infer', names=None, index_col=None, usecols=None, squeeze=False, prefix=None, mangle_dupe_cols=True, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skipinitialspace=False, skiprows=None, skipfooter=0, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, skip_blank_lines=True, parse_dates=False, infer_datetime_format=False, keep_date_col=False, date_parser=None, dayfirst=False, iterator=False, chunksize=None, compression='infer', thousands=None, decimal=b'.', lineterminator=None, quotechar='"', quoting=0, doublequote=True, escapechar=None, comment=None, encoding=None, dialect=None, tupleize_cols=None, error_bad_lines=True, warn_bad_lines=True, delim_whitespace=False, low_memory=True, memory_map=False, float_precision=None)
参数解释
filepath_or_buffer :可以是URL,可用URL类型包括:http, ftp, s3和文件。对于多文件正在准备中本地文件读取。 sep:如果不指定参数,则会尝试使用逗号分隔。分隔符长于一个字符并且不是‘\s+’,将使用python的语法分析器。并且忽略数据中的逗号。正则表达式例子:’\r\t’。 delim_whitespace : 指定空格(例如’ ‘或者’ ‘)是否作为分隔符使用,等效于设定sep=’\s+’。如果这个参数设定为True那么delimiter 参数失效。 header :指定行数用来作为列名,数据开始行数。如果文件中没有列名,则默认为0【第一行数据】,否则设置为None。如果明确设定 header = 0 就会替换掉原来存在列名。header参数可以是一个list例如:[0,1,3],这个list表示将文件中的这些行作为列标题(意味着每一列有多个标题),介于中间的行将被忽略掉。注意:如果skip_blank_lines=True 那么header参数忽略注释行和空行,所以header=0表示第一行数据而不是文件的第一行。 names :用于结果的列名列表,如果数据文件中没有列标题行,就需要执行 header=None。names属性在header之前运行默认列表中不能出现重复,除非设定参数mangle_dupe_cols=True。 index_col :用作行索引的列编号或者列名,如果给定一个序列则有多个行索引。 usecols:返回一个数据子集,该列表中的值必须可以对应到文件中的位置(数字可以对应到指定的列)或者是字符传为文件中的列名。例如:usecols有效参数可能是 [0,1,2]或者是 [‘foo’, ‘bar’, ‘baz’]。使用这个参数可以加快加载速度并降低内存消耗。 prefix:在没有列标题时,也就是header设定为None,给列添加前缀。例如:添加prefix= ‘X’ 使得列名称成为 X0, X1, … dtype: 每列数据的数据类型。例如 {‘a’: np.float64, ‘b’: np.int32} skipinitialspace:忽略分隔符后的空白(默认为False,即不忽略). skiprows :需要忽略的行数(从文件开始处算起),或需要跳过的行号列表(从0开始)。 nrows :需要读取的行数(从文件头开始算起)。 na_values :一组用于替换NA/NaN的值。如果传参,需要制定特定列的空值。默认为‘1.#IND’, ‘1.#QNAN’, ‘N/A’, ‘NA’, ‘NULL’, ‘NaN’, ‘nan’`. keep_default_na:如果指定na_values参数,并且keep_default_na=False,那么默认的NaN将被覆盖,否则添加 na_filter:是否检查丢失值(空字符串或者是空值)。对于大文件来说数据集中没有空值,设定na_filter=False可以提升读取速度。 skip_blank_lines :如果为True,则跳过空行;否则记为NaN。
常用参数解释:
全部写入
import pandas as pd
data = pd.DataFrame(要写入的数据源)
data.to_csv('文件名.csv',index = false,encoding = 'utf-8,mode='a'') #index= False的意思是不把index保存进文件中,mode='a'是表示以追加的方式加入文件中
)
添加,按行写入文件中
f=open(path,'a+',newline='')#newline设定可以让写出的csv中不包含空行
writer=csv.writer(f)
for row in range(b.shape[0]):
writer.writerow(b.iloc[row])#按行将数据写入文件中
f.close()
dataframe pd.read_excel('文件名.xlsx')
dataframe = pd.DataFrame(数据源)
datafram.to_excel('文件名.xlsx',sheetname='表名')
拼接两个数组
np.concatenate( ( array1,array2) )
拼接两个dataframe
pd.concat( [ dataframe1,dataframe2 ] )
np.random.shuffle()
import numpy.random
np.random.shufflr(data)
np.random.permutation
permutation = list(np.random.permutation(m)) #m为样本数
shuffled_X = X[permutation]
shuffled_Y = Y[permutation].reshape((1,m))
sample
# sample()参数frac是要返回的比例,比如df中有10行数据,我只想返回其中的30%,那么frac=0.3
# 以下代码实现了从“CRASHSEV”中选出1,2,3,4的属性,乱序,然后取出前10000行,按行链接成新的数据,重建索引:
def unbanlance(un_data):
data1 = un_data.loc[(data["CRASHSEV"] == 1)].sample(frac=1).iloc[:10000, :]
data2 = un_data.loc[(data["CRASHSEV"] == 2)].sample(frac=1).iloc[:10000, :]
data3 = un_data.loc[(data["CRASHSEV"] == 3)].sample(frac=1).iloc[:10000, :]
data4 = un_data.loc[(data["CRASHSEV"] == 4)].sample(frac=1).iloc[:10000, :]
ba_data = pd.concat([data1,data2,data3,data4], axis=0).sample(frac=1).reset_index(drop=True) #0是按行链接
return ba_data
将df数据中的 ? 替换为用 标准缺失值表示
df.replace(to_replace="?",value=np.nan)
查看数据前5行
dataframe.head()
查看数据的信息,包括每个字段的名称,非空数量、字段的数据类型
data.info()
查看数据的统计信息
(count/mean/std/min/25%/50%/75%max)
data.describe()
查看dataframe的大小
dataframe.shape
按列/数组排序
按某列排序:
df.groupby([‘列名’]).cumcount()
对该列或行进行值排序
sort_values(by = “列名/行名”)
对数组进行升序排序,返回索引值。降序的话可以给a加负号
numpy.argsort(a) 或者 a.argsort()
数据相加
a.sum(aixs = 1)
a为数组,sum(axis=1)表示每行的数相加,平时不加axis则默认为0,为0表示每列的数相加。
字典操作
sorted对字典或者列表的后面一个值排序
sorted(dic.items() , key=lambda x:x[1] , reverse=True )
sorted (dic.items(),key=operator.itemgetter(1) ,reverse=True)
字典的get函数:
dic.get(key,0)相当于if ……else ,若key在字典dic中则返回dic[key]的值,若不在则返回0。
对于随机缺失和非随机缺失,直接删除记录是不合适的,原因上面已经给出。随机缺失可以通过已知变量对缺失值进行估计,而非随机缺失的非随机性还没有很好的解决办法。
元素级别的判断,把对应的所有元素的位置都列出来,元素为空或者NA就显示True,否则就是False
列级别的判断,只要该列有为空或者NA的元素,就为True,否则False
将为空或者NA的列找出来
将列中为空或者NA的个数统计出来
计算缺失值比例
- 如果“缺失”没有业务含义,用众数填充:dataframe [age] [ dataframe.age.isnull() ] = dataframe.age.dropna().mode().values #众数填补 , mode()函数就是取出现次数最多的元素。
- 如果“缺失”包含了业务含义,保留该变量,并且直接将缺失值填充为默认值。 dataframe.loc [ dataframe [ column ] .isnull(),column ] = value # 将某一列column中缺失元素的值,用value值进行填充。
缺失值多:
- 剔除掉缺失率>80%并且未来依然会高缺失的变量
缺失值适中:
- 将缺失当做新的一类,如one-hot来处理
DataFrame.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)
功能:根据各标签的值中是否存在缺失数据对轴标签进行过滤,可通过阈值调节对缺失值的容忍度
参数:axis : {0 or ‘index’, 1 or ‘columns’},或 tuple/list
how : {‘any’, ‘all’}
any : 如果存在任何NA值,则放弃该标签
all : 如果所有的值都为NA值,则放弃该标签
thresh : int, 默认值 None
int value :要求每排至少N个非NA值
subset : 类似数组
inplace : boolean, 默认值 False
如果为True,则进行操作并返回None。
返回:被删除的DataFrame
直接删除含有缺失值的行/列
new_drop = dataframe.dropna ( axis=0,subset=[“Age”,“Sex”] )
在子集中有缺失值,按行删除
new_drop = dataframe.dropna ( axis=1)
将dataframe中含有缺失值的所有列删除
计算缺失值的个数,如果超过一定数,再删除
#去掉缺失值大的行
def miss_row(data):
miss_row = data.isnull().sum(axis=1).reset_index()
miss_row.columns = ['row','miss_count']
miss_row_value = miss_row[miss_row.miss_count>500].row.values
data.drop(miss_row_value,axis=0,inplace=True)
return data
#去掉缺失值大的列
def miss_col(data):
miss_col= data.isnull().sum(axis=0).reset_index()
miss_col.columns = ['col','miss_count']
miss_col_value = miss_col[miss_col.miss_count>200].col.values
data.drop(miss_col_value,axis=1,inplace=True)
return data
对缺失值的插补大体可分为两种:替换缺失值,拟合缺失值,虚拟变量。替换是通过数据中非缺失数据的相似性来填补,其核心思想是发现相同群体的共同特征,拟合是通过其他特征建模来填补,虚拟变量是衍生的新变量代替缺失值。
固定值插补
均值插补
中值插补
最近数据插补
回归插补
拉格朗日插值
牛顿插值法
分段插值
K-means
KNN填补空值
#用KNN填充空值
def knn_fill_nan(data,K):
#计算每一行的空值,如果有空值,就进行填充;没有空值的行用于做训练数据
data_row = data.isnull().sum(axis=1).reset_index()
data_row.columns = ['raw_row','nan_count']
#空值行(需要填充的行)
data_row_nan = data_row[data_row.nan_count>0].raw_row.values
#非空行,原始数据
data_no_nan = data.drop(data_row_nan,axis=0)
#空行,原始数据
data_nan = data.loc[data_row_nan]
for row in data_row_nan:
data_row_need_fill = data_nan.loc[row]
#找出空列,并用非空列做KNN
data_col_index = data_row_need_fill.isnull().reset_index()
data_col_index.columns = ['col','is_null']
is_null_col = data_col_index[data_col_index.is_null == 1].col.values
data_col_no_nan_index = data_col_index[data_col_index.is_null == 0].col.values
#保存需要填充的行的非空列
data_row_fill = data_row_need_fill[data_col_no_nan_index]
#广播,矩阵-向量
data_diff = data_no_nan[data_col_no_nan_index] - data_row_need_fill[data_col_no_nan_index]
#求欧式距离
data_diff = (data_diff ** 2).sum(axis=1)
data_diff = data_diff.apply(lambda x:np.sqrt(x))
data_diff = data_diff.reset_index()
data_diff.columns = ['raw_row','diff_val']
data_diff_sum = data_diff.sort_values(by='diff_val',ascending=True)
data_diff_sum_sorted = data_diff_sum.reset_index()
#取出k个距离最近的row
top_k_diff_val = data_diff_sum_sorted.loc[0:K-1].raw_row.values
#根据row和col值确定需要填充的数据的具体位置(可能是多个)
#填充的数据为最近的K个值的平均值
top_k_diff_val = data.loc[top_k_diff_val][is_null_col].sum(axis=0)/K
#将计算出来的列添加至非空列
data_row_fill = pd.concat([data_row_fill,pd.DataFrame(top_k_diff_val)]).T
data_no_nan = data_no_nan.append(data_row_fill,ignore_index=True)
print('填补完成')
return data_no_nan
**回归预测:**缺失值是连续的,即定量的类型,才可以使用回归来预测。
**极大似然估计(Maximum likelyhood):**在缺失类型为随机缺失的条件下,假设模型对于完整的样本是正确的,那么通过观测数据的边际分布可以对未知参数进行极大似然估计(Little and Rubin)。这种方法也被称为忽略缺失值的极大似然估计,对于极大似然的参数估计实际中常采用的计算方法是期望值最大化(Expectation Maximization,EM)。该方法比删除个案和单值插补更有吸引力,它一个重要前提:适用于大样本。有效样本的数量足够以保证ML估计值是渐近无偏的并服从正态分布。但是这种方法可能会陷入局部极值,收敛速度也不是很快,并且计算很复杂,且仅限于线性模型。
多重插补(Mutiple imputation):
多值插补的思想来源于贝叶斯估计,认为待插补的值是随机的,它的值来自于已观测到的值。具体实践上通常是估计出待插补的值,然后再加上不同的噪声,形成多组可选插补值。根据某种选择依据,选取最合适的插补值。
def set_missing_ages(df):
# 把已有的数值型特征取出来丢进Random Forest Regressor中
age_df = df[['Age','Fare', 'Parch', 'SibSp', 'Pclass']]
# 乘客分成已知年龄和未知年龄两部分
known_age = age_df[age_df.Age.notnull()].as_matrix()
unknown_age = age_df[age_df.Age.isnull()].as_matrix()
# y即目标年龄
y = known_age[:, 0]
# X即特征属性值
X = known_age[:, 1:]
# fit到RandomForestRegressor之中
rfr = RandomForestRegressor(random_state=0, n_estimators=2000, n_jobs=-1)
rfr.fit(X, y)
# 用得到的模型进行未知年龄结果预测
predictedAges = rfr.predict(unknown_age[:, 1:])
# print predictedAges
# 用得到的预测结果填补原缺失数据
df.loc[ (df.Age.isnull()), 'Age' ] = predictedAges
return df, rfr
采用lgb来预测缺失值填补(lgb: lightGBM 机器学习方法)
import lightGBM as lgb
def set_missing(df,predict_list):
for predict_feature in predict_list:
#原始数据分为已知的和未知的
known = df[df[predict_feature].notnull()]
unknown = df[df[predict_feature].isnull()]
#训练集构造,从已知的部分构造
y = known[ predict_feature].as_matrix()
x = known.drop(predict_feature,axis=1).as_matrix()
#测试集,从未知的部分构造
test_x = unknown.drop(predict_feature, axis=1).as_matrix()
#用lgb模型进行训练
predicted_feature = _model_predict(x, y, test_x)
#用得到的预测结果填补原缺失数据
df.loc[(df[predict_feature].isnull()), predict_feature] = predicted_feature
return df
def model_predict(x, y, test_X):
from sklearn.model_selection import train_test_split
X_train, X_test,y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1
lgb_train = lgb.Dataset(x_train, y_train)
lgb_eval = lgb.Dataset(X_test, y_test,reference=lgb_train)
params = {
" boosting' : 'gbdt ",
"objective' : 'regression ',
' metric ': 'rmse ',
'num_leaves ' : 31,
'min_data_in_leaf' : 20,
'learning_rate ' : 0.015,
'cat_smooth ': 10,
'feature_fraction ' : 0.8,
'bagging_freq': 5,
'verbosity': 0
}
gbm = lgb.train(params,
lgb_train,
num_boost_round=1000,valid_sets=lgb_eval,early_stopping_rounds=70)
#用得到的模型进行未知年龄结果预测
predicted_feature = gbm.predict(test_x,num_iteration=gbm.best_iteration)
print("---------best_iteration: ", gbm.best_iteration)
return predicted_feature
Xgboost
,lightgbm
等高级模型。画数据的散点图
观察偏差过大的数据,是否为异常值;
画箱型图
箱型图识别异常值比较客观,因为它是根据3σ原则,如果数据服从正态分布,若超过平均值的3倍标准差的值被视为异常值。
基于模型预测
基于近邻度的离群点检测
基于密度的离群点检测
基于聚类的方法来做异常点检测
专门的离群点检测
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2MDOYWZK-1630327036273)(E:\Typora\typora personal doc\personal doc photo source\1252882-20190410173245036-469845546.png)]
左偏,偏度<0;右偏,偏度>0,偏度的绝对值数值越大表示其分布形态的偏斜程度越大。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zaCeyniE-1630327036274)(E:\Typora\typora personal doc\personal doc photo source\1252882-20190410174323572-246887081.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jlmj7uzb-1630327036276)(E:\Typora\typora personal doc\personal doc photo source\1252882-20190410174408773-427166535.png)]
计算偏度、峰度
# 方法1:在series上计算偏度、峰度
import pandas as pd
x = [53, 61, 49, 66, 78, 47]
s = pd.Series(x)
print(s.skew())#偏度
print(s.kurt())#峰度
# 结果如下:
0.7826325504212567
-0.2631655441038463
# 方法2:直接在dataframe上计算偏度
data_frame2= pd.DataFrame({'A':[1,2,3,4],'b':[1,0,3,1]})
data_frame2.skew(axis = 0)
# 结果如下:
A 0.000000
b 1.129338
dtype: float64
参考文献: