数据科学——数据预处理

第一次作业

第一题

题目描述

现已使用 Pandas 读取数据集 challenge.csv

  1. 请提取该数据集的字段名称,将结果存为 cols
  2. 请获取给数据的字段和样本数量,将结果分别存为 col_num 和 sam_num
  3. 请获取该数据集的前五行记录,将最后的 DataFrame 存为 five_data

代码:

import pandas as pd
path = "./data/insurance.csv"
titannic = pd.read_csv(path)   #将这个csv文件读取进来

'''查看该数据集的前2条数据'''
# print(titannic.head(0))   #看一下前20行

'''提取该数据集的字段名称,将结果保存为cols'''
cols = titannic.columns
cols = [col.lower() for col in cols]
print(cols)

'''获取给出的数据的字段和样本数量,将结果分别存为col_num和sam_num'''
col_num = titannic.shape[1]
sam_num = titannic.shape[0]; sam_num = len(titannic)
print("col_num is:", col_num)
print("sam_num is: ", sam_num)

'''获取数据集的前五行记录,将最后的DataFrame存为five_data'''
five_data = titannic.head(5)
print(five_data)

总结与思考

  1. pandas库中里面有很多封装好的对表格数据进行操作的函数;
  2. pd.read_csv(path):读取path文件,创建一个pandas对象;
  3. head(x):读取数据中的前面x行数据;
  4. .columns: 读取数据集中的字段
  5. .shape:获取数据集中的(行,列)
  6. len(pandas对象):得到这个对象的行的数量

第二题

题目描述

使用 scipy 库中的 stats 模块,对生成的数据进行正态性检验,将检验的结果存为 model

代码:

import numpy as np
from scipy import stats
test_data = np.random.random(size = 100)

'''输出结果中第一个为统计量,第二个为P值(统计量越接近1越表明数据和正态分布拟合的好,
P值大于指定的显著性水平,接受原假设,认为样本来自服从正态分布的总体)'''
model = stats.shapiro(test_data); print(model)

'''输出结果中第一个为统计量,第二个为P值(注:统计量越接近0就越表明数据和标准正态分布拟合的越好,
如果P值大于显著性水平,通常是0.05,接受原假设,则判断样本的总体服从正态分布)'''
model = stats.kstest(test_data, 'norm')
print(model)

'''输出结果中第一个为统计量,第二个为P值(注:p值大于显著性水平0.05,认为样本数据符合正态分布)'''
model = stats.normaltest(test_data)
print(model)

总结与思考

  1. 有三个函数都可以进行正态分布检验,分别为:stats.shapiro(), stats.kstest(), stats.normaltest()

第三题

题目描述

3. 下列属于衡量数据整体散度的是(b,c):

a. 欧式距离

b. 标准差

c. 分位数

d. 众数

总结与思考

  1. 欧氏距离:L2范式,绝对距离,是欧几里得空间中两点间“普通”(即直线)距离;根据公式,我认为这个是用来衡量两个样本之间的距离。
  2. 算术平均值,中值,最大值,最小值,分位数,方差都分别是一种度量 数据中心趋势和离散程度,描述数据汇总的图形显示 的手段

第四题

题目描述

现已使用 Pandas 生成 Series 对象 example_data

  1. 请使用 isnull()函数确定 example_data 是否含有缺失值,将最后的结果存为 boolean_array
  2. 请使用 fillna()函数使用字符串 missing 替换缺失值,将替换后的 Series 对象存为 new_data

代码

import pandas as pd
import numpy as np
example_data = pd.Series([1,2,3,np.nan,4])
# 判断是否含有缺失值
boolean_array = example_data.isnull()
print(boolean_array)
# 缺失值替换
new_data = example_data.fillna("missing")
print(new_data)

总结与思考

  1. Pandas生成的数据集对象可以直接调用isnull()函数,isnull()函数对于此处为缺失值,返回True,此处不为缺失值,则返回False
  2. DataFrame.fillna();可以将所有NaN元素进行替换,可以向前或向后传播非null值,也可以指定填充连续数量的NaN元素。

第五题

题目描述

现已使用 Pandas 读取数据集 birthrate.csv
请对该数据集的 birth_rates 特征使用四分位数作为切分点,通过 qcut()函数完成等频离散化; 将最后的结果存为 data_qcut
该数据集详情为
1-5

