top of page
รูปภาพนักเขียนJuglans Regia

การลด Noise ในข้อมูลทางการเงิน

ทฤษฏีทางการเงินยุคใหม่อยู่อยู่บนสมมุติฐานของผลตอบแทนและความเสี่ยง ทำให้ Covariance matrices มีความสำคัญกับการพัฒนาแบบจำลอง ทั้งการ ประเมินความเสี่ยง เพิ่มประสิทธิภาพพอร์ตโฟลิโอ จำลองสถานการณ์ผ่านมอนติคาร์โล ค้นหาคลัสเตอร์ ลดขนาดพื้นที่เวกเตอร์

แต่การประมาณค่า Covariance matrices มักจะเกิด noise จนทำให้แบบจำลองของเราอาจใช้การไม่ได้ ดังนั้นการจัดการกับ noise และปรับปรุง Covariance matrices จึงมีความสำคัญมาก

Marcenko–Pastur Theorem


The Marcenko–Pastur theorem เป็นผลจากทฤษฎีเมทริกซ์สุ่มที่ให้ความสัมพันธ์ระหว่างค่าลักษณะเฉพาะของเมทริกซ์สุ่มขนาดใหญ่และมิติของเมทริกซ์ เมทริกซ์สุ่มเป็นไปตามการแจกแจงแบบหนึ่งที่เรียกว่าการแจกแจงแบบมาร์เชนโก-ปาสเตอร์ ซึ่งขึ้นอยู่กับอัตราส่วนของจำนวนแถวต่อจำนวนคอลัมน์ในเมทริกซ์

ทฤษฎีบท Marcenko–Pastur ถูกใช้ในด้านการเงิน มักใช้ในการวิเคราะห์ค่าลักษณะเฉพาะของเมทริกซ์ความแปรปรวนร่วมตัวอย่างของชุดสินทรัพย์ทางการเงิน เพื่อให้เข้าใจโครงสร้างพื้นฐานของผลตอบแทนและความสัมพันธ์ของสินทรัพย์ จากหนังสือเราจะได้ code ตัวอย่างมา

def mpPDF(var, q, pts):
    eMin, eMax = var*(1-(1./q)**.5)**2, var*(1+(1./q)**.5)**2 # calc lambda_minus, lambda_plus
    eVal = np.linspace(eMin, eMax, pts) #Return evenly spaced numbers over a specified interval. eVal='lambda'
    #Note: 1.0/2*2 = 1.0 not 0.25=1.0/(2*2)
    pdf = q/(2*np.pi*var*eVal)*((eMax-eVal)*(eVal-eMin))**.5 #np.allclose(np.flip((eMax-eVal)), (eVal-eMin))==True
    pdf = pd.Series(pdf, index=eVal)
    return pdf

และทดสอบด้วย

def getPCA(matrix):
    # Get eVal, eVec from a Hermitian matrix
    eVal, eVec = np.linalg.eig(matrix) #complex Hermitian (conjugate symmetric) or a real symmetric matrix.
    indices = eVal.argsort()[::-1] #arguments for sorting eval desc
    eVal,eVec = eVal[indices],eVec[:,indices]
    eVal = np.diagflat(eVal) # identity matrix with eigenvalues as diagonal
    return eVal,eVec
#---------------------------------------------------

def fitKDE(obs, bWidth=.15, kernel='gaussian', x=None):
    #Fit kernel to a series of obs, and derive the prob of obs
    # x is the array of values on which the fit KDE will be evaluated
    #print(len(obs.shape) == 1)
    if len(obs.shape) == 1: obs = obs.reshape(-1,1)
    kde = KernelDensity(kernel = kernel, bandwidth = bWidth).fit(obs)
    #print(x is None)
    if x is None: x = np.unique(obs).reshape(-1,1)
    #print(len(x.shape))
    if len(x.shape) == 1: x = x.reshape(-1,1)
    logProb = kde.score_samples(x) # log(density)
    pdf = pd.Series(np.exp(logProb), index=x.flatten())
    return pdf

