1.探索性数据分析(EDA,Exploratory Data Analysis)
一、数据探索
1.数据读取
- 遍历文件夹,读取文件夹下各个文件的名字:os.listdir() 方法:用于返回指定的文件夹包含的文件或文件夹的名字的列表。这个列表以字母顺序。 它不包括 '.' 和'..' 即使它在文件夹中。
1.1 CSV格式数据
(1)读取
### python导入csv文件的4种方法 # 1.原始的方式 lines = [line.split(',') for line in open('iris.csv')] df = [[float(x) for x in line[:4]] for line in lines[1:]] # 2.使用loadtxt,以下读取出来的不是dataframe,是列表形式 import numpy as np lines = np.loadtxt('iris.csv',delimiter=',',dtype='str')# 逗号为分隔符 df = lines[1:,:4].astype('float') # 3.使用read_csv import pandas as pd df = pd.read_csv('iris.csv') df=df.ix[:,:4] # 4.使用read_table # 分块读 reader1 = read_table(' 文件位置 ', names=' dataframe的列名 ',encoding='utf-8' ,sep='|' ) for chunk in reader1: print(chunk) # 迭代读 reader2 = pd.read_table('tmp.sv', sep='|', iterator=True) reader2.get_chunk(5)
pandas.read_csv可以读取CSV(逗号分割)文件、文本类型的文件text、log类型到DataFrame
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。
- head 、names:表示第一行的数据不取为列名,自己另外取名为names=['a','b','c']。如果不加header=None则表示第一行作为列名。
- encoding :遇到 ‘utf-8’ codec can’t decode byte 0xba in position 0: invalid start byte 但是又必须要中文解码,解决办法是设置read_csv中encoding = ‘GB2312’
- chunksize:通过指定一个chunksize分块大小来读取文件,返回的是一个可迭代的对象TextFileReader。
- iterator :指定iterator=True 也可以返回一个可迭代对象TextFileReader
(2)保存
①一次性写入
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()
1.2 Excel文件的读取和保存
(1)读取
dataframe=pd.read_excel('文件名.xlsx')
(2)保存
dataframe=pd.DataFrame(数据源) dataframe.to_excel('文件名.xlsx',sheet_name='表名')
1.3 sql文件读取:read_sql
读取sql文件之前需要安装好mysql以及python连接mysql的模块PyMySQL,直接命令pip install pymysql。
在数据库中新建一个数据库test,然后新建一个表students,插入数据。
在读取mysql数据之前要将mysql的服务启动:net start mysql。
import pymysql import pandas as pd #连接数据库为test conn=pymysql.connect(host="127.0.0.1",user="root",passwd="123456",db="test") #查询的表为students sql="select * from students" data=pd.read_sql(sql,conn) print(data)
1.4 读取html文件:read_html
这个函数主要读取HTML中table的数据。
import pandas as pd htl=pd.read_html('E:\test.html') print(htl)
读取网络上的HTML的数据也一样。只要将本地地址换成网络地址就行
1.5 读取文本数据(txt文件、dat文件、out文件):read_table
dataframe写入文本数据代码:
def text_save(filename, data):#filename为写入CSV文件的路径,data为要写入数据列表. file = open(filename,'a') for i in range(len(data)): s = str(data[i]).replace('[','').replace(']','')#去除[],这两行按数据不同,可以选择 s = s.replace("'",'').replace(',','') +'\n' #去除单引号,逗号,每行末尾追加换行符 file.write(s) file.close() print("保存文件成功")
1.6 json文件读取
(1)读取
#调用read函数全部读取json文件中的数据会报错,因为不能同时读取相同的json对象。需要用readlines()函数,一行一行的读取。 import json with open('data.json','r') as f: data=f.read() data=json.loads(data) print(data) #调用readlines()函数读取,并加载进一个列表当中 data_list=[] with open(r'data.json','r') as f: for line in f.readlines(): dic = json.loads(line) data_list.append(dic)
2.数据集成
(1)数据整合
- 整合两个数组: np.concatenate((数组1,数组2))
- 整合两个dataframe:pd.concat([dataframe1,dataframe2])
(2)数据打乱
- np.random.shuffle()
-
import numpy.random def shuffleData(data): np.random.shufflr(data) cols=data.shape[1] X=data[:,0:cols-1] Y=data[:,cols-1:] return X,Y
-
- 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
-
(3)数据替换
- 将df数据中的?替换为标准缺失值表示:df.replace(to_replace="?",value=np.nan)
3.查看数据信息
- 查看数据前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(axis=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。
-
二、数据质量分析
1.缺失值分析
1.1 数据缺失的类型
- 完全随机缺失(missing completely at random,MCAR):指的是数据的缺失是完全随机的,不依赖于任何不完全变量或完全变量,不影响样本的无偏性,如家庭地址缺失;
- 随机缺失(missing at random,MAR):指的是数据的缺失不是完全随机的,即该类数据的缺失依赖于其他完全变量,如财务数据缺失情况与企业的大小有关;
- 非随机缺失(missing not at random,MNAR):指的是数据的缺失与不完全变量自身的取值有关,如高收入人群不原意提供家庭收入;
对于随机缺失和非随机缺失,直接删除记录是不合适的,原因上面已经给出。随机缺失可以通过已知变量对缺失值进行估计,而非随机缺失的非随机性还没有很好的解决办法。
1.2 查看缺失情况
- dataframe.isnull()
元素级别的判断,把对应的所有元素的位置都列出来,元素为空或者NA就显示True,否则就是False
- dataframe.isnull().any()
列级别的判断,只要该列有为空或者NA的元素,就为True,否则False
- missing = dataframe.columns[ dataframe.isnull().any() ].tolist()
将为空或者NA的列找出来
- dataframe [ missing ].isnull().sum()
将列中为空或者NA的个数统计出来
- len(data["feature"] [ pd.isnull(data["feature"]) ]) / len(data))
缺失值比例
1.3 缺失值处理方式
1.3.1 连续型
(1)直接删除
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
-
(2)插补
对缺失值的插补大体可分为两种:替换缺失值,拟合缺失值,虚拟变量。替换是通过数据中非缺失数据的相似性来填补,其核心思想是发现相同群体的共同特征,拟合是通过其他特征建模来填补,虚拟变量是衍生的新变量代替缺失值。
【1】插补法(适用于缺失值少)
- 固定值插补
- dataframe.loc [ dataframe [ column ] .isnull(),column ] = value # 将某一列column中缺失元素的值,用value值进行填充。
- 均值插补
- data.Age.fillna(data.Age.mean(),inplace=True) # 将age列缺失值填充均值。(偏正态分布,用均值填充,可以保持数据的均值)
- 中值插补
- df['price'].fillna(df['price'].median()) # 偏长尾分布,使用中值填充,避免受异常值的影响。
- 最近数据插补
- dataframe ['age'].fillna(method='pad') # 使用前一个数值替代空值或者NA,就是NA前面最近的非空数值替换
- dataframe ['age'].fillna(method='bfill',limit=1) # 使用后一个数值替代空值或者NA,limit=1就是限制如果几个连续的空值,只能最近的一个空值可以被填充。
- 回归插补
- 拉格朗日插值
- 牛顿插值法
- 分段插值
- K-means
- 通过K均值的聚类方法将所有样本进行聚类划分,然后再通过划分的种类的均值对各自类中的缺失值进行填补。归其本质还是通过找相似来填补缺失值。缺失值填补的准确性就要看聚类结果的好坏了,而聚类结果的可变性很大,通常与初始选择点有关,因此使用时要慎重。
- 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
-
【2】拟合(适用于缺失值多)
- 回归预测:缺失值是连续的,即定量的类型,才可以使用回归来预测。
- 极大似然估计(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
【3】衍生(适用于缺失值多)
虚拟变量:通过判断特征值是否有缺失值来定义一个新的二分类变量。比如,特征为A含有缺失值,我们衍生出一个新的特征B,如果A中特征值有缺失,那么相应的B中的值为1,如果A中特征值没有缺失,那么相应的B中的值为0。
data_train['CabinCat'] = data_train['Cabin'].copy() data_train.loc[ (data_train.CabinCat.notnull()), 'CabinCat' ] = "No" data_train.loc[ (data_train.CabinCat.isnull()), 'CabinCat' ] = "Yes" fig, ax = plt.subplots(figsize=(10,5)) sns.countplot(x='CabinCat', hue='Survived',data=data_train) plt.show()
(3)不处理(适用于缺失值多)
- 如果“缺失”包含了业务含义,保留该变量,并且直接将缺失值填充为区别于其他正常值的默认值,比如-1。
- 补齐处理只是将未知值补以我们的主观估计值,不一定完全符合客观事实,在对不完备信息进行补齐处理的同时,我们或多或少地改变了原始的信息系统。而且,对空值不正确的填充往往将新的噪声引入数据中,使挖掘任务产生错误的结果。因此,在许多情况下,我们还是希望在保持原始信息不发生变化的前提下对信息系统进行处理。
- 在实际应用中,一些模型无法应对具有缺失值的数据,因此要对缺失值进行处理。然而还有一些模型本身就可以应对具有缺失值的数据,此时无需对数据进行处理,比如
Xgboost
,lightgbm
等高级模型。
1.3.2 类别型
缺失值少:
- 如果“缺失”没有业务含义,用众数填充:dataframe [age] [ dataframe.age.isnull() ] = dataframe.age.dropna().mode().values #众数填补 , mode()函数就是取出现次数最多的元素。
- 如果“缺失”包含了业务含义,保留该变量,并且直接将缺失值填充为默认值。 dataframe.loc [ dataframe [ column ] .isnull(),column ] = value # 将某一列column中缺失元素的值,用value值进行填充。
缺失值多:
- 剔除掉缺失率>80%并且未来依然会高缺失的变量
缺失值适中:
- 将缺失当做新的一类,如one-hot来处理
1.3.3 时间类型
- 缺失值少:
- df.interpolate():对于时间序列的缺失,可以使用这种方法。
- 缺失值多:
- 缺失值适中:
2.异常值分析
2.1查看异常情况
- 画数据的散点图。观察偏差过大的数据,是否为异常值;
- plt.scatter(x1,x2)
- 画箱型图,箱型图识别异常值比较客观,因为它是根据3σ原则,如果数据服从正态分布,若超过平均值的3倍标准差的值被视为异常值。
-
Percentile = np.percentile(df['length'],[0,25,50,75,100]) IQR = Percentile[3] - Percentile[1] UpLimit = Percentile[3]+ageIQR*1.5 DownLimit = Percentile[1]-ageIQR*1.5
- Ql为下四分位数:表示全部观察值中有四分之一的数据取值比它小;
- Qu为上四分位数:表示全部观察值中有四分之一的数据取值比它大;
- IQR称为四分位数间距:是上四分位数Qu和下四分卫数Ql之差,之间包含了全部观察值的一半。
- seaborn画boxplot
- f,ax=plt.subplots(figsize=(10,8)) sns.boxplot(y='length',data=df,ax=ax) plt.show()
-
- 基于模型预测
- 构建概率分布,离群点在该分布下概率低就视为异常点
- 基于近邻度的离群点检测
- KNN
- 基于密度的离群点检测
- 对象到k个最近邻的平均距离的倒数,如果该距离小,则密度高;
- DBSCAN:一个对象周围的密度等于该对象指定距离d内对象的个数
- 基于聚类的方法来做异常点检测
- K-means
- 专门的离群点检测
- One class SVM和Isolation Forest
2.2 异常值处理方式
- 视为缺失值:修补(平均数、中位数等)
- 直接删除:是否要删除异常值可根据实际情况考虑。因为一些模型对异常值不很敏感,即使有异常值也不影响模型效果,但是一些模型比如逻辑回归LR对异常值很敏感,如果不进行处理,可能会出现过拟合等非常差的效果。
- 不处理:直接在具有异常值的数据集上进行数据挖掘
- 平均值修正:可用前后两个观测值的平均值修正该异常值
三、数据特征分析
1.分布
- 定量数据分布分析:绘制频率直方分布图
- 定性数据分布分析:根据变量的分类类型分组,绘制饼图和条形图来描述分布
- 样本分布是否偏斜:计算偏度和峰度
左偏,偏度<0;右偏,偏度>0,偏度的绝对值数值越大表示其分布形态的偏斜程度越大。
计算偏度、峰度
# 方法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
2.对比
- 绝对数对比
- 相对数对比(如结构相对数、比例相对数)
3.常见统计量
- 集中趋势度量:均值、中位数、众数
- 离中趋势度量:极差、标准差、变异系数(标准差/均值)、四分位数间距
4.周期性
- 帕累托法则(即为二八法则)
5.相关性(连续变量间线性相关的程度)
- 绘制散点图、绘制散点图矩阵
- 计算相关系数(皮尔森相关系数、斯皮尔曼秩相关系数、判定系数)
- df.corr(method='pearson'),默认是pearson,还支持kendall/spearman
参考文献: