2017-08-11 2 views
3

Je voudrais remplacer les premières valeurs x dans chaque ligne de mon tableau a avec celles et conserver toutes les autres valeurs NaN . Les premières valeurs x changent cependant dans chaque ligne et sont déterminées par une liste b.python Comment remplacer les premières valeurs f (x) de chaque x dans le tableau (x, n)

Depuis que je ne suis pas très familier avec les tableaux que je pensais que je pourrais le faire avec une boucle comme indiqué ci-dessous, mais cela ne fonctionne pas (j'ai inspiration pour les bases de remplacement dans des tableaux de How to set first N elements of array to zero?) .

In: 
a = np.empty((3,4)) 
a.fill(np.nan) 
b = [2,3,1] 

for i in range(b): 
    a[0:b[i]] = [1] * b[i] 
    a[i:] = np.ones((b[i])) 
pass 

Out: 
line 7: 
ValueError: could not broadcast input array from shape (2) into shape (2,4) 

Résultat devrait ressembler:

Out: 
[[1, 1, nan, nan], 
[1, 1, 1, nan], 
[1, nan, nan, nan]] 
+1

Lorsque vous postez un code comme celui-ci, vous devriez en dire plus que «ça ne marche pas». Ce qui était faux? Quel genre d'erreur? Un tweak mineur le fait fonctionner: 'pour i dans la gamme (3): a [i, 0: b [i]] = 1' Vous n'avez pas appliqué complètement la réponse liée. – hpaulj

+0

@hpaulj Vous avez raison, je l'ai ajouté maintenant pour l'exhaustivité. Si j'utilise votre tweak une erreur provoquée par la dernière ligne apparaît '(ValueError: impossible de diffuser le tableau d'entrée de forme (2) en forme (3,4))'. Si je supprime cette ligne, tout va bien! –

+0

@hpaulj mon mauvais, ça ne marche pas. L'ensemble du tableau est rempli de ceux. Cependant votre solution avec enumerate fonctionne parfaitement –

Répondre

2

Dans la réponse liée, How to set first N elements of array to zero?

la solution pour les tableaux est

y = numpy.array(x) 
y[0:n] = 0 

Dans d'autres mots si nous remplissons une tranche (gamme d'indices) avec le même nombre, nous pouvons spécifier un scalaire. Il peut s'agir d'un tableau de la même taille, par ex. np.ones(n). Mais ça ne doit pas être.

donc nous avons juste besoin d'itérer sur les lignes de a (et des éléments de b) et effectuer cette mission indexée

In [368]: a = np.ones((3,4))*np.nan 
In [369]: for i in range(3): 
    ...:  a[i,:b[i]] = 1 
    ...:  
In [370]: a 
Out[370]: 
array([[ 1., 1., nan, nan], 
     [ 1., 1., 1., nan], 
     [ 1., nan, nan, nan]]) 

Il existe différentes façons de « remplissage » du tableau original avec nan.np.full fait un np.empty suivi d'un copyto. Une variante de l'itération de ligne est for i,n in enumerate(a):.

Un autre bon moyen d'itération dans un sens coordonné est avec zip.

In [371]: for i,x in zip(b,a): 
    ...:  x[:i] = 1 

Ceci profite du fait que l'itération sur un tableau 2d itère sur ses lignes. Donc, x est une vue 1d de a et peut être modifié sur place.

Mais avec un peu de tricherie d'indexation, nous n'avons même pas à boucler.

In [373]: a = np.full((3,4),np.nan) 

In [375]: mask = np.array(b)[:,None]>np.arange(4) 
In [376]: mask 
Out[376]: 
array([[ True, True, False, False], 
     [ True, True, True, False], 
     [ True, False, False, False]], dtype=bool) 
In [377]: a[mask] = 1 
In [378]: a 
Out[378]: 
array([[ 1., 1., nan, nan], 
     [ 1., 1., 1., nan], 
     [ 1., nan, nan, nan]]) 

Ceci est un favori de l'une des meilleures affiches numpy, @Divakar.

Numpy: Fix array with rows of different lengths by filling the empty elements with zeros

Il peut être utilisé pour pad une liste de listes. En parlant de rembourrage, itertools a un outil pratique, zip_longest (nom AP3)

In [380]: np.array(list(itertools.zip_longest(*[np.ones(x).tolist() for x in b],fillvalue=np.nan))).T 
Out[380]: 
array([[ 1., 1., nan], 
     [ 1., 1., 1.], 
     [ 1., nan, nan]]) 

Votre question aurait dû préciser ce qui était erroné; quels types d'erreurs que vous avez:

for i in w2: 
    a[0:b[i]] = [1] * b[i] 
    a[i:] = np.ones((b[i])) 

w2 est indéterminée, mais est probablement range(3).

a[0:b[i]] est erroné car il spécifie toutes les lignes, où que vous travaillez sur un seul à la fois. a[i:] spécifie également une plage de lignes.

+0

Bonne réponse!Je suppose que la solution impliquant des masques est la plus rapide. La ligne 'mask = np.array (b) [:, None]> np.arange (4)' est un pur génie :) –

