相关文章推荐
绅士的蚂蚁  ·  一文读懂异常检测 LOF ...·  4 天前    · 
难过的春卷  ·  Cannot add merged ...·  3 天前    · 
年轻有为的双杠  ·  npm ERR! gyp ERR! ...·  3 天前    · 
卖萌的烤土司  ·  【BOOST C++ 19 ...·  4 月前    · 
绅士的鸡蛋面  ·  Hadoop之——Permission ...·  1 年前    · 
聪明的冰棍  ·  nuxt ...·  1 年前    · 

如果没有,有什么简单的算法可以推荐给我吗?

2 个评论
你可以尝试用 rfft() 来变换你的信号,并将低频部分设置为零,从而设计一个高路径滤波器。
你应该看看这个问题中的最低限度的寻找技巧。 stackoverflow.com/questions/24656367/... . 一旦你有了这些,你就可以只对最小值进行拟合以找到你的基线校正。
python
numpy
scipy
signal-processing
Tinker
Tinker
发布于 2015-03-20
6 个回答
Tinker
Tinker
发布于 2017-08-17
已采纳
0 人赞同

我找到了问题的答案,只是为每个偶然发现这个问题的人分享。

P. Eilers和H. Boelens在2005年提出了一种叫做 "非对称最小二乘法平滑 "的算法。该论文是免费的,你可以在谷歌上找到它。

def baseline_als(y, lam, p, niter=10):
  L = len(y)
  D = sparse.csc_matrix(np.diff(np.eye(L), 2))
  w = np.ones(L)
  for i in xrange(niter):
    W = sparse.spdiags(w, 0, L, L)
    Z = W + lam * D.dot(D.transpose())
    z = spsolve(Z, w*y)
    w = p * (y > z) + (1-p) * (y < z)
  return z
    
works perfectly for me. just quoting from that paper what those parameters are: <<There are two parameters: p for asymmetry and λ for smoothness. Both have to be tuned to the data at hand. We found that generally 0.001 ≤ p ≤ 0.1 is a good choice (for a signal with positive peaks) and 10^2 ≤ λ ≤ 10^9 , but exceptions may occur. In any case one should vary λ on a grid that is approximately linear for log λ>>
只是一个简单的问题--基本上 z 就是基线?所以光谱需要在最后减去该阵列以获得基线校正?
我找不到这篇论文,你能给我链接吗?谢谢
我自己找不到那份文件,但 this 文章对AsLS和相关方法进行了非常清晰的解释。顺便说一下,他们提出的版本在我的案例中效果要好得多。
jpantina
jpantina
发布于 2017-08-17
0 人赞同

The following code works on Python 3.6.

这是从公认的正确答案改编的,以避免密集矩阵 diff 的计算(这很容易导致内存问题),并使用 range (而不是 xrange )。

import numpy as np
from scipy import sparse
from scipy.sparse.linalg import spsolve
def baseline_als(y, lam, p, niter=10):
  L = len(y)
  D = sparse.diags([1,-2,1],[0,-1,-2], shape=(L,L-2))
  w = np.ones(L)
  for i in range(niter):
    W = sparse.spdiags(w, 0, L, L)
    Z = W + lam * D.dot(D.transpose())
    z = spsolve(Z, w*y)
    w = p * (y > z) + (1-p) * (y < z)
  return z
    
Rustam Guliev
Rustam Guliev
发布于 2017-08-17
0 人赞同

最近,我需要使用这种方法。答案中的代码工作得很好,但它显然过度使用了内存。所以,这里是我的版本,对内存的使用进行了优化。

def baseline_als_optimized(y, lam, p, niter=10):
    L = len(y)
    D = sparse.diags([1,-2,1],[0,-1,-2], shape=(L,L-2))
    D = lam * D.dot(D.transpose()) # Precompute this term since it does not depend on `w`
    w = np.ones(L)
    W = sparse.spdiags(w, 0, L, L)
    for i in range(niter):
        W.setdiag(w) # Do not create a new matrix, just update diagonal values
        Z = W + D
        z = spsolve(Z, w*y)
        w = p * (y > z) + (1-p) * (y < z)
    return z