แต่อย่างไรก็ตามเราไม่สามารถสร้างที่สมบูรณ์แบบได้ด้วยการสุ่ม

Marcenko–Pastur Distribution

การแจกแจงแบบ Marcenko–Pastur เป็นการแจกแจงความน่าจะเป็นที่อธิบายค่าลักษณะเฉพาะของเมทริกซ์สุ่มที่มีจำนวนแถวและคอลัมน์จำนวนหนึ่ง ในบริบทของเมทริกซ์ความแปรปรวนร่วม สามารถใช้การแจกแจง Marcenko–Pastur เพื่อวิเคราะห์ค่าลักษณะเฉพาะของเมทริกซ์ความแปรปรวนร่วมตัวอย่างของชุดสินทรัพย์ทางการเงิน

การแจกแจง Marcenko–Pastur กำหนดไว้ดังนี้:

$$f(x) = \frac{1}{2\pi qx}\sqrt{(b-x)(x-a)}$$

โดยที่ $a$ และ $b$ เป็นขอบเขตล่างและบนของการแจกแจง ตามลำดับ และ $q = \frac{T}{N}$ คืออัตราส่วนของจำนวนการสังเกต (T) ต่อจำนวนสินทรัพย์ ( น). ขอบเขตล่างและบนของการกระจายถูกกำหนดโดย:

$$a = (1 — \sqrt{q})²$$ $$b = (1 + \sqrt{q})²$$

รูปร่างของการแจกแจง Marcenko–Pastur ขึ้นอยู่กับค่าของ $q$ สำหรับ $q > 1$ การกระจายจะ “กว้าง” และมีจุดสูงสุดเดียว ในขณะที่สำหรับ $q < 1$ การกระจายจะ “แคบ” และมีจุดสูงสุด 2 จุด

#snippet 2.3
def getRndCov(nCols, nFacts): #nFacts - contains signal out of nCols
    w = np.random.normal(size=(nCols, nFacts))
    cov = np.dot(w, w.T) #random cov matrix, however not full rank
    cov += np.diag(np.random.uniform(size=nCols)) #full rank cov
    return cov
#---------------------------------------------------

def cov2corr(cov):
    # Derive the correlation matrix from a covariance matrix
    std = np.sqrt(np.diag(cov))
    corr = cov/np.outer(std,std)
    corr[corr<-1], corr[corr>1] = -1,1 #for numerical errors
    return corr
#---------------------------------------------------
def corr2cov(corr, std):
    cov = corr * np.outer(std, std)
    return cov    

ลองทดสอบโดย

#snippet 2.4 - fitting the marcenko-pastur pdf - find variance
#Fit error
def errPDFs(var, eVal, q, bWidth, pts=1000):
    var = var[0]
    pdf0 = mpPDF(var, q, pts) #theoretical pdf
    pdf1 = fitKDE(eVal, bWidth, x=pdf0.index.values) #empirical pdf
    sse = np.sum((pdf1-pdf0)**2)
    print("sse:"+str(sse))
    return sse 
    
# find max random eVal by fitting Marcenko's dist
# and return variance
def findMaxEval(eVal, q, bWidth):
    out = minimize(lambda *x: errPDFs(*x), x0=np.array(0.5), args=(eVal, q, bWidth), bounds=((1E-5, 1-1E-5),))
    print("found errPDFs"+str(out['x'][0]))
    if out['success']: var = out['x'][0]
    else: var=1
    eMax = var*(1+(1./q)**.5)**2
    return eMax, var

จะได้การแจกแจงดังนี้

Denoising

โดยทั่วไปในทางการเงินที่จะลดขนาดเมทริกซ์ความแปรปรวนร่วมที่มีเงื่อนไขเป็นตัวเลขทำให้เมทริกซ์ความแปรปรวนร่วมเข้าใกล้เส้นทแยงมุมมากขึ้นและลดสัญญาณรบกวน

