2010-04-15 7 views
0

J'ai une matrice m x n où chaque ligne est constituée de zéros et de valeurs identiques pour chaque ligne.meilleure façon d'obtenir un vecteur à partir d'une matrice clairsemée

un exemple serait:

M = [-0.6 1.8 -2.3 0 0 0; 0 0 0 3.4 -3.8 -4.3; -0.6 0 0 3.4 0 0] 

Dans cet exemple, la première colonne est constituée de 0 s et -0.6, deuxième 0 et 1.8, troisième -2.3 et ainsi de suite.

Dans ce cas, je voudrais réduire m à 1 (obtenir un vecteur d'une matrice donnée) si dans cet exemple un vecteur serait [-0.6 1.8 -2.3 3.4 -3.8 -4.3]

Est-ce que quelqu'un sait quelle est la meilleure façon d'obtenir un vecteur de une telle matrice?

Merci!

+0

@niko: Je vous suggère d'expliquer plus clairement ce que votre objectif était exact, puisque vous la question peut être interprétée différemment. J'aimerais savoir si je dois commencer à m'excuser. – Jonas

Répondre

1

Voilà une seule ligne qui utilise la fonction SUM:

nonZeroColumnValues = sum(M)./sum(M ~= 0); 

Ceci renvoie un vecteur 1-par-n qui contient la valeur non nulle répétée à partir de chaque colonne. Il le fait en additionnant chaque colonne, puis en divisant le résultat par le nombre de valeurs non nulles dans chaque colonne. S'il n'y a pas de valeurs non nulles dans une colonne, le résultat pour cette colonne sera NaN.

Voici un exemple en utilisant la matrice de l'échantillon M dans la question:

>> M = [-0.6 1.8 -2.3 0 0 0; 0 0 0 3.4 -3.8 -4.3; -0.6 0 0 3.4 0 0] 

M = 

    -0.6000 1.8000 -2.3000   0   0   0 
     0   0   0 3.4000 -3.8000 -4.3000 
    -0.6000   0   0 3.4000   0   0 

>> nonZeroColumnValues = sum(M)./sum(M ~= 0) 

nonZeroColumnValues = 

    -0.6000 1.8000 -2.3000 3.4000 -3.8000 -4.3000 
+0

Comment "non-idiomatique"! Mais encore plus court et plus intelligent que ma version. +1 – Jonas

0

M = M(M~=0)

ou

M(find(M))

et s'il vous plaît apprendre comment formater le code pour les lecteurs SO.

EDIT @Jonas suggère que l'OP veut qu'une seule occurrence de chaque élément non nul de M. Pour cet essai d'emballage ou l'autre des suggestions ci-dessus dans unique(), tels que

unique(M(M~=0)) 
0

Ce n'est pas en fait une matrice éparse. Une matrice clairsemée dans MATLAB est définie comme telle. Si vous utilisez les fonctions sparse ou spdiags pour définir cette matrice, les éléments zéro n'auront pas besoin d'être stockés, mais uniquement les non-zéros. Bien sûr, MATLAB sait comment travailler avec ces vraies matrices creuses en conjonction avec d'autres doubles matrices standard. Enfin, les vraies matrices éparses sont généralement beaucoup plus clairsemées que celles-ci, ou vous ne vous soucieriez pas d'utiliser la forme de stockage clairsemée.

Peu importe, si vous ne souhaitez que les éléments non nuls de toute matrice, vous pouvez le faire:

NZ = M(M ~= 0); 

alternativement,

NZ = M(find(M)); 

Soit sera chaîne les non-zéros par colonnes, car c'est ainsi que les nombres sont stockés dans une matrice dans MATLAB.

NZ = M(find(M)) 
NZ = 
     -0.6 
     -0.6 
      1.8 
     -2.3 
      3.4 
      3.4 
     -3.8 
     -4.3 

Dans votre question, vous avez demandé comment faire en lignes, extraire les éléments non nuls dans la première rangée, puis la deuxième rangée, etc.

Ceci est le plus simplement fait en transposant le tableau en premier. Ainsi, nous pourrions faire quelque chose comme ...

NZ = M.'; 
NZ = NZ(find(NZ)) 
NZ = 
     -0.6 
      1.8 
     -2.3 
      3.4 
     -3.8 
     -4.3 
     -0.6 
      3.4 

Voir que j'ai utilisé. ' faire la transposition, juste au cas où les éléments seraient complexes.

+1

Si je comprends bien la question, ce n'est pas ce que cherche @niko. – Jonas

+0

Comment n'est-ce pas ce que niko cherchait? Ceci renvoie un vecteur avec les éléments non nuls, EXACTEMENT dans l'ordre tel que demandé. La seule différence est que je n'ai pas transposé le résultat dans un vecteur ligne. Mais seul un "vecteur" a été demandé. Si le PO veut vraiment un vecteur ligne, alors. va le transposer en un. Si le PO a un autre schéma vague qui est impliqué par cette question, alors il doit rendre la question claire, beaucoup plus claire qu'elle ne l'est maintenant. –

1

S'il existe un nombre inconnu de non-zéros et de zéros, un moyen de résoudre le problème consiste à remplacer les zéros par des NaN, puis d'utiliser quelque chose comme max ou min pour trouver les données.

%# create an array 
M = [-0.6 1.8 -2.3 0 0 0; 0 0 0 3.4 -3.8 -4.3; -0.6 0 0 3.4 0 0]; 

%# replace zeros with NaN 
M(M==0) = NaN; 

%# get, for each column, the number 
numbers = max(M,[],1) 

numbers = 

    -0.6000 1.8000 -2.3000 3.4000 -3.8000 -4.3000 

EDIT

Voilà comment je compris la question. « Je veux, pour chaque colonne, de connaître la valeur des entrées non nulles Il n'y a qu'un nombre non nul par colonne, mais il pourrait se produire plusieurs fois »

Voici un plus de Matlab (mais plus) façon d'obtenir la solution:

%# create an array 
    M = [-0.6 1.8 -2.3 0 0 0; 0 0 0 3.4 -3.8 -4.3; -0.6 0 0 3.4 0 0]; 

%# find the non-zero entries 
[r,c] = find(M); 

%# only take one entry per column 
[uniqueCols, sortIdx] = unique(c); 

%# fix the rows correspondingly 
uniqueRows = r(sortIdx); 

%# convert to index 
idx = sub2ind(size(M),uniqueRows,uniqueCols); 

%# get the numbers per column (transpose as needed) 
numbers = M(idx) 

numbers = 

    -0.6000 
    1.8000 
    -2.3000 
    3.4000 
    -3.8000 
    -4.3000 
+0

C'est une façon très alambiquée de faire quelque chose pour lequel il y a des idiomes naturels de Matlab! –

+0

@High Performance Mark: Votre solution et @woodchips trouve plusieurs versions des valeurs numériques, ce qui n'est pas ce que le PO veut pour autant que je sache. Je ne pense pas qu'il existe une version beaucoup moins compliquée. Vous pourriez éventuellement lancer find avec deux sorties et ne prendre qu'une valeur numérique par ligne, mais cela impliquerait plus de dactylographie que cela. – Jonas

+0

@Jonas: voir ma modification ci-dessus. Je pense toujours que votre approche est unidiomatique et trop compliquée. –

0

Si l'OP veut VRAIMENT trouver les éléments non-zéro qui sont aussi uniques, alors il y a de bien meilleurs moyens de le faire que Jonas ne le suggère.

La solution logique consiste à trouver les éléments non-zéro FIRST. Ensuite, appliquez la fonction unique. Donc, faites ceci:

unique(M(find(M))) 

Si votre objectif est de trouver ces éléments dans un ordre spécifique, cet ordre doit être explicitement défini dans votre objectif.

+0

Je pense que la solution qu'il fournit est l'objectif. – Jonas

+0

Enfin, nous sommes tous les trois d'accord! –

+1

En fait, nous ne le faisons pas, car je pense que la commande est importante :). – Jonas