代码

import pandas as pd
data = pd.read_csv('./data/birthrate.csv')
#请在下面作答
data_qcut = pd.qcut(data["birth_rates"], [0,0.25,0.5,0.75,1])
print(data_qcut)
data_qcut = pd.qcut(data["birth_rates"], 4)
print(data_qcut)

总结

  1. pd.qcut(x, q, labels=None, retbins=False, precision=3, duplicates='raise');x :一维数组或者Serise;q : 表示分位数的整数或者数组;如果是分位数的整数,例如10用于十分位,4用于四分位;如果是分位数数组,例如[0,0.25,0.5,0.75,1]用于四分位数
  2. 等频离散化,将特征分成k个区间,每个区间里面的样本数量是一样的(区间长度可能不一致)。等距离散化,将特征分成k个区间,每个区间长度一样。等频离散化的好处:基于模型需要啊,更加容易理解等缺点:容易使相同的特征值分到不同的区间。

第六题

题目描述

1
实现
1
1
1
1

总结与思考

最小二乘法和加大似然估计方法,最后都变成了对同一个函数求其偏导,由于这个线性模型是可以直接使用求偏导的形式求出其解析解;但是像一些混合模型,则不能直接得到解析解,例如高斯混合模型,这时候对于含有隐变量的模型,可以考虑使用EM算法等方法通过求其近似解来逼近其最优解。

第七题

题目描述
1
实现1

这里我是直接使用了最小二乘法进行求解;通过最小二乘法,分别求出参数a和参数b的偏导,得到a与b的解析解;代码中a与b我通过直接表达其算式,来得到;求出a与b之后,直接带入方程;
最后,通过描出数据集的点()
画出确定了a与b拟合的方程

import matplotlib.pyplot as plt

# 数据
X = [0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12]
Y = [42, 44, 51, 48, 51, 54, 57, 54, 57, 63, 61, 69, 70, 70, 70, 72, 74, 83, 84, 81, 84, 85, 91, 86, 91, 95]

# 计算X,Y的平均值
Y_ = sum(Y) / len(Y); X_ = sum(X) / len(X)

# 计算Y = a + b * X   中的  a 与 b
temp_mu = 0; temp_zi = 0
for tmp_zip in zip(X, Y):
    x = tmp_zip[0]; y = tmp_zip[1]
    temp_mu = x * x + temp_mu
    temp_zi = x * y + temp_zi
b = (temp_zi - len(X) * X_ * Y_) /  (temp_mu - len(X) * X_ * X_)
a = Y_ - b * X_

print(a); print(b)

# 计算预测值
Y_predict = []
for x in X:
    tmp_y = a + b * x
    Y_predict.append(tmp_y)

# 画出蓝色的数据点,红色的拟合曲线
plt.scatter(X, Y, c="blue")
plt.plot(X, Y_predict, c="red")
plt.show()

'''代码是可以直接运行的'''

1

实现二

直接调用sklearn中的LinearRegression

from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt
import numpy as np

X = [0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,12, 12]
Y = [42, 44, 51, 48, 51, 54, 57, 54, 57, 63, 61, 69, 70, 70, 70, 72, 74, 83, 84, 81, 84, 85, 91, 86, 91, 95]

# LinearRegression需要列式数据
X_train = np.array(X).reshape(len(X), 1)
Y_train = np.array(Y).reshape(len(Y), 1)

'''求解线性回归方程参数时,首先判断训练集X是否是稀疏矩阵,如果是,就用Golub&Kanlan双对角线化过程方法来求解;
否则调用C库中LAPACK中的用基于分治法的奇异值分解来求解;进行训练,sklearn中并不是使用梯度下降法求解线性回归,
而是使用最小二乘法求解(源码里面可以看到'''
'''fit_intercept:模型是否存在截距
normalize:模型是否对数据进行标准化(在回归之前,对X减去平均值再除以二范数),如果fit_intercept被设置为False时,该参数将忽略。
该函数有属性:coef_可供查看模型训练后得到的估计系数,如果获取的估计系数太大,说明模型有可能过拟合。'''
LineModule = LinearRegression()
LineModule.fit(X_train, Y_train)

#进行预测
Y_predict = LineModule.predict(X_train)

