सहसंबंधित डेटा सिमुलेशन के लिए चोल्स्की अपघटन, या एक विकल्प का उपयोग कैसे करें


19

मैं एक सहसंबंध मैट्रिक्स दिया सहसंबद्ध यादृच्छिक चर का अनुकरण करने के लिए चोल्स्की अपघटन का उपयोग करता हूं। बात यह है, परिणाम कभी भी सहसंबंध संरचना को पुन: पेश नहीं करता है जैसा कि दिया गया है। यहां स्थिति का वर्णन करने के लिए पायथन में एक छोटा सा उदाहरण है।

import numpy as np    

n_obs = 10000
means = [1, 2, 3]
sds = [1, 2, 3] # standard deviations 

# generating random independent variables 
observations = np.vstack([np.random.normal(loc=mean, scale=sd, size=n_obs)
                   for mean, sd in zip(means, sds)])  # observations, a row per variable

cor_matrix = np.array([[1.0, 0.6, 0.9],
                       [0.6, 1.0, 0.5],
                       [0.9, 0.5, 1.0]])

L = np.linalg.cholesky(cor_matrix)

print(np.corrcoef(L.dot(observations))) 

यह प्रिंट:

[[ 1.          0.34450587  0.57515737]
 [ 0.34450587  1.          0.1488504 ]
 [ 0.57515737  0.1488504   1.        ]]

जैसा कि आप देख सकते हैं, पोस्ट-हॉक अनुमानित सहसंबंध मैट्रिक्स काफी पहले से अलग है। क्या मेरे कोड में एक बग है, या चोल्स्की अपघटन का उपयोग करने के लिए कोई विकल्प है?

संपादित करें

मैं इस गड़बड़ी के लिए आपसे क्षमा चाहता हूं। मुझे नहीं लगता था कि कोड और / या जिस तरह से मैंने पहले अध्ययन किया था सामग्री की कुछ गलतफहमी के कारण चोल्स्की अपघटन लागू किया गया था, उसमें कोई त्रुटि थी। वास्तव में मुझे यकीन था कि विधि स्वयं सटीक होने के लिए नहीं थी और मैं उस स्थिति तक ठीक था जब तक कि मुझे इस प्रश्न को पोस्ट नहीं किया गया। मेरे द्वारा की गई गलतफहमी को इंगित करने के लिए धन्यवाद। मैंने @Silverfish द्वारा प्रस्तावित वास्तविक स्थिति को बेहतर ढंग से दर्शाने के लिए शीर्षक संपादित किया है।


1
चोल्स्की ठीक काम करता है, और यह वास्तव में "आप मेरे कोड में बग ढूंढ सकते हैं" प्रकार का प्रश्न है। सवाल का शीर्षक और सामग्री, जैसा कि मूल रूप से लिखा गया है, मूल रूप से "चोल्स्की काम नहीं करता है, एक विकल्प क्या है"? जो कि इस साइट को खोजने वाले उपयोगकर्ताओं के लिए बहुत भ्रामक होगा। क्या इस प्रश्न को प्रतिबिंबित करने के लिए संपादित किया जाना चाहिए? (नकारात्मक पक्ष यह है कि javlacalle का उत्तर कम प्रासंगिक होगा। उल्टा प्रश्न यह है कि प्रश्न पाठ तब प्रतिबिंबित करेगा कि खोजकर्ता वास्तव में पृष्ठ पर क्या पाएंगे।)
सिल्वरफ़िश

@Antoni Parellada हाँ, मुझे लगता है कि आपने मेरे (MATLAB कोड) का अनुवाद (a) के लिए किया है, इसे सही तरीके से करने के लिए Python numpy में, np.linalg.cholesky के लिए समायोजन के साथ पूर्ण त्रिभुज बनाम MATLAB के ऊपरी ऊपरी त्रिकोणीय होने के कारण त्रिकोणीय है। मैंने पहले ही ओपीटी के गलत कोड को इसके MATLAB समकक्ष के रूप में अनुवादित किया और उसके गलत परिणामों को दोहराया।
मार्क एल। स्टोन

