91 votes

Comment copier des données d'un tableau numpy vers un autre tableau numpy ?

Quel est le moyen le plus rapide de copier des données du tableau b vers le tableau a, sans modifier l'adresse du tableau a. J'en ai besoin parce qu'une bibliothèque externe (PyFFTW) utilise un pointeur sur mon tableau qui ne peut pas changer.

Par exemple :

a = numpy.empty(n, dtype=complex)
for i in xrange(a.size):
  a[i] = b[i]

Est-il possible de le faire sans boucle ?

90voto

Brian Hawkins Points 1037

Je crois

a = numpy.empty_like(b)
a[:] = b

copiera rapidement les valeurs. Comme le mentionne Funsi, les versions récentes de numpy disposent également de la fonction copyto fonction.

4 votes

+1. Mais ne serait-ce pas numpy.empty est sensiblement plus rapide que numpy.zeros ?

0 votes

Je me demande quelle est la différence entre a[:] = b y a = b ?

9 votes

@M.ElSaka a = b crée simplement une nouvelle référence à b . a[:] = b signifie "mettre tous les éléments de a égales à celles de b ". La différence est importante car les tableaux numpy sont des types mutables.

29voto

Funsi Points 151

La version 1.7 de NumPy dispose de la fonction numpy.copyto qui fait ce que vous recherchez :

numpy.copyto(dst, src)

Copie les valeurs d'un tableau dans un autre, en les diffusant si nécessaire.

Voir : https://docs.scipy.org/doc/numpy/reference/generated/numpy.copyto.html

0 votes

Cela ne fonctionne pas pour moi. J'obtiens AttributeError: 'module' object has no attribute 'copyto'

21voto

Benor Points 11
a = numpy.array(b)

est encore plus rapide que les solutions proposées jusqu'à numpy v1.6 et fait également une copie du tableau. Je n'ai cependant pas pu la tester contre copyto(a,b), car je n'ai pas la version la plus récente de numpy.

0 votes

C'est une excellente façon de copier un tableau, mais cela crée un nouvel objet. Le PO a besoin de savoir comment assigner rapidement des valeurs à un tableau qui a déjà été créé.

18voto

mab Points 1191

Pour répondre à votre question, j'ai joué avec quelques variantes et j'en ai dressé le profil.

Conclusion : pour copier des données d'un tableau numpy vers un autre, utilisez l'une des fonctions numpy intégrées. numpy.array(src) o numpy.copyto(dst, src) dans la mesure du possible.

Mise à jour 2022-05 : un nouveau test avec numpy v1.22 et CPython v3.9 a montré que src.astype(...) est actuellement le plus rapide sur mon système. Il est donc préférable d'exécuter vous-même le code fourni pour obtenir des chiffres correspondant à votre configuration spécifique.

(Mais choisissez toujours numpy.copyto(dst, src) si dst est déjà allouée, afin de réutiliser la mémoire. Voir le profilage à la fin du billet).

configuration du profilage

import timeit
import numpy as np
import pandas as pd
from IPython.display import display

def profile_this(methods, setup='', niter=10 ** 4, p_globals=None, **kwargs):
    if p_globals is not None:
        print('globals: {0}, tested {1:.0e} times'.format(p_globals, niter))
    timings = np.array([timeit.timeit(method, setup=setup, number=niter,
                                      globals=p_globals, **kwargs) for 
                        method in methods])
    ranking = np.argsort(timings)
    timings = np.array(timings)[ranking]
    methods = np.array(methods)[ranking]
    speedups = np.amax(timings) / timings

    # pd.set_option('html', False)
    data = {'time (s)': timings,
            'speedup': ['{:.2f}x'.format(s) if s != 1 else '' for s in speedups],
            'methods': methods}
    data_frame = pd.DataFrame(data, columns=['time (s)', 'speedup', 'methods'])

    display(data_frame)
    print()

code de profilage

setup = '''import numpy as np; x = np.random.random(n)'''
methods = (
    '''y = np.zeros(n, dtype=x.dtype); y[:] = x''',
    '''y = np.zeros_like(x); y[:] = x''',
    '''y = np.empty(n, dtype=x.dtype); y[:] = x''',
    '''y = np.empty_like(x); y[:] = x''',
    '''y = np.copy(x)''',
    '''y = x.astype(x.dtype)''',
    '''y = 1*x''',
    '''y = np.empty_like(x); np.copyto(y, x)''',
    '''y = np.empty_like(x); np.copyto(y, x, casting='no')''',
    '''y = np.empty(n)\nfor i in range(x.size):\n\ty[i] = x[i]'''
)

