1、百度百科的解释:冰雹猜想

2、本练习的目的是在假设冰雹猜想正确的情况下,利用数据挖掘的方法找出 n 和 fn 之间的关系,其中 n 是输入的整数 1、2、3..., fn 则是 n 经过一定规则的变换后得到 1 所经过的步骤次数,规则为 如果 n 是奇数则变为 3*n + 1,如果是偶数则为 n/2

3、生成数据 


#! usr/bin/env python
# coding:utf8

"""
__author__ = "LCG22"
__date__ = "2016-11-22"

本程序目的是生成用于数据挖掘的冰雹猜想的数据,主要是 n 和 fn,其中 n 是输入的整数 1、2、3...,
fn 则是 n 经过一定规则的变换后得到 1 所经过的步骤次数,规则为 如果 n 是奇数则变为 3*n + 1,如果是偶数则为 n/2
"""

import pandas as pd

DATA_PATH = {
    "100": r"data_100.csv",
    "1000": r"data_1000.csv",
    "10000": r"data_10000.csv",
    "100000": r"data_100000.csv",
    "1000000": r"data_1000000.csv",
    "10000000": r"data_10000000.csv"
}

def fn_num(n, i=0):
    """
    输出 fn
    :param n:
    :param i: 已经经过了多少步
    :return:
    """
    if n == 2:
        return i + 1
    else:
        if n % 2 == 0:
            nn = n / float(2)
            i += 1
            return fn_num(nn, i)
        else:
            nn = 3*n + 1
            i += 1
            return fn_num(nn, i)


def main(save_path, n_max=100):
    fn_list = []
    for n in range(1, n_max):
        fn = fn_num(n)
        fn_list.append(fn)

    data_df = pd.DataFrame({"n": [n for n in range(1, n_max)], "fn": fn_list})
    data_df.to_csv(save_path, index=False)


if __name__ == '__main__':
    main(DATA_PATH["100"], 100)
    main(DATA_PATH["1000"], 1000)
    main(DATA_PATH["10000"], 10000)
    main(DATA_PATH["100000"], 100000)
    main(DATA_PATH["1000000"], 1000000)
    main(DATA_PATH["10000000"], 10000000)



4、利用 sklearn 的相关机器学习的方法来找出 n 和 fn 的关系

在第三步的时候我们生成了很多个数量级的数据,最小的是100,最大的是1千万。而在第四步中,我们会首先进行数据可视化,因为 100 的数据量太小,故选用了 1000 的数据进行可视化

可视化:

代码部分:


data_df = pd.read_csv(read_path)

 # 画图观察数据的分布
 plt.plot(data_df.n, data_df.fn)
 plt.xlabel(u"n")
 plt.ylabel(u"fn")
 plt.show()
 plt.close()



图像部分:

冰雹猜想python代码计算次数 python冰雹猜想验证_拟合


图中的 x 轴的 n 表示的是整数 1- 1000(生成的数据中并没有包括 0 ,这是因为 0 是不是偶数仍有争议,故不使用 0 来生成数据)而 y 轴的 fn 则表示的是从整数 n 经过规则变换后变为 1 所经过的步骤。而由图中可以明显看出:

    ①、n 和 fn 并不是线性关系

    ②、n 和 fn 也并不是指数关系。图中可以看出 fn 并没有随着 n 的大幅增加而大幅增加,所以显然不是指数关系

    ③、fn 并不是总是随着 n 的增加而增加,故 n 和 fn 的关系也不是单调递增或递减


拟合:

    下面是整篇文章的重头戏,将会使用到 sklearn 库中的机器学习方法,对 fn 进行拟合

     ① 贝叶斯岭回归 (Beyesian Ridge Regression)

代码部分:


# 使用贝叶斯岭回归(Bayesian Ridge Regression)方法进行拟合
    X = list(data_df.n.apply(lambda x: [x]))
    # X = [[i] for i in X]
    y = data_df.fn
    clf = BayesianRidge(compute_score=True)
    clf.fit(X, y)
    pre = clf.predict(X)

    # 数据可视化
    lw = 2
    plt.plot(pre, color="lightgreen", label="Bayesian Ridge Regression")
    plt.plot(y, color="gold", label="y")
    plt.show()
    plt.close()



图像部分:

冰雹猜想python代码计算次数 python冰雹猜想验证_岭回归_02

       通过图像明显可以看出贝叶斯岭回归的拟合效果并不好,因为贝叶斯岭回归拟合的是线性关系,但是显然我们的数据集并不是线性的


        ②多项式

代码部分:


# 多项式拟合
    from sklearn.pipeline import Pipeline
    from sklearn.linear_model import LinearRegression
    from sklearn.preprocessing import PolynomialFeatures
    degree = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40]
    for d in degree:
        clf = Pipeline([("poly", PolynomialFeatures(degree=d)),
                        ("linear", LinearRegression(fit_intercept=False))])
        clf.fit(X, y)
        y_test = clf.predict(X)

        plt.plot(X, y_test, linewidth=2)
    plt.plot(X, y)
    plt.grid()
    plt.legend([str(i) for i in degree], loc="upper left")
    plt.show()
    plt.close()



图像部分:

冰雹猜想python代码计算次数 python冰雹猜想验证_冰雹猜想python代码计算次数_03

        通过图像也可以看出多项式的拟合效果不好


        

其它方法则等学习了更多的拟合相关的方法再更新