जवाबों:


11

चोल्स्की अपघटन पर आधारित दृष्टिकोण काम करना चाहिए, यह यहां वर्णित है और मार्क एल। स्टोन के उत्तर में दिखाया गया है जो लगभग एक ही समय में पोस्ट किया गया है।

एन(μ,Σ)

Y=क्यूएक्स+μ,साथ मेंक्यू=Λ1/2Φ,

Yएक्सΦΣΛΣΦ

उदाहरण के लिए R(क्षमा करें, मैं उसी सॉफ़्टवेयर का उपयोग नहीं कर रहा हूं जिसका आपने प्रश्न में उपयोग किया है):

n <- 10000
corM <- rbind(c(1.0, 0.6, 0.9), c(0.6, 1.0, 0.5), c(0.9, 0.5, 1.0))
set.seed(123)
SigmaEV <- eigen(corM)
eps <- rnorm(n * ncol(SigmaEV$vectors))
Meps <- matrix(eps, ncol = n, byrow = TRUE)    
Meps <- SigmaEV$vectors %*% diag(sqrt(SigmaEV$values)) %*% Meps
Meps <- t(Meps)
# target correlation matrix
corM
#      [,1] [,2] [,3]
# [1,]  1.0  0.6  0.9
# [2,]  0.6  1.0  0.5
# [3,]  0.9  0.5  1.0
# correlation matrix for simulated data
cor(Meps)
#           [,1]      [,2]      [,3]
# [1,] 1.0000000 0.6002078 0.8994329
# [2,] 0.6002078 1.0000000 0.5006346
# [3,] 0.8994329 0.5006346 1.0000000

आपको इस पोस्ट और इस पोस्ट में भी दिलचस्पी हो सकती है ।


पुनरुत्पादित सहसंबंध-मैट्रिक्स को सटीक बनाने के लिए डेटा-जेनरेशन-प्रक्रिया को लागू करने से पहले यादृच्छिक-जनरेटर से यादृच्छिक-डेटा में सहज सहसंबंधों को हटा देना चाहिए। उदाहरण के लिए, पहले उस बेतरतीब सहसंबंध को देखने के लिए eps में अपने यादृच्छिक-डेटा के सहसंबंध की जाँच करें।
गॉटफ्रीड हेल्स

17

लोगों को संभवतः आपकी त्रुटि बहुत तेज़ी से मिल जाएगी यदि आपने समझाया कि आपने कोड के बजाय शब्दों और बीजगणित के साथ क्या किया था (या कम से कम इसे स्यूडोकोड का उपयोग करके लिख रहे हैं)।

आप इसके समतुल्य प्रतीत होते हैं (हालाँकि संभवतः ट्रांसपोज़्ड):

  1. n×जेड

  2. σमैंμमैं

  3. Y=एलएक्स

एल

आपको क्या करना चाहिए:

  1. n×जेड

  2. एक्स=एलजेड

  3. σमैंμमैं

साइट पर इस एल्गोरिथ्म के कई स्पष्टीकरण हैं। जैसे

सहसंबद्ध यादृच्छिक संख्या (दिए गए साधन, भिन्नता और सहसंबंध की डिग्री) कैसे उत्पन्न करें?

क्या मैं दिए गए माध्य के साथ सहसंबद्ध यादृच्छिक चर उत्पन्न करने के लिए चोल्स्की-विधि का उपयोग कर सकता हूं?

यह एक वांछित covariance मैट्रिक्स के संदर्भ में सीधे चर्चा करता है, और एक वांछित नमूना सहसंयोजक प्राप्त करने के लिए एक एल्गोरिथ्म भी देता है :

