31 Stimmen

Wie man eine Ansicht mehrerer Spalten in einem strukturierten Numpy-Array zurückgibt

Ich kann mehrere Spalten (fields) gleichzeitig in einem strukturierten numpy Array sehen, indem ich mit einer Liste der Feldnamen indiziere, zum Beispiel

import numpy as np

a = np.array([(1.5, 2.5, (1.0,2.0)), (3.,4.,(4.,5.)), (1.,3.,(2.,6.))],
        dtype=[('x',float), ('y',float), ('value',float,(2,2))])

print a[['x','y']]
#[(1.5, 2.5) (3.0, 4.0) (1.0, 3.0)]

print a[['x','y']].dtype
#[('x', '

``Aber das Problem ist, dass es anscheinend eine Kopie und keine Ansicht zu sein scheint:

b = a[['x','y']]
b[0] = (9.,9.)

print b
#[(9.0, 9.0) (3.0, 4.0) (1.0, 3.0)]

print a[['x','y']]
#[(1.5, 2.5) (3.0, 4.0) (1.0, 3.0)]

Wenn ich nur eine Spalte auswähle, ist es eine Ansicht:

c = x['y']
c[0] = 99.

print c
#[ 99.  4.   3. ]

print a['y']
#[ 99.  4.   3. ]

Gibt es einen Weg, um das Ansichtsverhalten für mehr als eine Spalte gleichzeitig zu erhalten?

Ich habe zwei Workarounds, einen ist einfach durch die Spalten zu iterieren, der andere ist die Erstellung eines hierarchischen dtype, sodass die eine Spalte tatsächlich ein strukturiertes Array mit den beiden (oder mehr) Feldern zurückgibt, die ich möchte. Leider gibt auch zip eine Kopie zurück, also kann ich nicht folgendes tun:

x = a['x']; y = a['y']
z = zip(x,y)
z[0] = (9.,9.)``

37voto

HYRY Punkte 89513

Sie können ein dtype-Objekt erstellen, das nur die Felder enthält, die Sie möchten, und numpy.ndarray() verwenden, um eine Ansicht des Originalarrays zu erstellen:

import numpy as np
strc = np.zeros(3, dtype=[('x', int), ('y', float), ('z', int), ('t', "i8")])

def fields_view(arr, fields):
    dtype2 = np.dtype({name:arr.dtype.fields[name] for name in fields})
    return np.ndarray(arr.shape, dtype2, arr, 0, arr.strides)

v1 = fields_view(strc, ["x", "z"])
v1[0] = 10, 100

v2 = fields_view(strc, ["y", "z"])
v2[1:] = [(3.14, 7)]

v3 = fields_view(strc, ["x", "t"])

v3[1:] = [(1000, 2**16)]

print(strc)

Hier ist die Ausgabe:

[(10, 0.0, 100, 0L) (1000, 3.14, 7, 65536L) (1000, 3.14, 7, 65536L)]

11voto

ChristopherC Punkte 1555

Als Ergänzung zu @HYRYs Antwort könnten Sie auch ndarray's Methode getfield verwenden:

def fields_view(array, fields):
    return array.getfield(numpy.dtype(
        {name: array.dtype.fields[name] for name in fields}
    ))

7voto

Anders Lindstrom Punkte 185

Ab der Numpy-Version 1.16 wird der von Ihnen vorgeschlagene Code tatsächlich eine Ansicht zurückgeben. Weitere Informationen finden Sie auf dieser Seite unter 'NumPy 1.16.0 Release Notes->Zukünftige Änderungen->Mehrfachfeldansichten geben eine Ansicht zurück anstelle einer Kopie':

https://numpy.org/doc/stable/release/1.16.0-notes.html#multi-field-views-return-a-view-instead-of-a-copy

5voto

Jaime Punkte 62475

Ich glaube nicht, dass es einen einfachen Weg gibt, um das zu erreichen, was du willst. Im Allgemeinen kannst du keinen beliebigen Blick in ein Array werfen. Versuche Folgendes:

>>> a
array([(1.5, 2.5, [[1.0, 2.0], [1.0, 2.0]]),
       (3.0, 4.0, [[4.0, 5.0], [4.0, 5.0]]),
       (1.0, 3.0, [[2.0, 6.0], [2.0, 6.0]])], 
      dtype=[('x', '>> a.view(float)
array([ 1.5,  2.5,  1. ,  2. ,  1. ,  2. ,  3. ,  4. ,  4. ,  5. ,  4. ,
        5. ,  1. ,  3. ,  2. ,  6. ,  2. ,  6. ])

Die Ansicht des Fließkommabereichs zeigt dir, wie die tatsächlichen Daten im Speicher gespeichert sind. Ein Blick auf diese Daten muss als Kombination aus Form, Schritten und Offsets in den obigen Daten ausdrückbar sein. Wenn du beispielsweise nur einen Blick auf 'x' und 'y' haben möchtest, könntest du Folgendes tun:

>>> from numpy.lib.stride_tricks import as_strided
>>> b = as_strided(a.view(float), shape=a.shape + (2,),
                   strides=a.strides + a.view(float).strides)
>>> b
array([[ 1.5,  2.5],
       [ 3. ,  4. ],
       [ 1. ,  3. ]])

Das as_strided tut dasselbe wie das vielleicht leichter zu verstehende:

>>> bb = a.view(float).reshape(a.shape + (-1,))[:, :2]
>>> bb
array([[ 1.5,  2.5],
       [ 3. ,  4. ],
       [ 1. ,  3. ]])

Eine davon ist ein Blick auf a:

>>> b[0,0] =0
>>> a
array([(0.0, 2.5, [[0.0, 2.0], [1.0, 2.0]]),
       (3.0, 4.0, [[4.0, 5.0], [4.0, 5.0]]),
       (1.0, 3.0, [[2.0, 6.0], [2.0, 6.0]])], 
      dtype=[('x', '>> bb[2, 1] = 0
>>> a
array([(0.0, 2.5, [[0.0, 2.0], [1.0, 2.0]]),
       (3.0, 4.0, [[4.0, 5.0], [4.0, 5.0]]),
       (1.0, 0.0, [[2.0, 6.0], [2.0, 6.0]])], 
      dtype=[('x', '

``

Es wäre schön, wenn eine davon in ein Rekordarray umgewandelt werden könnte, aber numpy weigert sich dies zu tun, der Grund ist mir nicht klar:

>>> b.view([('x',float), ('y',float)])
Traceback (most recent call last):
  File "", line 1, in 
ValueError: new type not compatible with array.

Natürlich würde das, was für 'x' und 'y' funktioniert (irgendwie) nicht funktionieren, zum Beispiel für 'x' und 'value', also lautet die allgemeine Antwort: Es ist nicht möglich.

``

0voto

xyzzyqed Punkte 437

In meinem Fall entspricht 'mehrere Spalten' zwei Spalten des gleichen Datentyps, wo ich die folgende Funktion verwenden kann, um eine Ansicht zu erstellen:

def make_view(arr, fields, dtype):
    offsets = [arr.dtype.fields[f][1] for f in fields]
    offset = min(offsets)
    stride = max(offsets)
    return np.ndarray((len(arr), 2), buffer=arr, offset=offset, strides=(arr.strides[0], stride-offset), dtype=dtype)

Ich denke, das läuft auf dasselbe hinaus, was @Jamie gesagt hat, es kann im Allgemeinen nicht gemacht werden, aber für zwei Spalten desselben Datentyps kann es. Das Ergebnis dieser Funktion ist kein Dict, sondern ein altmodisches numpy-Array.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X