#画图
plt.scatter(X, Y, c = "blue")
plt.plot(X, Y_predict, c = "red")
plt.show()

'''可以直接运行'''

1
总结与思考

  1. 求解线性回归方程参数时,首先判断训练集X是否是稀疏矩阵,如果是,就用Golub&Kanlan双对角线化过程方法来求解;否则调用C库中LAPACK中的用基于分治法的奇异值分解来求解;进行训练,sklearn中并不是使用梯度下降法求解线性回归,而是使用最小二乘法求解。
  2. fit_intercept:模型是否存在截距
    normalize:模型是否对数据进行标准化(在回归之前,对X减去平均值再除以二范数),如果fit_intercept被设置为False时,该参数将忽略。
  3. coef_可供查看模型训练后得到的估计系数,如果获取的估计系数太大,说明模型有可能过拟合。
  4. 我手动实现的和直接调库的结果图是一样的。

第八题

题目描述

1
实现

  1. 这道题目,我通过求出题目中f(x)的原函数f(x);从而求f(x)=0,变成了求F(x)的极值点;(这样就可以使用到梯度下降法)
  2. 首先观察,可以发现x = 0是在所有极值点的左边的,然后F(x)函数只有三个极值点;
  3. 我首先去确定了x的初始值为x1 = 0;学习率 = 0.1;通过X_fi来存储迭代过程中找到的极值点;
  4. 确定了初始值和学习率后;就需要开始迭代了,由于F(X)有三个极值点,通过观察其有着 极小值点,极大值点,极小值点;所以,x1 = x1 - (gradient * learning_rate),x1 = x1 + (gradient * learning_rate),x1 = x1 - (gradient * learning_rate);我通过设置了一个布尔类型f1来控制算式的变换;
  5. 在实现的过程中,还有一个很重要的问题是,当找到一个极值点后,如何跳跃到后边的点以找到下一个极值点;对于这个问题,我采用的方法是:第一次中,我找到斜率的绝对值接近0.3,将这个时候的x记录下来;当找到第一个极值点后,通过其对称性,对称到另一边(x1 = x1 + (x1 - x01)),此时记录下跳跃后的点,为下一次跳跃做准备;下一次同理,依然是记录上一次跳跃的点,即x01。
  6. 在上一个步骤中,值得一提的是为什么我指定斜率为0.3;这个地方,我是直接去调试了代码,发现每次跳跃后,他们的斜率的绝对值都存在着大于0.3的情况(大概是0.3...,小于0.4),所以我就直接指定0.3了(最开始我指定的是1,然后没得到答案,后来发现原来后边的斜率绝对值就全部都小于1)
  7. 由于知道这个函数的极值点数量为3,所以当我找到了3个极值点后,我就直接终止迭代,最终得到最后的答案
  8. 梯度下降的过程,我使用蓝色的点绘画了出来,并使用了蓝色的线链接了起来;为了方便观察,我使用了红色的线画出了F(X)的图像。
  9. 最后的三个答案,我在控制台打印了出来

答案是:x = 1, x = 2, x = 3 (经过验证,是正确的)

import matplotlib.pyplot as plt

# 初始化x1
x1 = 0
x01 = x1
learning_rate = 0.1
X_fi = []
X = []; Y = []
f1 = True
cnt = 0

def f(x):
    return 0.25 * (x ** 4) - 2 * (x ** 3) + 11 * (x ** 2) / 2 - 6 * x

def qiudao(x):
    return x * x * x - 6 * x * x + 11 * x - 6

for i in range(1000):
    X.append(x1); Y.append(f(x1))
    if(cnt == 3):
        break
    dao_x1 = qiudao(x1)
    print("dao_x1: ", dao_x1)

    if(cnt == 0):
        if(abs(dao_x1) >= 0.3):
            x01 = x1

    if(f1):
        x1 = x1 - learning_rate * dao_x1
        if(dao_x1 >= -1e-4):
            f1 = False
            X_fi.append(x1)
            cnt += 1
            x1 = x1 + (x1 - x01)
            x01 = x1


    else:
        x1 = x1 + learning_rate * dao_x1
        if(dao_x1 <= 1e-4):
            f1 = True
            X_fi.append(x1)
            cnt += 1
            x1 = x1 + (x1 - x01)
            x01 = x1

print(X_fi)

