加州房价预测项目详细笔记(Regression)——(2)采样(数据分割)<重要>

参考内容:

《机器学习实战》原作者github:https://github.com/ageron/handson-ml

加州房价预测项目精细解释https://blog.csdn.net/jiaoyangwm/article/details/81671084

DataFrame.where:

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.where.html

快速学会pandas中Dataframe索引.ix,.iloc,.loc的使用以及区别https://blog.csdn.net/qq1483661204/article/details/77587881


为了防止数据窥探偏误(data snooping bias),一般会将机器学习的数据集划分成三个子集:训练集,验证集测试集

训练集是用来训练模型的,给模型输入和对应的输出,让模型学习它们之间的关系。

验证集是用来估计模型的训练水平,比如分类器的分类精确度,预测的误差等,我们可以根据验证集的表现来选择最好的模型。

测试集是输入数据在最终得到的模型得到的结果,是训练好的模型在模拟的“新”输入数据上得到的输出。(只能在最后用于测试模型的性能,不能拿来训练。)

常见的划分比例是:50%用于训练,25%用于验证,25%用于测试。(或60%、20%、20%),这个比例可以根据数据集的大小和数据信噪比来改变。 


一、纯随机抽样创建测试集

该项目只分成训练集和测试集两个部分,选取20%的数据作为测试集。

(1)简单划分

通过创建split_train_test函数,实现将数据集分成训练集和测试集两个部分的目标:

import numpy as np
def split_train_test(data, test_ratio):
    shuffled_indices = np.random.permutation(len(data))
    test_set_size = int(len(data) * test_ratio)
    test_indices = shuffled_indices[:test_set_size]
    train_indices =shuffled_indices[test_set_size:]
    return data.iloc[train_indices], data.iloc[test_indices]
    
train_set,test_set = split_train_test(housing,0.2)
print(f"{len(train_set)} train + {len(test_set)} test")
# print(len(train_set), "train +", len(test_set), "test")

但是这样简单的划分数据集的话,每运行一次可能会产生不同的训练集和测试集。运行次数多的话,可能整个数据集都被运用,没能起到测试集的作用。

解决方案:

1) 在第一次运行程序后就保存数据集,后面的运行只是加载它;

2)为了保证在下一次获得更新的数据时不会中断,常见的解决方法是每个实例都使用一个标识符(identifier)来决定是否进入测试集;

3)通过Scikit-Learn提供的函数train_test_split的random_state参数,设置一个随机数生成器的种子,从而让它始终生成相同的随机索引。例:random_state = 42;42出自《银河系搭车客指南》的“关于生命、宇宙和一切的终极问题的答案”。

(2)使用标识符(identifier)划分

  • 使用行号索引

housing数据集没有标识符列,最简单的是使用行号索引作为ID:

housing_with_id = housing.reset_index() #新增一个“index”列
train_set, test_set = split_tain_test_by_id(housing_with_id, 0.2, "index")

使用这种方法需要确保在数据集的末尾添加新数据,并不会删除任何行。

  • 创建稳定的标识符

如果没法保证使用行索引使用要求的话,可以尝试使用一个最稳定的特征来创建唯一标识符(本例选择经纬度)

housing_with_id["id"] = housing["longitude"] * 100 + housing["latitude"]
train_set, test_set = split_train_test_by_id(housing_with_id, 0.2, "id")

(3)使用Scikit-Learn提供的函数train_test_split

通过Scikit-Learn提供的函数train_test_split的random_state参数,设置一个随机数生成器的种子,从而让它始终生成相同的随机索引。

from sklearn.model_selection import train_test_split
train_set,test_set = train_test_split(housing, test_size = 0.2, random_state = 42)
print(f"{len(train_set)} train + {len(test_set)} test")

纯随机的取样方法在数据集很大的时候(尤其是相较于属性的数量而言),通常是可行的。但是如果数据集不大,可能会导致明显的抽样偏差。


二、分层抽样创建测试集

数据少的时候采用分层抽样,从每个分层去取合适数量的实例,能相对保证测试集对总人数具有代表性。

专家建议收入中位数(median_income)是一个非常重要的属性,因此可以以这一属性作为分层抽样的依据。(随机切分会将原本的数据分布破坏掉,比如收入、性别等,保证特性分布是很重要的)

(1)以中位数(median_income)创建一个分类属性

  • 观察收入中位数的柱状图
housing["median_income"].hist()
plt.show()

可以看到,收入中位数(median_income)集中在2~5(万美元)附近,超出6(万美元)的数据较少,为了保证分层抽样的每一层有足够的数据,层数不应该分的太多。

  • 创建分类属性
import numpy as np
housing["income_cat"] = np.ceil(housing["median_income"] / 1.5)
housing["income_cat"].where(housing["income_cat"] < 5, 5.0, inplace = True)
housing["income_cat"].hist()
plt.show()

这里通过将收入中位数(median_income)除以1.5来限制收入类别的数量,然后使用ceil取整得到离散类别,最后将所有大于5的类别合并成一个类别5。

DataFrame.where()的用法:

DataFrame.where(condition, other, inplace=False, axis=None, level=None, errors='raise', try_cast=<no_default>)


inplace = True 的参数解读:

