【问题标题】:Curve fitting for each column in Pandas + extrapolate valuesPandas中每列的曲线拟合+外推值
【发布时间】:2019-02-26 20:47:45
【问题描述】:

我有一个包含大约 300 列的数据集,每列都取决于深度。 Pandas DataFrame 的简化版本如下所示:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from scipy_optimize import curve_fit

df1 = pd.DataFrame({'depth': [1.65, 2.15, 2.65, 3.15, 3.65, 4.15, 4.65, 5.15, 5.65, 6.15, 6.65, 7.15, 7.65, 8.15, 8.65],
               '400.0': [13.909261, 7.758734, 3.513627, 2.095409, 1.628918, 0.782643, 0.278548, 0.160153, -0.155895, -0.152373, -0.147820, -0.023997, 0.010729, 0.006050, 0.002356],
               '401.0': [14.581624, 8.173803, 3.757856, 2.223524, 1.695623, 0.818065, 0.300235, 0.173674, -0.145402, -0.144456, -0.142969, -0.022471, 0.010802, 0.006181, 0.002641],
               '402.0': [15.253988, 8.588872, 4.002085, 2.351638, 1.762327, 0.853486, 0.321922, 0.187195, -0.134910, -0.136539, -0.138118, -0.020945, 0.010875, 0.006313, 0.002927],
               '403.0': [15.633908, 8.833914, 4.146499, 2.431543, 1.798185, 0.874350, 0.333470, 0.192128, -0.130119, -0.134795, -0.136049, -0.019307, 0.012037, 0.006674, 0.003002],
               '404.0': [15.991816, 9.066159, 4.283401, 2.507818, 1.831721, 0.894119, 0.344256, 0.196415, -0.125758, -0.133516  , -0.134189, -0.017659, -0.013281,0.007053, 0.003061],
               '405.0': [16.349725, 9.298403, 4.420303, 2.584094, 1.865257, 0.913887, 0.355041, 0.200702, -0.121396, -0.132237, -0.132330, -0.016012, 0.014525, 0.007433, 0.003120]
               })

我需要做的是估计下面等式中的K。基本上每一列都对应一个 I(z) 配置文件。必须计算 I(0),为此我使用了 curve_fit 作为参考,我正在使用这篇有用的帖子:https://stackoverflow.com/a/15369787/7541421

x = df1.depth       # Column values as a function of depth
y = df1['400.0']

plt.plot(x, y, 'ro',label="Original Data")

def func(def func(x, I0, k):     # a = I0, b = k
    return I0 * np.exp(-k*x)    

popt, pcov = curve_fit(func, x, y)

print ("E0 = %s , k = %s" % (popt[0], popt[1]))

plt.plot(x, func(x, *popt), label="Fitted Curve")

是否可以对每一列分别进行并以某种方式保存新的DataFrame

此外,对于某些 dz 配额,新的 DataFrame 需要传播z=0 的值。在这种情况下,我的 depth 列中缺少 [0.15, 0.65, 1.15] 。 因此,对于每个z,我需要从函数中为每一列获取I(z)

在我的案例中,每个数据集都有不同的深度范围,我该如何实现自动化?

附:或者,正如本文最初讨论的那样,可以应用对数转换线性回归拟合,其解决方案写在下面的答案中。

【问题讨论】:

    标签: python pandas scipy regression curve-fitting


    【解决方案1】:

    在与此答案的主要作者交谈并获得他的批准后,已进行了一些更改。

    首先,由于我们处理的是对数变换量,因此有必要找到对应于每列非负值的值范围。

    negative_idx_aux = df_drop_depth.apply(lambda x:(x<0).nonzero()[0][:1].tolist())   
    negative_idx = [item for sublist in negative_idx_aux for item in sublist]
    
    if len(negative_idx) > 0:
        max_idx = max_idx = np.min(negative_idx)
    else:
        max_idx = None
    

    与原来相比,我只合并循环以获得斜率和截距。

    iz_cols = df1.columns.difference(['depth'])
    slp_int = {}
    for c in iz_cols:
        slope, intercept, r_value, p_value, std_err = stats.linregress(df1['depth'][0:max_idx],np.log(df1[c][0:max_idx]))
        slp_int[c] = [intercept, slope]
    
    slp_int = pd.DataFrame(, index = ['intercept', 'slope'])
    

    取幂截距为我们提供了表面上的 I 值:

    slp_int.loc['intercept'] = np.exp(slp_int.loc['intercept'])
    

    由于对最终概念的误解,已更正帖子的最后一部分。 数据框现已重新创建,表面深度具有新值(高于df1 的深度范围,以下值保留 df1。

    首先重新创建 z = 0 和深度列最大值之间的整个范围,并分配一个 step 并保持值在 z = 0

    depth = np.asarray(df1.depth)
    depth_min = np.min(depth)    ;   
    depth_min_arr = np.array([depth_min])
    step = 0.5
    missing_vals_aux = np.arange(depth_min - step, 0, -step)[::-1]
    missing_vals = np.concatenate(([0.], missing_vals_aux), axis=0)
    depth_tot = np.concatenate((missing_vals, depth), axis=0)
    
    df_boundary = pd.DataFrame(columns = iz_cols) 
    df_up = pd.DataFrame(columns = iz_cols) 
    

    使用向上传播的深度配额范围创建一个数据框:

    for c in iz_cols: 
        df_up[c]       = missing_vals
    

    用回归得到的参数填充数据:

    upper_df = slp_int.loc['intercept']*np.exp(slp_int.loc['slope']*df_up)
    upper_df['depth'] = missing_vals
    

    合并df1和upper_df得到一个完整的profile:

    lower_df = df1
    lower_df['depth'] = depth
    
    df_profile_tot = upper_df.append(lower_df, ignore_index=True)
    

    【讨论】:

    • 我能再问你一个问题吗?假设我需要将某些 dz 配额的值传播到 z=0。在这种情况下 [1.15, 0.65, 0.15]。因此,对于每个 z,我需要从上面的等式中获取每列的 I(z):I0 = np.exp(intercept),然后是 I(z) = I0*np.exp(slope*x)。所以实际上我需要根据每个截距和每列向 z = 0 fot 固定 dz 层的斜率填充数据框@Vishnu
    • 您能否将其添加到原始问题中以便我可以编辑我的答案?
    • 每列的 x 代表什么?
    • 所以基本上对于每一列(400401 等),您需要使用每列的斜率和截距为 depth 的每个值生成预测,是的?
    猜你喜欢
    • 2016-04-26
    • 2018-03-26
    • 2021-01-30
    • 2020-06-26
    • 2020-12-06
    • 2018-10-01
    • 1970-01-01
    • 2021-01-19
    • 1970-01-01
    相关资源
    最近更新 更多