'''画图'''
# 函数
X_f, Y_f = [], []
x = -0.2
while(x <= 3.7):
    X_f.append(x)
    Y_f.append(f(x))
    x += 0.01
plt.plot(X_f, Y_f, c = "red")
# 梯度下降过程
plt.scatter(X, Y, s = 12, c = "blue")
plt.plot(X, Y, c = "blue")
plt.show()

1
总结与思考

  1. 梯度下降是一种通过迭代的方法来找到函数的局部最值点;但是当函数有多个极值点时,需要去改变迭代的符号,因为每次寻找到的梯度方向是数值增加最快的方向;所以,极小值点要减去它,极大值点要加上它;
  2. 梯度下降的过程中,学习率和迭代次数都是超参数,有时候需要进行调试,才能找到一个合适的(我第一次设置成0.001,10000000,跑了很久没跑出来)
  3. 在这次的作业中,我是手写的(以前没写过,写起来还是花了很长时间,算法思路也变换了几次,最后才找到这个我觉得比较合适的);
  4. 应该还有矩阵计算的方式来求解(更具有普遍性,因为需要考虑多元函数的情况),通过调用numpy以及封装好的库,由于时间关系,我就没有继续去写这个版本的代码了,后边有时间需要补上。

第九题

题目描述

9. [自学牛顿方法] 牛顿方法和梯度下降法有什么异同点?请写出牛顿方法的推导过程,编程实现牛顿方法求解上一题,并编程绘图展示迭代计算过程。
梯度下降与牛顿迭代方法的异同点

相同点:

  1. 都是通过迭代的方式进行求解
  2. 都可以求局部的最值点

不同点:

  1. 牛顿迭代的过程中,每一步都指定了一定的步长;而梯度下降的学习率是我们自己指定的,且 一直不变;所以,牛顿迭代在时间上会更快一些。
  2. 牛顿法,利用到了函数的二阶导,收敛速度相对于梯度下降会快很多(多元的话就是海塞矩阵的逆对应着梯度下降的学习率)

牛顿方法的推导过程
9niu01
9niu02
算法实现

算法思想1:

我首先设置x = 0找到最左边的零点;然后设置一个比较大的x(可以是100,考虑到要进行画图,我设置的4)找到最右边的零点;最后取这两个零点的平均值,最后再进行一次牛顿迭代,得到中间的零点。

算法思路2:

虽然思路不同,但是代码却可以是一样的(这个思路是我在看牛顿法和梯度下降法的区别时发现的)
和上一题同样,这道题目中求零点的问题,同样可以转化为求f(x)的原函数F(x)的极值点问题;此时代码中的f(x):看作是F(x)的一阶导;gra(x)看作是F(x)的二阶导。此时通过泰勒二阶展开,可以得到推导公式:x = x - f'(x) / f''(x)。

import matplotlib.pyplot as plt

def f(x):
    return (x ** 3) - 6 * (x ** 2) + 11 * x - 6
def gra(x):
    return 3 * (x ** 2) - 12 * x + 11
X = []
x = 0
cnt = 0

'''画图'''
X_, Y_ = [], []
X_niudun, Y_niudun = [], []
x = 0
while(x <= 4):
    X_.append(x)
    Y_.append(f(x))
    x += 0.1

'''算法核心'''
x = 0
while(cnt == 0):
    fx = f(x); grax = gra(x)
    X_niudun.append(x)
    if(abs(fx / grax) <= 1e-4):
        X.append(x)
        cnt += 1
        break
    x = x - fx / grax

x = 4
while(cnt == 1):
    fx = f(x); grax = gra(x)
    X_niudun.append(x)
    if(abs(fx / grax) <= 1e-4):
        X.append(x)
        cnt += 1
        break
    x = x - fx / grax

x = (X[0] + X[1]) / 2
while(cnt == 2):
    fx = f(x); grax = gra(x)
    X_niudun.append(x)
    if (abs(fx / grax) <= 1e-4):
        X.append(x)
        cnt += 1
        break
    x = x - fx / grax

print(X)

sorted(X_niudun)
for i in X_niudun:
    Y_niudun.append(f(i))

'''函数 + 牛顿迭代'''
plt.plot(X_, Y_, c = "red")
# 梯度下降过程
plt.scatter(X_niudun, Y_niudun, s = 12, c = "blue")
for (i, j) in zip(X_niudun, Y_niudun):
    plt.plot([i + (0 - j) / gra(i), i], [0, j], c = "blue", linestyle=':')