एक दिए गए नमूना सहसंयोजक मैट्रिक्स के साथ डेटा उत्पन्न करना


11

चोल्स्की कारक के साथ कुछ भी गलत नहीं है। आपके कोड में कोई त्रुटि है। नीचे संपादित देखें।

यहां MATLAB कोड और परिणाम हैं, पहले n_obs = 10000 के लिए, जैसा कि आपके पास है, फिर n_obs = 1e8 के लिए। सादगी के लिए, क्योंकि यह परिणामों को प्रभावित नहीं करता है, मैं साधनों से परेशान नहीं होता, अर्थात, मैं उन्हें शून्य बनाता हूं। ध्यान दें कि MATLAB का चॉइस मैट्रिक्स M के ऊपरी त्रिकोणीय चोल्स्की फैक्टर R का उत्पादन करता है जैसे कि R '* R = M. numpy.linalg.cholesky एक कम त्रिकोणीय चोल्स्की फैक्टर का उत्पादन करता है, इसलिए एक समायोजन बनाम उसके कोड की आवश्यकता होती है; लेकिन मेरा मानना ​​है कि उस संदर्भ में आपका कोड ठीक है।

   >> correlation_matrix = [1.0, 0.6, 0.9; 0.6, 1.0, 0.5;0.9, 0.5, 1.0];
   >> SD = diag([1 2 3]);
   >> covariance_matrix = SD*correlation_matrix*SD
   covariance_matrix =
      1.000000000000000   1.200000000000000   2.700000000000000
      1.200000000000000   4.000000000000000   3.000000000000000
      2.700000000000000   3.000000000000000   9.000000000000000
   >> n_obs = 10000;
   >> Random_sample = randn(n_obs,3)*chol(covariance_matrix);
   >> disp(corr(Random_sample))
      1.000000000000000   0.599105015695768   0.898395949647890
      0.599105015695768   1.000000000000000   0.495147514173305
      0.898395949647890   0.495147514173305   1.000000000000000
   >> n_obs = 1e8;
   >> Random_sample = randn(n_obs,3)*chol(covariance_matrix);
   >> disp(corr(Random_sample))
      1.000000000000000   0.600101477583914   0.899986072541418
      0.600101477583914   1.000000000000000   0.500112824962378
      0.899986072541418   0.500112824962378   1.000000000000000

संपादित करें: मुझे आपकी गलती मिली। आपने मानक विचलन को गलत तरीके से लागू किया। आपने जो किया, वह गलत है।

   >> n_obs = 10000;
   >> Random_sample = randn(n_obs,3)*SD*chol(correlation_matrix);
   >> disp(corr(Random_sample))
      1.000000000000000   0.336292731308138   0.562331469857830
      0.336292731308138   1.000000000000000   0.131270077244625
      0.562331469857830   0.131270077244625   1.000000000000000
   >> n_obs=1e8;
   >> Random_sample = randn(n_obs,3)*SD*chol(correlation_matrix);
   >> disp(corr(Random_sample))
      1.000000000000000   0.351254525742470   0.568291702131030
      0.351254525742470   1.000000000000000   0.140443281045496
      0.568291702131030   0.140443281045496   1.000000000000000

6

सीवी कोड के बारे में नहीं है, लेकिन मुझे यह देखने के लिए तैयार किया गया था कि यह सभी अच्छे उत्तरों और विशेष रूप से @Mark L. स्टोन योगदान के बाद कैसा दिखेगा। प्रश्न का वास्तविक उत्तर उसकी पोस्ट पर दिया गया है (कृपया संदेह के मामले में उसके पोस्ट को क्रेडिट करें)। मैं भविष्य में इस पोस्ट की पुनः प्राप्ति की सुविधा के लिए इस संलग्न जानकारी को यहाँ ले जा रहा हूँ। मार्क के जवाब के बाद किसी भी अन्य उत्कृष्ट जवाब को खेले बिना, यह ओपी में पोस्ट को सही करके इस मुद्दे को लपेटता है।