for n, it in ((2, 6), (3, 6), (3.8, 6), (4, 6), (5, 5), (6, 4.5)):
    profile_this(methods[:-1:] if n > 2 else methods, setup, 
                 niter=int(10 ** it), p_globals={'n': int(10 ** n)})

résultats pour Windows 7 sur Intel i7 CPU, CPython v3.5.0, numpy v1.10.1.

globals: {'n': 100}, tested 1e+06 times

     time (s) speedup                                            methods
0    0.386908  33.76x                                    y = np.array(x)
1    0.496475  26.31x                              y = x.astype(x.dtype)
2    0.567027  23.03x              y = np.empty_like(x); np.copyto(y, x)
3    0.666129  19.61x                     y = np.empty_like(x); y[:] = x
4    0.967086  13.51x                                            y = 1*x
5    1.067240  12.24x  y = np.empty_like(x); np.copyto(y, x, casting=...
6    1.235198  10.57x                                     y = np.copy(x)
7    1.624535   8.04x           y = np.zeros(n, dtype=x.dtype); y[:] = x
8    1.626120   8.03x           y = np.empty(n, dtype=x.dtype); y[:] = x
9    3.569372   3.66x                     y = np.zeros_like(x); y[:] = x
10  13.061154          y = np.empty(n)\nfor i in range(x.size):\n\ty[...

globals: {'n': 1000}, tested 1e+06 times

   time (s) speedup                                            methods
0  0.666237   6.10x                              y = x.astype(x.dtype)
1  0.740594   5.49x              y = np.empty_like(x); np.copyto(y, x)
2  0.755246   5.39x                                    y = np.array(x)
3  1.043631   3.90x                     y = np.empty_like(x); y[:] = x
4  1.398793   2.91x                                            y = 1*x
5  1.434299   2.84x  y = np.empty_like(x); np.copyto(y, x, casting=...
6  1.544769   2.63x                                     y = np.copy(x)
7  1.873119   2.17x           y = np.empty(n, dtype=x.dtype); y[:] = x
8  2.355593   1.73x           y = np.zeros(n, dtype=x.dtype); y[:] = x
9  4.067133                             y = np.zeros_like(x); y[:] = x

globals: {'n': 6309}, tested 1e+06 times

   time (s) speedup                                            methods
0  2.338428   3.05x                                    y = np.array(x)
1  2.466636   2.89x                              y = x.astype(x.dtype)
2  2.561535   2.78x              y = np.empty_like(x); np.copyto(y, x)
3  2.603601   2.74x                     y = np.empty_like(x); y[:] = x
4  3.005610   2.37x  y = np.empty_like(x); np.copyto(y, x, casting=...
5  3.215863   2.22x                                     y = np.copy(x)
6  3.249763   2.19x                                            y = 1*x
7  3.661599   1.95x           y = np.empty(n, dtype=x.dtype); y[:] = x
8  6.344077   1.12x           y = np.zeros(n, dtype=x.dtype); y[:] = x
9  7.133050                             y = np.zeros_like(x); y[:] = x

globals: {'n': 10000}, tested 1e+06 times

   time (s) speedup                                            methods
0  3.421806   2.82x                                    y = np.array(x)
1  3.569501   2.71x                              y = x.astype(x.dtype)
2  3.618747   2.67x              y = np.empty_like(x); np.copyto(y, x)
3  3.708604   2.61x                     y = np.empty_like(x); y[:] = x
4  4.150505   2.33x  y = np.empty_like(x); np.copyto(y, x, casting=...
5  4.402126   2.19x                                     y = np.copy(x)
6  4.917966   1.96x           y = np.empty(n, dtype=x.dtype); y[:] = x
7  4.941269   1.96x                                            y = 1*x
8  8.925884   1.08x           y = np.zeros(n, dtype=x.dtype); y[:] = x
9  9.661437                             y = np.zeros_like(x); y[:] = x

globals: {'n': 100000}, tested 1e+05 times

    time (s) speedup                                            methods
0   3.858588   2.63x                              y = x.astype(x.dtype)
1   3.873989   2.62x                                    y = np.array(x)
2   3.896584   2.60x              y = np.empty_like(x); np.copyto(y, x)
3   3.919729   2.58x  y = np.empty_like(x); np.copyto(y, x, casting=...
4   3.948563   2.57x                     y = np.empty_like(x); y[:] = x
5   4.000521   2.53x                                     y = np.copy(x)
6   4.087255   2.48x           y = np.empty(n, dtype=x.dtype); y[:] = x
7   4.803606   2.11x                                            y = 1*x
8   6.723291   1.51x                     y = np.zeros_like(x); y[:] = x
9  10.131983                   y = np.zeros(n, dtype=x.dtype); y[:] = x

globals: {'n': 1000000}, tested 3e+04 times

     time (s) speedup                                            methods
0   85.625484   1.24x                     y = np.empty_like(x); y[:] = x
1   85.693316   1.24x              y = np.empty_like(x); np.copyto(y, x)
2   85.790064   1.24x  y = np.empty_like(x); np.copyto(y, x, casting=...
3   86.342230   1.23x           y = np.empty(n, dtype=x.dtype); y[:] = x
4   86.954862   1.22x           y = np.zeros(n, dtype=x.dtype); y[:] = x
5   89.503368   1.18x                                    y = np.array(x)
6   91.986177   1.15x                                            y = 1*x
7   95.216021   1.11x                                     y = np.copy(x)
8  100.524358   1.05x                              y = x.astype(x.dtype)
9  106.045746                             y = np.zeros_like(x); y[:] = x

Voir également les résultats pour une variante du profilage où la mémoire de la destination est déjà pré-affecté lors de la copie des valeurs, puisque y = np.empty_like(x) fait partie de la configuration :

globals: {'n': 100}, tested 1e+06 times

   time (s) speedup                        methods
0  0.328492   2.33x                np.copyto(y, x)
1  0.384043   1.99x                y = np.array(x)
2  0.405529   1.89x                       y[:] = x
3  0.764625          np.copyto(y, x, casting='no')

globals: {'n': 1000}, tested 1e+06 times

   time (s) speedup                        methods
0  0.453094   1.95x                np.copyto(y, x)
1  0.537594   1.64x                       y[:] = x
2  0.770695   1.15x                y = np.array(x)
3  0.884261          np.copyto(y, x, casting='no')

globals: {'n': 6309}, tested 1e+06 times

   time (s) speedup                        methods
0  2.125426   1.20x                np.copyto(y, x)
1  2.182111   1.17x                       y[:] = x
2  2.364018   1.08x                y = np.array(x)
3  2.553323          np.copyto(y, x, casting='no')

globals: {'n': 10000}, tested 1e+06 times

   time (s) speedup                        methods
0  3.196402   1.13x                np.copyto(y, x)
1  3.523396   1.02x                       y[:] = x
2  3.531007   1.02x                y = np.array(x)
3  3.597598          np.copyto(y, x, casting='no')

globals: {'n': 100000}, tested 1e+05 times

   time (s) speedup                        methods
0  3.862123   1.01x                np.copyto(y, x)
1  3.863693   1.01x                y = np.array(x)
2  3.873194   1.01x                       y[:] = x
3  3.909018          np.copyto(y, x, casting='no')

10voto

PateToni Points 361

Vous pouvez facilement l'utiliser :

b = 1*a

C'est le moyen le plus rapide, mais il pose aussi quelques problèmes. Si vous ne définissez pas directement l'élément dtype de a et ne vérifie pas non plus le dtype de b vous risquez d'avoir des ennuis. Par exemple :

a = np.arange(10)        # dtype = int64
b = 1*a                  # dtype = int64

a = np.arange(10.)       # dtype = float64
b = 1*a                  # dtype = float64

a = np.arange(10)        # dtype = int64
b = 1. * a               # dtype = float64

J'espère avoir été clair. Parfois, il suffit d'une petite opération pour que le type de données change.

1 votes

Non. Cela crée un nouveau tableau. Cela équivaut à b = a.copy().

0 votes

Désolé, mais je ne vous comprends pas. Que voulez-vous dire par créer un nouveau tableau ? Toutes les autres méthodes présentées ici ont le même comportement. a = numpy.zeros(len(b)) o a = numpy.empty(n,dtype=complex) créera également un nouveau tableau.

2 votes

Supposons que vous ayez a = numpy.empty(1000) . Maintenant, vous devez remplir a avec des données, sans changer son adresse en mémoire. Si vous faites a[0] = 1, vous ne recréez pas un tableau, vous changez juste son contenu.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X