inplace = True:不创建新的对象,直接对原始对象进行修改;
inplace = False:对数据进行修改,创建并返回新的对象承载其修改结果。

默认是False,即创建新的对象进行修改,原对象不变。

 (2)进行分层抽样

from sklearn.model_selection import StratifiedShuffleSplit
split = StratifiedShuffleSplit(n_splits = 1,test_size = 0.2, random_state = 42)
for train_index, test_index in split.split(housing, housing["income_cat"]):
    strat_train_set = housing.loc[train_index]
    strat_test_set = housing.loc[test_index]

housing["income_cat"].value_counts() / len(housing)
#查看住房数根据收入类别的比例分布

DataFrame.loc[]的用法:

DataFrame.loc[] 通过轴标签选择数据

DataFrame.iloc[] 通过整数索引选择数据


 n_splits = n的用法:

表示划分为几块(至少是2)   例:n_splits = 1 表示分成两块


三、分层抽样与纯随机抽样的抽样偏差比较

def income_cat_proportions(data):
    return data["income_cat"].value_counts() / len(data)

train_set, test_set = train_test_split(housing, test_size=0.2, random_state=42)
compare_props = pd.DataFrame({"Overall": income_cat_proportions(housing),
                           "Stratified": income_cat_proportions(strat_test_set),
                           "Random": income_cat_proportions(test_set),}).sort_index()
compare_props["Rand. %error"] = 100 * compare_props["Random"] / compare_props["Overall"] - 100
compare_props["Strat. %error"] = 100 * compare_props["Random"] / compare_props["Overall"] - 100
compare_props

由图中可以看出,分层抽样测试集的收入分类比例与总数据集的几乎相同,而随机采样数据集偏差严重。


恢复原始数据

删除income_cat这一属性:

for set in (strat_train_set, strat_test_set):
    set.drop(["income_cat"], axis = 1, inplace = True)

axis=0:在第一维操作
axis=1:在第二维操作
axis=-1:在最后一维操作

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C#中实现非线性回归方法可以使用MathNet.Numerics库,该库提供了许多数学计算的方法,包括线性和非线性回归。 首先安装MathNet.Numerics库,可以在NuGet包管理器中搜索安装。 下面是一个简单的示例代码,其中包含一个非线性回归方法。方法名为NonlinearRegression,传入参数为一个函数Func<Vector<double>, Vector<double>>,一个Vector<double>类型的数据集和一个double数组。 ```csharp using MathNet.Numerics.LinearAlgebra; public static class Regression { public static Vector<double> NonlinearRegression(Func<Vector<double>, Vector<double>> function, Vector<double> data, double[] target) { var jacobian = Matrix<double>.Build.Dense(target.Length, data.Count); var residuals = Vector<double>.Build.Dense(target.Length); var parameters = Vector<double>.Build.Dense(data.Count); for (int i = 0; i < target.Length; i++) { var x = data[i]; var y = target[i]; // Calculate the residual residuals[i] = y - function(x)[0]; // Calculate the Jacobian matrix for (int j = 0; j < data.Count; j++) { jacobian[i, j] = (function(x + Epsilon(j)) - function(x - Epsilon(j)))[0] / (2 * Epsilon(j)); } } // Solve for the parameters var qr = jacobian.QR(); var q = qr.Q; var r = qr.R; var qTranspose = q.Transpose(); var b = qTranspose * residuals; var c = qTranspose * jacobian; var parametersDelta = r.Solve(c.Transpose() * b); parameters -= parametersDelta; return parameters; } private const double EpsilonValue = 1e-8; private static readonly Vector<double> EpsilonVector = Vector<double>.Build.Dense(1, EpsilonValue); private static Vector<double> Epsilon(int index) { var result = Vector<double>.Build.Dense(index, 0); result = result.Append(EpsilonVector); result = result.Append(Vector<double>.Build.Dense(EpsilonVector.Count - index - 1, 0)); return result; } } ``` 在上面的代码中,使用了MathNet.Numerics库中的Matrix和Vector类来处理矩阵和向量数据。方法中的代码可以按照以下步骤完成: 1. 初始化Jacobian矩阵、残差向量和参数向量。 2. 通过循环遍历数据集,计算出每个数据点的残差,并且计算Jacobian矩阵。 3. 使用QR分解求解参数向量的最小二乘解。 4. 返回参数向量。 这个方法可以用于任何非线性回归问题。只需要将函数作为第一个参数传递给该方法,它会自动计算Jacobian矩阵和最小二乘解。 使用示例: ```csharp // Define the function var function = new Func<Vector<double>, Vector<double>>(x => Vector<double>.Build.DenseOfArray(new[] { x[0] * Math.Sin(x[0]), Math.Cos(x[0]) })); // Create the dataset var data = Vector<double>.Build.DenseOfArray(new[] { 0.1, 0.2, 0.3, 0.4, 0.5 }); var target = new[] { 0.078, 0.149, 0.217, 0.282, 0.342 }; // Perform the nonlinear regression var parameters = Regression.NonlinearRegression(function, data, target); // Output the results Console.WriteLine("Parameters: [{0}]", string.Join(", ", parameters)); ``` 这个示例代码中,我们定义了一个函数,然后生成一个数据集和目标值数组。最后调用非线性回归方法,得到最优参数向量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值