Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1"""helper functions conversion between moments 

2 

3contains: 

4 

5* conversion between central and non-central moments, skew, kurtosis and 

6 cummulants 

7* cov2corr : convert covariance matrix to correlation matrix 

8 

9 

10Author: Josef Perktold 

11License: BSD-3 

12 

13""" 

14 

15import numpy as np 

16from scipy.special import comb 

17 

18 

19def _convert_to_multidim(x): 

20 if any([isinstance(x, list), isinstance(x, tuple)]): 

21 return np.array(x) 

22 elif isinstance(x, np.ndarray): 

23 return x 

24 else: 

25 # something strange was passed and the function probably 

26 # will fall, maybe insert an exception? 

27 return x 

28 

29 

30def _convert_from_multidim(x, totype=list): 

31 if len(x.shape) < 2: 

32 return totype(x) 

33 return x.T 

34 

35 

36def mc2mnc(mc): 

37 """convert central to non-central moments, uses recursive formula 

38 optionally adjusts first moment to return mean 

39 """ 

40 x = _convert_to_multidim(mc) 

41 

42 def _local_counts(mc): 

43 mean = mc[0] 

44 mc = [1] + list(mc) # add zero moment = 1 

45 mc[1] = 0 # define central mean as zero for formula 

46 mnc = [1, mean] # zero and first raw moments 

47 for nn, m in enumerate(mc[2:]): 

48 n = nn + 2 

49 mnc.append(0) 

50 for k in range(n + 1): 

51 mnc[n] += comb(n, k, exact=True) * mc[k] * mean ** (n - k) 

52 return mnc[1:] 

53 

54 res = np.apply_along_axis(_local_counts, 0, x) 

55 # for backward compatibility convert 1-dim output to list/tuple 

56 return _convert_from_multidim(res) 

57 

58 

59def mnc2mc(mnc, wmean=True): 

60 """convert non-central to central moments, uses recursive formula 

61 optionally adjusts first moment to return mean 

62 """ 

63 X = _convert_to_multidim(mnc) 

64 

65 def _local_counts(mnc): 

66 mean = mnc[0] 

67 mnc = [1] + list(mnc) # add zero moment = 1 

68 mu = [] 

69 for n, m in enumerate(mnc): 

70 mu.append(0) 

71 for k in range(n + 1): 

72 sgn_comb = (-1) ** (n - k) * comb(n, k, exact=True) 

73 mu[n] += sgn_comb * mnc[k] * mean ** (n - k) 

74 if wmean: 

75 mu[1] = mean 

76 return mu[1:] 

77 

78 res = np.apply_along_axis(_local_counts, 0, X) 

79 # for backward compatibility convert 1-dim output to list/tuple 

80 return _convert_from_multidim(res) 

81 

82 

83def cum2mc(kappa): 

84 """convert non-central moments to cumulants 

85 recursive formula produces as many cumulants as moments 

86 

87 References 

88 ---------- 

89 Kenneth Lange: Numerical Analysis for Statisticians, page 40 

90 """ 

91 X = _convert_to_multidim(kappa) 

92 

93 def _local_counts(kappa): 

94 mc = [1, 0.0] # _kappa[0]] #insert 0-moment and mean 

95 kappa0 = kappa[0] 

96 kappa = [1] + list(kappa) 

97 for nn, m in enumerate(kappa[2:]): 

98 n = nn + 2 

99 mc.append(0) 

100 for k in range(n - 1): 

101 mc[n] += comb(n - 1, k, exact=True) * kappa[n - k] * mc[k] 

102 mc[1] = kappa0 # insert mean as first moments by convention 

103 return mc[1:] 

104 

105 res = np.apply_along_axis(_local_counts, 0, X) 

106 # for backward compatibility convert 1-dim output to list/tuple 

107 return _convert_from_multidim(res) 

108 

109 

110def mnc2cum(mnc): 

111 """convert non-central moments to cumulants 

112 recursive formula produces as many cumulants as moments 

113 

114 https://en.wikipedia.org/wiki/Cumulant#Cumulants_and_moments 

115 """ 

116 X = _convert_to_multidim(mnc) 

117 

118 def _local_counts(mnc): 

119 mnc = [1] + list(mnc) 

120 kappa = [1] 

121 for nn, m in enumerate(mnc[1:]): 

122 n = nn + 1 

123 kappa.append(m) 

124 for k in range(1, n): 

125 num_ways = comb(n - 1, k - 1, exact=True) 

126 kappa[n] -= num_ways * kappa[k] * mnc[n - k] 

127 return kappa[1:] 

128 

129 res = np.apply_along_axis(_local_counts, 0, X) 

130 # for backward compatibility convert 1-dim output to list/tuple 

131 return _convert_from_multidim(res) 

132 

133 

134def mc2cum(mc): 

135 """ 

136 just chained because I have still the test case 

137 """ 

138 first_step = mc2mnc(mc) 

139 if isinstance(first_step, np.ndarray): 

140 first_step = first_step.T 

141 return mnc2cum(first_step) 

142 # return np.apply_along_axis(lambda x: mnc2cum(mc2mnc(x)), 0, mc) 

143 

144 

145def mvsk2mc(args): 

146 """convert mean, variance, skew, kurtosis to central moments""" 

147 X = _convert_to_multidim(args) 

148 

149 def _local_counts(args): 

150 mu, sig2, sk, kur = args 

151 cnt = [None] * 4 

152 cnt[0] = mu 

153 cnt[1] = sig2 

154 cnt[2] = sk * sig2 ** 1.5 