+0

Merci beaucoup, belle explication :) Pour l'exhaustivité je vais remplacer w2 et écrire le les erreurs que j'ai eues. –

2

Vous pouvez le faire via une boucle. Initialisez un tableau de valeurs nan puis parcourez la liste des premiers n et définissez les valeurs sur 1 en fonction de n pour chaque ligne.

a = np.full((3, 4), np.nan) 
b = [2, 3, 1] 
for i, x in enumerate(b): 
    a[i, :x] = 1 
+3

Vous pouvez utiliser ['numpy.full'] (https://docs.scipy.org/doc/numpy/reference/generated/numpy.full.html#numpy-full) pour init votre matrice avec des valeurs 'np.NAN' plutôt que des zéros. 'a = np.full ((3, 4), np.NAN)' Sinon belle solution! –

+0

Est-ce important si je commence par rendre mon tableau tout NaN, en omettant ainsi votre dernière ligne, par rapport à les faire Zéro en premier et que (avec votre dernière ligne) faire tous les restes zéro? Peut-être la vitesse? –

+1

@ SVerhoef, surtout ** lisibilité **, imo plus important que la vitesse parfois. –

0
import numpy as np 
a = np.random.rand(3,4) #Create matrix with random numbers (you can change this to np.empty or whatever you want. 
b = [1, 2, 3] # Your 'b' list 
for idr, row in enumerate(a): # Loop through the matrix by row 
    a[idr,:b[idr]] = 1 # idr is the row index, here you change the row 'idr' from the column 0 to the column b[idr] that will be 0, 1 and 3 
    a[idr,b[idr]:] = 'NaN' # the values after that receive NaN 
print(a) # Outputs matrix 
#[[ 1. nan nan nan] 
[ 1. 1. nan nan] 
[ 1. 1. 1. nan]] 
+0

Ceci est un doublon trop complexe d'une réponse déjà postée –

+0

La réponse a été postée il y a 13 minutes, je ne peux pas accepter les réponses en double des choses déjà réglées mais quand j'ai commencé à le faire, l'autre réponse n'était même pas encore postée. Je viens de le voir maintenant. –

1

Vous pouvez vous initialiser matrice en utilisant une compréhension de liste:

>>> import numpy as np 
>>> b = [2, 3, 1] 
>>> max_len = 4 
>>> gen_array = lambda i: [1] * i + [np.NAN] * (max_len - i) 
>>> np.matrix([gen_array(i) for i in b]) 

Avec les étapes détaillées:

[1] * N créerons un tableau de longueur N rempli de 1:

>>> [1] * 3 
[1, 1, 1] 

Vous pouvez tableau concaténer en utilisant +:

>>> [1, 2] + [3, 4] 
[1, 2, 3, 4] 

Il vous suffit de combiner les deux [1] * X + [np.NAN] * (N - X) va créer un tableau de N dimension remplie de X1

dernier, liste-compréhension:

[i for i in b]

est un "raccourci" (pas vraiment, mais il est plus facile à comprendre) pour:

a = [] 
for i in b: 
    a.append(i)