2011-11-02 5 views
1

Je ne suis pas très à l'aise avec l'utilisation de la fonction accumarray dans Matlab, même si j'ai commencé à apprécier ses puissances! Je me demandais si je pouvais entrer 2 cols dans le champ VAL de la fonction accumarray. S'il vous plaît voir -2 colonnes dans VAL field d'accumarray - Matlab

sz = 3 ; % num_rows for each ID 
mat1 = [1 20 ; 1 40 ; 1 50 ; 2 10 ; 2 100 ; 2 110] ; % Col1 is ID, Col2 is Value 
idx = [30 1000 ; 30 1200 ; 30 1500 ; 30 1000 ; 30 1200 ; 30 1500 ] ; 
% col1: index ID, col2: value 

mat1 est l'ID retourne tandis que idx est l'indice renvoie. Pour plus de simplicité, les retours d'idx sont répétés pour correspondre à mat1. Tous les ID de mat1 ont les mêmes lignes. Même idx a les mêmes lignes.

[~,~,n] = unique(mat1(:,1), 'rows', 'last') ; 
fncovariance = @(x,y) (x.*y)/sz ; 
accumarray(n, [x(:,2) y(:,2)], [], fncovariance) % --> FAILS as VAL is not-vector! 

Vous pouvez voir que je suis en train de calculer covariance (cov (x, y, 1)) mais ne peut pas utiliser la fonction de Matlab directement mat1 a ID et j'ai besoin covariance pour chaque ID w.r.t Index.

Ansmat:

1 2444.4 
    2 7888.9 
+0

Quels sont 'x' et' y' dans votre dernière ligne de code? Voulez-vous dire «mat1» et «idx»? –

+0

@John oui. Mais je faisais juste référence à la fonction intégrée de matlab. Pour moi, mat1 a beaucoup d'identifiants et y a des indices (disons NYSE). Donc un simple cov (x, y, 1) serait inutile. Merci. – Maddy

Répondre

0

La réponse courte est non. Dans le accumarray() aide, la partie clé est:

« VAL doit être numérique, logique ou vecteur de caractère avec la même longueur que le nombre de lignes dans SUBS VAL peut aussi être un scalaire dont la valeur. est répété pour toutes les lignes de SUBS. "

Cela signifie que vous ne pouvez même pas faire semblant en utilisant des cellules. Toutefois, si vous placez les ID dans leur propre variable d'index, puis remodelez vos données afin que les données correspondant aux ID différents se trouvent dans des colonnes différentes, ce problème peut être efficacement traité par bsxfun(). Pour référence, j'ai également inclus une méthode mathématique matricielle, une simple méthode de boucle for utilisant cov(), et une méthode cellfun() utilisant une fonction personnalisée fncovariance() (notez que je l'ai modifiée ci-dessus).

fncovariance = @(x,y) mean(x.*y) - mean(x)*mean(y); 

IDs = unique(mat1(:,1)); 
ret = reshape(mat1(:,2), sz, length(IDs)); 
idx = idx(1:sz, 2); 
% bsxfun method 
mean(bsxfun(@times, ret, idx)) - bsxfun(@times, mean(ret), mean(idx)) 
% matrix math 
idx' * ret/length(idx) - mean(ret)*mean(idx) 
% for loop method 
id_cov = zeros(1, length(IDs)); 
for i=1:length(IDs) 
    tmp = cov(ret(:,i), idx, 1); 
    id_cov(i) = tmp(2,1); 
end 
id_cov 
% cellfun method 
ret_cell = num2cell(ret, 1); 
idx_cell = num2cell(repmat(idx, 1, length(IDs)), 1); 
cellfun(fncovariance, ret_cell, idx_cell) 

Si vous simulez des données supplémentaires et du temps ces différentes méthodes, la façon dont bsxfun() est le plus rapide:

sz = 10; 
n_ids = 100; 

IDs = 1:n_ids; 
ret = randi(1000, sz, n_ids); 
idx = randi(1000, sz, 1); 
Elapsed time is 0.001292 seconds. 
Elapsed time is 0.001523 seconds. 
Elapsed time is 0.009625 seconds. 
Elapsed time is 0.011454 seconds. 

Une dernière option qui pourrait vous intéresser est la fonction grpstats() dans la boîte à outils des statistiques, qui vous permet de balayer des statistiques arbitraires basées sur une variable de regroupement.