根据我下面的基准测试,它的速度也是1.5倍左右。

%%timeit -n 1000 -r 10 y = randn(1000)
baseline_als(y, 10000, 0.05) # function from @jpantina's answer
# 20.5 ms ± 382 µs per loop (mean ± std. dev. of 10 runs, 1000 loops each)
%%timeit -n 1000 -r 10 y = randn(1000)
baseline_als_optimized(y, 10000, 0.05)
# 13.3 ms ± 874 µs per loop (mean ± std. dev. of 10 runs, 1000 loops each)

NOTE 1:原文中说。

为了强调算法的基本简单性,迭代次数被固定为10次。在实际应用中,人们应该检查权重是否有任何变化;如果没有,就说明已经达到了收敛的目的。

因此,这意味着停止迭代的更正确方法是检查||w_new - w|| < tolerance

NOTE 2:另一句有用的话(来自@glycoaddict的评论)给出了如何选择参数值的想法。

有两个参数:P代表不对称性,λ代表平稳性。两者都必须 都要根据手头的数据进行调整。我们发现,通常0.001≤p≤0.1是一个很好的选择(对于具有正峰值的信号),102≤λ≤109,但也可能出现例外。在任何情况下,人们应该在对数λ近似线性的网格上改变λ。通常情况下,目测就可以得到好的参数值。

对二维数据使用这种方法是否正确,或者是否有更合适的实现方法?我想从荧光显微镜图像中去除基线。它的效果很好,但是很慢。我正在用ravel平整阵列,然后用你的代码来寻找基线。
StatguyUser
StatguyUser
发布于 2017-08-17
0 人赞同

有一个python库可用于基线校正/去除。它有Modpoly、IModploy和Zhang fit算法,当你把原始值作为python列表或pandas序列输入并指定多项式程度时,可以返回基线校正的结果。

将该库安装为 pip install BaselineRemoval 。下面是一个例子

from BaselineRemoval import BaselineRemoval
input_array=[10,20,1.5,5,2,9,99,25,47]
polynomial_degree=2 #only needed for Modpoly and IModPoly algorithm
baseObj=BaselineRemoval(input_array)
Modpoly_output=baseObj.ModPoly(polynomial_degree)
Imodpoly_output=baseObj.IModPoly(polynomial_degree)
Zhangfit_output=baseObj.ZhangFit()
print('Original input:',input_array)
print('Modpoly base corrected values:',Modpoly_output)
print('IModPoly base corrected values:',Imodpoly_output)
print('ZhangFit base corrected values:',Zhangfit_output)
Original input: [10, 20, 1.5, 5, 2, 9, 99, 25, 47]
Modpoly base corrected values: [-1.98455800e-04  1.61793368e+01  1.08455179e+00  5.21544654e+00
  7.20210508e-02  2.15427531e+00  8.44622093e+01 -4.17691125e-03
  8.75511661e+00]
IModPoly base corrected values: [-0.84912125 15.13786196 -0.11351367  3.89675187 -1.33134142  0.70220645
 82.99739548 -1.44577432  7.37269705]
ZhangFit base corrected values: [ 8.49924691e+00  1.84994576e+01 -3.31739230e-04  3.49854060e+00
  4.97412948e-01  7.49628529e+00  9.74951576e+01  2.34940300e+01
  4.54929023e+01
    
我试着使用BaselineRemoval库,其中输入数组是一个数据框架列的列表,但它无法运行。给出的错误是'ValueError: setting an array element with a sequence.
@Sp_95 检查 1) 数组的维度,如果它是一维的Python列表对象或dataframe['ColumnName'].tolist(),它应该工作。2) 你是否使用了最新版本的库。如果你仍然面临这个问题,请用实例数据创建一个单独的问题,并在这里发布问题链接。我将很高兴研究这个问题。
Daniel Casas-Orozco
Daniel Casas-Orozco
发布于 2017-08-17
0 人赞同

