Seite 1 von 1

Numpy error seeting an array element with a sequence

Verfasst: Mittwoch 12. Juli 2023, 11:55
von wanted
0

Ich habe den folgenden Code geschrieben, aber irgendwie bekomme ich die ganze Zeit eine Error Message ausgespuckt und ich habe keine Ahnung wie ich ihn fixen kann.

Code: Alles auswählen

import pickle

import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score


data_dict = pickle.load(open('./data.pickle', 'rb'))

data = np.asarray(data_dict['data'])
labels = np.asarray(data_dict['labels'])

model = RandomForestClassifier()

model.fit(x_train, y_train)

y_predict = model.predict(x_test)

score = accuracy_score(y_predict, y_test)

print('{}% of samples were classified correctly !'.format(score * 100))

f = open('model.p', 'wb')
pickle.dump({'model': model}, f)
f.close()
Das ist der Error den ich bekomme

Code: Alles auswählen

/home/PycharmProjects/SignLanguage/train_classifier.py:13: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
  data = np.asarray(data_dict['data'])
TypeError: float() argument must be a string or a real number, not 'list'

The above exception was the direct cause of the following exception:


Traceback (most recent call last):
  File "/home/PycharmProjects/SignLanguage/train_classifier.py", line 21, in <module>
    model.fit(x_train, y_train)
  File "/home/PycharmProjects/SignLanguage/venv/lib/python3.10/site-packages/sklearn/base.py", line 1151, in wrapper
    return fit_method(estimator, *args, **kwargs)
  File "/home/PycharmProjects/SignLanguage/venv/lib/python3.10/site-packages/sklearn/ensemble/_forest.py", line 348, in fit
    X, y = self._validate_data(
  File "/home/PycharmProjects/SignLanguage/venv/lib/python3.10/site-packages/sklearn/base.py", line 621, in _validate_data
    X, y = check_X_y(X, y, **check_params)
  File "/home/PycharmProjects/SignLanguage/venv/lib/python3.10/site-packages/sklearn/utils/validation.py", line 1147, in check_X_y
    X = check_array(
  File "/home/PycharmProjects/SignLanguage/venv/lib/python3.10/site-packages/sklearn/utils/validation.py", line 917, in check_array
    array = _asarray_with_order(array, order=order, dtype=dtype, xp=xp)
  File "/home/PycharmProjects/SignLanguage/venv/lib/python3.10/site-packages/sklearn/utils/_array_api.py", line 380, in _asarray_with_order
    array = numpy.asarray(array, order=order, dtype=dtype)
ValueError: setting an array element with a sequence.

Process finished with exit code 1
Ich habe versucht np 1.21.6, hat nichts gebracht. Ich habe versucht np 1.21.1 zu installieren , hat auch nichts gebracht. Ich habe auch versucht die initialisierung von data so zu verändern:

Code: Alles auswählen

data =  np.asarray([np.asarray(d) for d in data_dict['data']]) # doesn't work 
Außerdem wenn ich data so definiere:

Code: Alles auswählen

data =  np.asarray(data_dict['data'], dtype=float)
Bekomme ich den folgenden Fehler

Code: Alles auswählen

ValueError: setting an array element with a sequence. The requested array has an inhomogeneous shape after 1 dimensions. The detected shape was (2912,) + inhomogeneous part.
Der Code für data_dict sieht wie folgt aus:

Code: Alles auswählen

import mediapipe as mp
import cv2
import os
import pickle
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt

mp_hands = mp.solutions.hands
mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles

hands = mp_hands.Hands(static_image_mode=True, min_detection_confidence=0.3)

DATA_DIR = "./data"

data = []
labels = []

for dir_ in os.listdir(DATA_DIR):
    for img_path in os.listdir(os.path.join(DATA_DIR, dir_)):
        data_aux = []

        img = cv2.imread(os.path.join(DATA_DIR, dir_, img_path))
        img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

        results = hands.process(img_rgb)
        if results.multi_hand_landmarks:
            for hand_landmarks in results.multi_hand_landmarks:
                for i in range(len(hand_landmarks.landmark)):
                    x = hand_landmarks.landmark[i].x
                    y = hand_landmarks.landmark[i].y
                    data_aux.append(x)
                    data_aux.append(y)

            data.append(data_aux)
            labels.append(dir_)

f = open('data.pickle', 'wb')
pickle.dump({'data': data, 'labels': labels}, f)
f.close()
Wenn ich folgendes versuche

Code: Alles auswählen

np.array(data) bevor pickle.dump() 
bekomme ich die folgende Warnung:

Code: Alles auswählen

VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
  np.array(data)
Und wenn ich es mir so ausgeben lasse :

Code: Alles auswählen

print([np.asarray(d).shape for d in data_dict['data']]
erscheint folgendes:

Code: Alles auswählen

[(42,), (42,), (42,), (42,), (42,), (42,), (42,), (42,), (42,), (42,), (42,), (42,), (42,), (42,), (42,), (42,), (42,), (42,), (42,), (42,), (42,), (42,), (42,), (42,), (42,)]
Traceback (most recent call last):
  File "/home/PycharmProjects/SignLanguage/train_classifier.py", line 16, in <module>
    data =  np.asarray(data_dict['data'], dtype=float)
ValueError: setting an array element with a sequence. The requested array has an inhomogeneous shape after 1 dimensions. The detected shape was (2912,) + inhomogeneous part.
Ich bin komplet aufgeschmissen und habe keine Ahnung was ich noch versuchen könnte
Vielen Dank für jede Idee und Hilfe.

Re: Numpy error seeting an array element with a sequence

Verfasst: Mittwoch 12. Juli 2023, 14:06
von Sirius3
Du hast eine dreidimensionale Struktur 25x42x* wobei die letzte Dimension eben nicht für alle 25x42-Felder gleich groß ist, denn Du ermittelst irgendwelche x-y-Werte pro Bild.

Re: Numpy error seeting an array element with a sequence

Verfasst: Mittwoch 12. Juli 2023, 15:16
von __blackjack__
@wanted: Zum Quelltext der die Pickle-Datei erzeugt: Da wird nichts mit `matplotlib` gemacht, die Importe können raus. Es werden auch einige unbenutzte Namen im Zusammenhang mit `mediapipe` definiert. Fall die benutzt würden, würde man das auch eher im Zusammenhang mit Importen und ``as`` machen. So ist das ein bisschen unerwartet.

Statt `os.path` & Co würde man in neuem Code `pathlib` verwenden.

Ich würde da ja mindestens mal prüfen ob die entsprechenden Pfade zu Verzeichnissen beziehungsweise Dateien führen.

``for i in range(len(sequence)):`` nur um dann `i` als Index in `sequence` zu verwenden ist ein „anti pattern“ in Python weil man *direkt* über die Elemente der Sequenz iterieren kann, ohne den unnötigen Umweg über einen Laufindex.

Dateien öffnet man wo es geht mit der ``with``-Anweisung, dann ist das schliessen auch in den Fällen garantiert in denen der Programmfluss nicht an einem `close()` vorbei kommt.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import os
import pickle
from pathlib import Path

import cv2
from mediapipe.solutions.hands import Hands

DATA_PATH = Path("data")


def main():
    hands = Hands(static_image_mode=True, min_detection_confidence=0.3)
    data = []
    labels = []
    for sub_path in (path for path in DATA_PATH.iterdir() if path.is_dir()):
        for image_path in (
            path for path in sub_path.iterdir() if path.is_file()
        ):
            data_aux = []
            results = hands.process(
                cv2.cvtColor(cv2.imread(image_path), cv2.COLOR_BGR2RGB)
            )
            if results.multi_hand_landmarks:
                for hand_landmarks in results.multi_hand_landmarks:
                    for coordinate in hand_landmarks.landmark:
                        data_aux.append(coordinate.x)
                        data_aux.append(coordinate.y)

                data.append(data_aux)
                labels.append(sub_path)

    with open("data.pickle", "wb") as file:
        pickle.dump({"data": data, "labels": labels}, file)


if __name__ == "__main__":
    main()
Was man eigenltich nicht haben will sind ”parallele” Datenstrukturen, also Listen bei denen die Werte am gleichen Index zusammengehören. Da verwendet man *eine* Liste, beispielsweise mit Tupeln aus den zusammengehörenden Werten.

Ebenfalls nicht gut sind Listen bei denen immer jedes zweite Element etwas anderes bedeutet, oder allgemeiner, bei denen die Elemente nicht alle die gleiche Bedeutung haben. Auch hier würde man wieder die zusammengehörenden Elemente beispielsweise in Tupeln zusammenfassen.

Sähe dann so aus (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import os
import pickle
from pathlib import Path

import cv2
from mediapipe.solutions.hands import Hands

DATA_PATH = Path("data")


def main():
    hands = Hands(static_image_mode=True, min_detection_confidence=0.3)
    data_and_labels = []
    for sub_path in (path for path in DATA_PATH.iterdir() if path.is_dir()):
        for image_path in (
            path for path in sub_path.iterdir() if path.is_file()
        ):
            data_aux = []
            results = hands.process(
                cv2.cvtColor(cv2.imread(image_path), cv2.COLOR_BGR2RGB)
            )
            if results.multi_hand_landmarks:
                data_aux.extend(
                    (coordinate.x, coordinate.y)
                    for hand_landmarks in results.multi_hand_landmarks
                    for coordinate in hand_landmarks.landmark
                )
                data_and_labels.append((data_aux, sub_path))

    with open("data.pickle", "wb") as file:
        pickle.dump(data_and_labels, file)


if __name__ == "__main__":
    main()
Die Stelle an der `data_aux` definiert wird, das entweder genau einmal um Werte ergänzt oder gar nicht verwendet wird, ist unübersichtlich. Eigentlich braucht man den Namen auch überhaupt gar nicht:

Code: Alles auswählen

#!/usr/bin/env python3
import os
import pickle
from pathlib import Path

import cv2
from mediapipe.solutions.hands import Hands

DATA_PATH = Path("data")


def main():
    hands = Hands(static_image_mode=True, min_detection_confidence=0.3)
    data_and_labels = []
    for sub_path in (path for path in DATA_PATH.iterdir() if path.is_dir()):
        for image_path in (
            path for path in sub_path.iterdir() if path.is_file()
        ):
            results = hands.process(
                cv2.cvtColor(cv2.imread(image_path), cv2.COLOR_BGR2RGB)
            )
            if results.multi_hand_landmarks:
                data_and_labels.append(
                    (
                        [
                            (coordinate.x, coordinate.y)
                            for hand_landmarks in results.multi_hand_landmarks
                            for coordinate in hand_landmarks.landmark
                        ],
                        sub_path,
                    )
                )

    with open("data.pickle", "wb") as file:
        pickle.dump(data_and_labels, file)


if __name__ == "__main__":
    main()

Re: Numpy error seeting an array element with a sequence

Verfasst: Mittwoch 12. Juli 2023, 17:37
von wanted
Wenn ich den Code so ändere funktioniert das zwar für das erstellen der pickle Datei, allerdings bin ich jetzt komplett verwirrt wie ich das dann jetzt in einen np array umwandele so wie ich das ursprünglich tun wollte...

jetzt sieht datadict so aus falls das relevant ist:

Code: Alles auswählen

[..., ([(0.3775956332683563, 0.5386132597923279), (0.4242878258228302, 0.5439502596855164), (0.45684775710105896, 0.5842125415802002), (0.4652678668498993, 0.6323069334030151), (0.466773122549057, 0.6693066954612732), (0.47439640760421753, 0.5882108211517334), (0.5042067170143127, 0.6475873589515686), (0.5086818337440491, 0.6876282691955566), (0.5048747062683105, 0.7186694145202637), (0.4496690034866333, 0.5951089262962341), (0.4633995294570923, 0.6819579005241394), (0.4674365520477295, 0.7289001941680908), (0.4705360233783722, 0.7637642621994019), (0.42224380373954773, 0.6048421263694763), (0.4277583956718445, 0.6780377626419067), (0.42316964268684387, 0.6603876352310181), (0.42096760869026184, 0.6366013288497925), (0.39536792039871216, 0.6151334643363953), (0.4052458107471466, 0.6753289103507996), (0.40337082743644714, 0.6603569388389587), (0.40039676427841187, 0.6392402052879333)], PosixPath('data/16'))]

Re: Numpy error seeting an array element with a sequence

Verfasst: Mittwoch 12. Juli 2023, 17:45
von wanted
Sirius3 hat geschrieben: Mittwoch 12. Juli 2023, 14:06 Du hast eine dreidimensionale Struktur 25x42x* wobei die letzte Dimension eben nicht für alle 25x42-Felder gleich groß ist, denn Du ermittelst irgendwelche x-y-Werte pro Bild.
Und wie würde ich das ignorieren bzw. ändern können?

Re: Numpy error seeting an array element with a sequence

Verfasst: Mittwoch 12. Juli 2023, 22:11
von Sirius3
Wie viele Hände pro Bild erwartest du denn?
Schau dir am besten erst einmal an, was cv denn pro Bild so erkennt.

Re: Numpy error seeting an array element with a sequence

Verfasst: Freitag 14. Juli 2023, 22:11
von wanted
Sirius3 hat geschrieben: Mittwoch 12. Juli 2023, 22:11 Wie viele Hände pro Bild erwartest du denn?
Schau dir am besten erst einmal an, was cv denn pro Bild so erkennt.
Der Tipp hats gebracht, das programm hat ab und zu zu viele Hände erkannt, die das Problem waren. Danke :)