स्रोत

अजगर में:

import numpy as np

no_obs = 1000             # Number of observations per column
means = [1, 2, 3]         # Mean values of each column
no_cols = 3               # Number of columns

sds = [1, 2, 3]           # SD of each column
sd = np.diag(sds)         # SD in a diagonal matrix for later operations

observations = np.random.normal(0, 1, (no_cols, no_obs)) # Rd draws N(0,1) in [3 x 1,000]

cor_matrix = np.array([[1.0, 0.6, 0.9],
                       [0.6, 1.0, 0.5],
                       [0.9, 0.5, 1.0]])          # The correlation matrix [3 x 3]

cov_matrix = np.dot(sd, np.dot(cor_matrix, sd))   # The covariance matrix

Chol = np.linalg.cholesky(cov_matrix)             # Cholesky decomposition

array([[ 1.        ,  0.        ,  0.        ],
       [ 1.2       ,  1.6       ,  0.        ],
       [ 2.7       , -0.15      ,  1.29903811]])

sam_eq_mean = Chol .dot(observations)             # Generating random MVN (0, cov_matrix)

s = sam_eq_mean.transpose() + means               # Adding the means column wise
samples = s.transpose()                           # Transposing back

print(np.corrcoef(samples))                       # Checking correlation consistency.

[[ 1.          0.59167434  0.90182308]
 [ 0.59167434  1.          0.49279316]
 [ 0.90182308  0.49279316  1.        ]]

[R] में:

no_obs = 1000             # Number of observations per column
means = 1:3               # Mean values of each column
no_cols = 3               # Number of columns

sds = 1:3                 # SD of each column
sd = diag(sds)         # SD in a diagonal matrix for later operations

observations = matrix(rnorm(no_cols * no_obs), nrow = no_cols) # Rd draws N(0,1)

cor_matrix = matrix(c(1.0, 0.6, 0.9,
                      0.6, 1.0, 0.5,
                      0.9, 0.5, 1.0), byrow = T, nrow = 3)     # cor matrix [3 x 3]

cov_matrix = sd %*% cor_matrix %*% sd                          # The covariance matrix

Chol = chol(cov_matrix)                                        # Cholesky decomposition

     [,1] [,2]      [,3]
[1,]    1  1.2  2.700000
[2,]    0  1.6 -0.150000
[3,]    0  0.0  1.299038

sam_eq_mean = t(observations) %*% Chol          # Generating random MVN (0, cov_matrix)

samples = t(sam_eq_mean) + means

cor(t(samples))

          [,1]      [,2]      [,3]
[1,] 1.0000000 0.6071067 0.8857339
[2,] 0.6071067 1.0000000 0.4655579
[3,] 0.8857339 0.4655579 1.0000000

colMeans(t(samples))
[1] 1.035056 2.099352 3.065797
apply(t(samples), 2, sd)
[1] 0.9543873 1.9788250 2.8903964

1

जैसा कि दूसरों ने पहले ही दिखाया है: चोल्स्की काम करता है। यहाँ कोड का एक टुकड़ा जो बहुत छोटा है और छद्मकोड के बहुत पास है: MatMate में एक कोडपीस:

Co = {{1.0, 0.6, 0.9},  _
      {0.6, 1.0, 0.5},  _
      {0.9, 0.5, 1.0}}           // make correlation matrix


chol = cholesky(co)              // do cholesky-decomposition           
data = chol * unkorrzl(randomn(3,100,0,1))  
                                 // dot-multiply cholesky with random-
                                 // vectors with mean=0, sdev=1  
                                 //(refined by a "decorrelation" 
                                 //to remove spurious/random correlations)   


chk = data *' /100               // check the correlation of the data
list chk

1.0000  0.6000  0.9000
0.6000  1.0000  0.5000
0.9000  0.5000  1.0000
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.