plt.plot([0, 5], [0, 0], c = "blue")
plt.show()

9jieguo
总结与思考

  1. 梯度下降和牛顿法都属于优化算法;其中当求极值点时,牛顿法的收敛速度会更快一些,因为它考虑到了函数的二阶导,而梯度下降只考虑到了函数的一阶导
  2. 听说牛顿法更消耗资源,因为海塞矩阵的缘故;梯度下降法也可以通过步长不断降低来优化,但是降低多少也算是一个超参数了(没写过,直觉);
  3. 牛顿法如果用来求最值点,应该会受到鞍点的影响(没写过);梯度下降法求最值点,也会有到一个局部最值点的问题。这道题目由于函数的缘故,一看就知道有几个点;但是如果继续进行扩展的话,就不好说了;这两个算法都有其局限性,
  4. 梯度:步长问题,局部最值点问题;牛顿:计算资源问题,鞍点问题。

第十题

题目描述

10. 数据标准化是将数据按比例缩放到一个特定区间,其主要包括数据同趋化处理和无量纲化处理两个方面。数据标准化的方法有很多种,常用的有最小-最大标准化和 z-score 标准化。请用户对本题中的变量(不包括变量 ID)进行 z-score 标准化;数据说明:本题数据来自 KEEL,数据集一共包含 1 列 ID,4 列特征变量,共100 个样本点。
10-0
实现
首先我通过random随机取生成0 - 200.0的数据并保存到keel.csv文件中;然后,读取csv文件中的数据,并对其进行修改,最终保存。

import csv
import numpy as np
import pandas as pd
'''
生成数据并保存到csv文件中
'''
# 1.创建文件对象
f = open('./data/keel.csv', 'w', encoding='utf-8', newline="")
# 2.基于文件对象构建csv写入对象
csv_write = csv.writer(f)
# 3.构建列表头
csv_write.writerow(['ID', 'CT', 'FA', 'WT', 'SP'])
# 4. 随机生成数据
random = np.random.RandomState(0)#RandomState生成随机数种子
A = []
for i in range(500):#随机数个数
    a = random.uniform(0, 200.0)#随机数范围
    round(a, 1)#随机数精度要求
    A.append(a)
# 5.将数据写入csv文件
for i in range(100):
    csv_write.writerow([i + 1, A[i], A[i + 100], A[i + 200], A[i + 400]])
# 6.关闭文件
f.close()

'''读取文件中的数据,并进行z-score操作'''
data = pd.read_csv('./data/keel.csv')
print(data.head(10))
E, FD = [], []
cols = data.columns
# 求均值
for i in range(4):
    x = data[cols[i + 1]]
    tmp = 0
    for j in x:
        tmp += j
    E.append(tmp / len(data))
# 求标准差
for i in range(4):
    x = data[cols[i + 1]]
    tmp = 0
    for j in x:
        tmp += (j - E[i - 1]) ** 2
    FD.append((tmp / len(data)) ** 0.5)
f = True
dic = {'CT': 0, 'FA': 1, 'WT': 2, 'SP': 3}
dic_reverse = {0: 'CT', 1: 'FA', 2: 'WT', 3: 'SP'}
feature = ['CT', 'FA', 'WT', 'SP']

for i in range(len(data)):
    for j in feature:
        data.loc[i, j] = (data.loc[i, j] - E[dic[j]]) / FD[dic[j]]

data.to_csv('./data/keel.csv')
print(data.head(10))

分别查看数据处理前后,成功修改了文件
10jieguo
总结与思考

  1. 这道题目,算法思路没啥难度,关键在于要知道Pandas如何对文件进行操作,如读操作,修改操作。
  2. 通过Uniform()函数可以指定random()生成数据的范围;使用round()函数可以修改生成的数据的精度。
  3. C语言中可以直接用map进行映射,对应到Python中则是使用字典可以随意映射
  4. 通过data.loc可以对读取的数据保存的DataFrame文件进行修改
  5. 通过to_csv()函数,可以将DataFrame对象保存到指定的文件中。
posted @ 2021-10-05 10:31  pha创噬  阅读(837)  评论(2编辑  收藏  举报