我的工作是在《中国日报》所引用的算法版本中进行的 粘土 在以前的评论中,这是对发表在一个相对较小的杂志上的惩罚性加权线性平方法的改进。 最近的论文 . I took 鲁斯塔姆-古利耶夫的 code to build this one:

from scipy import sparse
from scipy.sparse import linalg
import numpy as np
from numpy.linalg import norm
def baseline_arPLS(y, ratio=1e-6, lam=100, niter=10, full_output=False):
    L = len(y)
    diag = np.ones(L - 2)
    D = sparse.spdiags([diag, -2*diag, diag], [0, -1, -2], L, L - 2)
    H = lam * D.dot(D.T)  # The transposes are flipped w.r.t the Algorithm on pg. 252
    w = np.ones(L)
    W = sparse.spdiags(w, 0, L, L)
    crit = 1
    count = 0
    while crit > ratio:
        z = linalg.spsolve(W + H, W * y)
        d = y - z
        dn = d[d < 0]
        m = np.mean(dn)
        s = np.std(dn)
        w_new = 1 / (1 + np.exp(2 * (d - (2*s - m))/s))
        crit = norm(w_new - w) / norm(w)
        w = w_new
        W.setdiag(w)  # Do not create a new matrix, just update diagonal values
        count += 1
        if count > niter:
            print('Maximum number of iterations exceeded')
            break
    if full_output:
        info = {'num_iter': count, 'stop_criterion': crit}
        return z, d, info
    else:
        return z

为了测试该算法,我创建了一个类似于论文中图3所示的光谱,首先生成了一个由多个高斯峰组成的模拟光谱。

def spectra_model(x):
    coeff = np.array([100, 200, 100])
    mean = np.array([300, 750, 800])
    stdv = np.array([15, 30, 15])
    terms = []
    for ind in range(len(coeff)):
        term = coeff[ind] * np.exp(-((x - mean[ind]) / stdv[ind])**2)
        terms.append(term)
    spectra = sum(terms)
    return spectra
x_vals = np.arange(1, 1001)
spectra_sim = spectra_model(x_vals)

然后,我用直接取自论文的4个点创建了一个三阶内插多项式。

from scipy.interpolate import CubicSpline
x_poly = np.array([0, 250, 700, 1000])
y_poly = np.array([200, 180, 230, 200])
poly = CubicSpline(x_poly, y_poly)
baseline = poly(x_vals)
noise = np.random.randn(len(x_vals)) * 0.1
spectra_base = spectra_sim + baseline + noise

最后,我使用基线校正算法,将基线从改变后的光谱中减去(spectra_base)。

 _, spectra_arPLS, info = baseline_arPLS(spectra_base, lam=1e4, niter=10,
                                         full_output=True)

结果是(作为参考,我与纯ALS的实现进行了比较,由鲁斯塔姆-古利耶夫的, using lam = 1e4 and p = 0.001):

谢谢你,丹尼尔。只有一个问题,这可以应用于一个单一的光谱。如果我们有500个光谱(500xrow),我们如何做到这一点?
Pedro Fluxa
Pedro Fluxa
发布于 2017-08-17
0 人赞同

我知道这是个老问题了,但我几个月前偶然发现了这个问题,并使用spicy.sparse例程实现了同等的答案。

# Baseline removal                                                                                            
def baseline_als(y, lam, p, niter=10):                                                                        
    s  = len(y)                                                                                               
    # assemble difference matrix                                                                              
    D0 = sparse.eye( s )                                                                                      
    d1 = [numpy.ones( s-1 ) * -2]                                                                             
    D1 = sparse.diags( d1, [-1] )                                                                             
    d2 = [ numpy.ones( s-2 ) * 1]                                                                             
    D2 = sparse.diags( d2, [-2] )                                                                             
    D  = D0 + D2 + D1                                                                                         
    w  = np.ones( s )                                                                                         
    for i in range( niter ):                                                                                  
        W = sparse.diags( [w], [0] )                                                                          
        Z =  W + lam*D.dot( D.transpose() )                                                                   
        z = spsolve( Z, w*y )                                                                                 
        w = p * (y > z) + (1-p) * (y < z)                                                                     
    return z