155 cnt[3] = (kur + 3.0) * sig2 ** 2.0 

156 return tuple(cnt) 

157 

158 res = np.apply_along_axis(_local_counts, 0, X) 

159 # for backward compatibility convert 1-dim output to list/tuple 

160 return _convert_from_multidim(res, tuple) 

161 

162 

163def mvsk2mnc(args): 

164 """convert mean, variance, skew, kurtosis to non-central moments""" 

165 X = _convert_to_multidim(args) 

166 

167 def _local_counts(args): 

168 mc, mc2, skew, kurt = args 

169 mnc = mc 

170 mnc2 = mc2 + mc * mc 

171 mc3 = skew * (mc2 ** 1.5) # 3rd central moment 

172 mnc3 = mc3 + 3 * mc * mc2 + mc ** 3 # 3rd non-central moment 

173 mc4 = (kurt + 3.0) * (mc2 ** 2.0) # 4th central moment 

174 mnc4 = mc4 + 4 * mc * mc3 + 6 * mc * mc * mc2 + mc ** 4 

175 return (mnc, mnc2, mnc3, mnc4) 

176 

177 res = np.apply_along_axis(_local_counts, 0, X) 

178 # for backward compatibility convert 1-dim output to list/tuple 

179 return _convert_from_multidim(res, tuple) 

180 

181 

182def mc2mvsk(args): 

183 """convert central moments to mean, variance, skew, kurtosis""" 

184 X = _convert_to_multidim(args) 

185 

186 def _local_counts(args): 

187 mc, mc2, mc3, mc4 = args 

188 skew = np.divide(mc3, mc2 ** 1.5) 

189 kurt = np.divide(mc4, mc2 ** 2.0) - 3.0 

190 return (mc, mc2, skew, kurt) 

191 

192 res = np.apply_along_axis(_local_counts, 0, X) 

193 # for backward compatibility convert 1-dim output to list/tuple 

194 return _convert_from_multidim(res, tuple) 

195 

196 

197def mnc2mvsk(args): 

198 """convert central moments to mean, variance, skew, kurtosis 

199 """ 

200 X = _convert_to_multidim(args) 

201 

202 def _local_counts(args): 

203 # convert four non-central moments to central moments 

204 mnc, mnc2, mnc3, mnc4 = args 

205 mc = mnc 

206 mc2 = mnc2 - mnc * mnc 

207 mc3 = mnc3 - (3 * mc * mc2 + mc ** 3) # 3rd central moment 

208 mc4 = mnc4 - (4 * mc * mc3 + 6 * mc * mc * mc2 + mc ** 4) 

209 return mc2mvsk((mc, mc2, mc3, mc4)) 

210 

211 res = np.apply_along_axis(_local_counts, 0, X) 

212 # for backward compatibility convert 1-dim output to list/tuple 

213 return _convert_from_multidim(res, tuple) 

214 

215# def mnc2mc(args): 

216# """convert four non-central moments to central moments 

217# """ 

218# mnc, mnc2, mnc3, mnc4 = args 

219# mc = mnc 

220# mc2 = mnc2 - mnc*mnc 

221# mc3 = mnc3 - (3*mc*mc2+mc**3) # 3rd central moment 

222# mc4 = mnc4 - (4*mc*mc3+6*mc*mc*mc2+mc**4) 

223# return mc, mc2, mc 

224 

225# TODO: no return, did it get lost in cut-paste? 

226 

227 

228def cov2corr(cov, return_std=False): 

229 """ 

230 convert covariance matrix to correlation matrix 

231 

232 Parameters 

233 ---------- 

234 cov : array_like, 2d 

235 covariance matrix, see Notes 

236 

237 Returns 

238 ------- 

239 corr : ndarray (subclass) 

240 correlation matrix 

241 return_std : bool 

242 If this is true then the standard deviation is also returned. 

243 By default only the correlation matrix is returned. 

244 

245 Notes 

246 ----- 

247 This function does not convert subclasses of ndarrays. This requires that 

248 division is defined elementwise. np.ma.array and np.matrix are allowed. 

249 """ 

250 cov = np.asanyarray(cov) 

251 std_ = np.sqrt(np.diag(cov)) 

252 corr = cov / np.outer(std_, std_) 

253 if return_std: 

254 return corr, std_ 

255 else: 

256 return corr 

257 

258 

259def corr2cov(corr, std): 

260 """ 

261 convert correlation matrix to covariance matrix given standard deviation 

262 

263 Parameters 

264 ---------- 

265 corr : array_like, 2d 

266 correlation matrix, see Notes 

267 std : array_like, 1d 

268 standard deviation 

269 

270 Returns 

271 ------- 

272 cov : ndarray (subclass) 

273 covariance matrix 

274 

275 Notes 

276 ----- 

277 This function does not convert subclasses of ndarrays. This requires 

278 that multiplication is defined elementwise. np.ma.array are allowed, but 

279 not matrices. 

280 """ 

281 corr = np.asanyarray(corr) 

282 std_ = np.asanyarray(std) 

283 cov = corr * np.outer(std_, std_) 

284 return cov 

285 

286 

287def se_cov(cov): 

288 """ 

289 get standard deviation from covariance matrix 

290 

291 just a shorthand function np.sqrt(np.diag(cov)) 

292 

293 Parameters 

294 ---------- 

295 cov : array_like, square 

296 covariance matrix 

297 

298 Returns 

299 ------- 

300 std : ndarray 

301 standard deviation from diagonal of cov 

302 """ 

303 return np.sqrt(np.diag(cov))