# DENOISING BY CONSTANT RESIDUAL EIGENVALUE

def denoisedCorr(eVal, eVec, nFacts):
    eVal_ = np.diag(eVal).copy()
    eVal_[nFacts:] = eVal_[nFacts:].sum()/float(eVal_.shape[0] - nFacts) #all but 0..i values equals (1/N-i)sum(eVal_[i..N]))
    eVal_ = np.diag(eVal_) #square matrix with eigenvalues as diagonal: eVal_.I
    corr1 = np.dot(eVec, eVal_).dot(eVec.T) #Eigendecomposition of a symmetric matrix: S = QΛQT
    corr1 = cov2corr(corr1) # Rescaling the correlation matrix to have 1s on the main diagonal
    return corr1


Detoning

เครื่องมือ Detoning เป็นวิธีการขั้นสูงที่รวมเมทริกซ์ความแปรปรวนร่วมของตัวอย่างเข้ากับค่าประมาณ “ก่อนหน้า” ของเมทริกซ์ความแปรปรวนร่วม เช่น เมทริกซ์เอกลักษณ์หรือเมทริกซ์ความแปรปรวนร่วมตัวอย่างของสินทรัพย์ชุดอื่น ตัวประมาณค่าการหดตัวมีข้อได้เปรียบในการทนทานต่อค่าผิดปกติและอาจให้การประมาณเมทริกซ์ความแปรปรวนร่วมที่แม่นยำกว่าในบางกรณี

def detoned_corr(corr, eigenvalues, eigenvectors, market_component=1):
    """
    De-tones the de-noised correlation matrix by removing the market component.
    The input is the eigenvalues and the eigenvectors of the correlation matrix and the number
    of the first eigenvalue that is above the maximum theoretical eigenvalue and the number of
    eigenvectors related to a market component.
    :param corr: (np.array) Correlation matrix to detone.
    :param eigenvalues: (np.array) Matrix with eigenvalues on the main diagonal.
    :param eigenvectors: (float) Eigenvectors array.
    :param market_component: (int) Number of fist eigevectors related to a market component. (1 by default)
    :return: (np.array) De-toned correlation matrix.
    """
    
    # Getting the eigenvalues and eigenvectors related to market component
    eigenvalues_mark = eigenvalues[:market_component, :market_component]
    eigenvectors_mark = eigenvectors[:, :market_component]
    
    # Calculating the market component correlation
    corr_mark = np.dot(eigenvectors_mark, eigenvalues_mark).dot(eigenvectors_mark.T)
    
    # Removing the market component from the de-noised correlation matrix
    corr = corr - corr_mark
    
    # Rescaling the correlation matrix to have 1s on the main diagonal
    corr = cov2corr(corr)
    
    return 

ส่งท้าย

Marcenko–Pastur ให้การกระจายของค่าลักษณะเฉพาะที่เกี่ยวข้องกับเมทริกซ์แบบสุ่ม เราสามารถแยกแยะระหว่างค่าลักษณะเฉพาะที่เกี่ยวข้องกับสัญญาณและค่าลักษณะเฉพาะที่เกี่ยวข้องกับสัญญาณรบกวนได้

เงื่อนไขของเมทริกซ์สหสัมพันธ์คืออัตราส่วนระหว่างค่าลักษณะเฉพาะสูงสุดและต่ำสุด (ตามโมดูลี) Denoising ช่วยลดจำนวนเงื่อนไขโดยการเพิ่มค่าลักษณะเฉพาะที่ต่ำที่สุด เราสามารถลดจำนวนเงื่อนไขลงได้อีกโดยการลดค่าลักษณะเฉพาะสูงสุด สิ่งนี้ทำให้เกิดความรู้สึกทางคณิตศาสตร์และยังเป็นความรู้สึกที่เข้าใจได้ง่าย การลบส่วนประกอบของตลาดที่มีอยู่ใน


อ้างอิง

コメント


bottom of page