Wie man Web-Scraping für Machine Learning nutzt

Erfahren Sie, wie Sie vom Web gescrapte Daten für Machine-Learning-Projekte erfassen, aufbereiten und verwenden, einschließlich Tipps zur ETL-Einrichtung und zum Modelltraining.
22 min read
How to Use Web Scraping for Machine Learning blog image

In diesem Leitfaden erfahren Sie Folgendes:

  • Was ist Machine Learning?
  • Warum Web-Scraping für Machine Learning nützlich ist
  • Wie man Scraping für Machine Learning durchführt
  • Wie man Machine Learning auf gescrapte Daten anwendet
  • Details zum Training von ML-Modellen mit gescrapten Daten
  • Wie man ETLs einrichtet, wenn man Daten für Machine Learning scrapt

Dann legen wir mal los!

Was ist Machine Learning?

Machine Learning, auch ML genannt, ist ein Teilbereich der Künstlichen Intelligenz (KI), der sich mit der Entwicklung von Systemen befasst, die aus Daten lernen können. Die große Revolution, die sich aus der Anwendung des Machine Learning auf Software und Computersysteme ergibt, besteht insbesondere darin, dass Computer nicht mehr explizit programmiert werden müssen, um ein ML-Problem zu lösen. Dank der Machine-Learning-Systemen, die aus Daten lernen.

Wie können Maschinen aus Daten lernen? Man kann sich Machine Learning als nichts anderes als angewandte Mathematik vorstellen. Die ML-Modelle können nämlich die Muster der zugrunde liegenden Daten erkennen, denen sie ausgesetzt sind, sodass sie bei neuen Eingabedaten Vorhersagen zu den Ergebnissen machen können.

Warum Web-Scraping für Machine Learning nützlich ist

Systeme für Machine Learning – aber ganz allgemein jedes KI-System –benötigen Daten, um die Modelle zu trainieren, und hier kommt Web-Scraping als Chance für Datenexperten ins Spiel.

Hier sind also einige Gründe, warum Web-Scraping für Machine Learning wichtig ist:

  • Datenerfassung im großen Maßstab: Für ein effektives Training von Machine-Learning-Modellen – und insbesondere von Deep-Learning-Modellen – sind große Datenmengen erforderlich. Web-Scraping ermöglicht das Sammeln von großen Datensätzen, die anderswo nicht verfügbar sind.
  • Vielfältige und reichhaltige Datenquellen: Wenn Sie bereits über Daten verfügen, um Ihre ML-Modelle zu trainieren, ist das Scrapen des Webs eine Gelegenheit, Ihre Datensätze zu erweitern, da das Web eine Vielzahl von Daten enthält.
  • Aktuelle Informationen: Manchmal entsprechen Ihre Daten nicht den neuesten Trends. In diesem Fall kann Ihnen Web-Scraping weiterhelfen. Für Modelle, die auf die neuesten Informationen angewiesen sind (z. B. Aktienkursprognosen, Analyse der Nachrichtenstimmung usw.), kann Web-Scraping aktuelle Datenfeeds liefern.
  • Verbesserung der Modellleistung: Die Daten, die Sie haben, können je nach Modell oder Projekt, an dem Sie arbeiten, einfach nicht ausreichen. Aus diesem Grund ist das Abrufen von Daten aus dem Internet mittels Web-Scraping eine Möglichkeit, mehr Daten zu erhalten, um die Leistung Ihres Modells zu verbessern und es zu validieren.
  • Marktanalyse: Das Scrapen von Bewertungen, Kommentaren und Beurteilungen hilft dabei, die Stimmung der Verbraucher zu verstehen, was für Unternehmen sehr wertvoll ist. Dies kann auch dazu beitragen, Daten zu neuen Themen zu sammeln und Prognosen über Markttrends oder die öffentliche Meinung aufstellen.

Voraussetzungen

In diesem Tutorial lernen Sie, wie Sie Web-Scraping für Machine Learning in Python durchführen können.

Um das nachstehende Python-Projekt zu reproduzieren, muss Ihr System die folgenden Voraussetzungen erfüllen:

  • Python 3.6 oder höher: Jede Python-Version höher als 3.6 ist geeignet. Insbesondere werden wir die Abhängigkeiten über pip installieren, das bereits mit jeder Python-Version größer als 3.4 installiert wird.
  • Jupyter Notebook 6.x: Wir werden ein Jupyter Notebook verwenden, um die Daten zu analysieren und mithilfe von Machine Learning Prognosen aufzustellen. Jede höhere Version als 6.x ist geeignet.
  • Eine IDEVS CODE oder eine andere Python IDE Ihrer Wahl genügt.

Wie man Scraping für Machine Learning durchführt

In diesem Abschnitt erfahren Sie Schritt für Schritt, wie Sie ein Web-Scraping-Projekt erstellen, das Daten zur weiteren Analyse mit Machine Learning abruft.

Im Detail werden Sie sehen, wie man Yahoo Finanzen scrapen kann, um NVIDIA-Aktienkurse zu erhalten. Wir werden diese Daten dann für Machine Learning verwenden.

Schritt Nr. 1: Einrichten der Umgebung

Erstellen Sie zunächst ein Repository (z. B. mit dem Namen scraping_project), das Unterordner mit den Namen DatenNotebooks und Skripte enthält, etwa so:

scraping_project/
├── data/
│   └── ...
├── notebooks/
│   └── analysis.ipynb
├── scripts/
│   └── data_retrieval.py
└── venv/

Wo:

  • data_retrieval.py wird Ihre Scraping-Logik enthalten.
  • analysis.ipynb wird die Lernlogik enthalten.
  • data/ wird die gescrapten Daten enthalten, die mittels Machine Learning analysiert werden.

Der Ordner venv/ enthält die virtuelle Umgebung. Sie können ihn wie folgt erstellen:

python3 -m venv venv 

Zur Aktivierung unter Windows, führen Sie ihn wie folgt aus:

venv\Scripts\activate

Unter macOS/Linux, führen Sie Folgendes aus:

source venv/bin/activate

Sie können nun alle benötigten Bibliotheken installieren:

pip install selenium requests pandas matplotlib scikit-learn tensorflow notebook

Schritt Nr. 2: Zielseite festlegen

Um die historischen NVIDIA-Daten zu erhalten, müssen Sie die folgende URL aufrufen:

https://finance.yahoo.com/quote/NVDA/history/

Die Seite enthält jedoch einige Filter, mit denen Sie bestimmen können, wie die Daten angezeigt werden sollen:

Filter, mit denen Sie festlegen können, wie die Daten angezeigt werden sollen.

Um genügend Daten für Machine Learning abzurufen, können Sie sie nach 5 Jahren filtern. Zur Vereinfachung können Sie die folgende URL nutzen, die die Daten bereits nach 5 Jahren filtert:

https://finance.yahoo.com/quote/NVDA/history/?frequency=1d&period1=1574082848&period2=1731931014

Auf dieser Seite müssen Sie die folgende Tabelle anvisieren und die Daten aus ihr abrufen:

Tabelle mit täglichen Finanzdaten wie Eröffnungs- und Schlusskurs, Tiefst- und Höchstkurs und mehr.

Der CSS-Selektor, der die Tabelle definiert, ist .table, sodass Sie den folgenden Code in die Datei data_retrieval.py schreiben können:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.common import NoSuchElementException
import pandas as pd
import os

# Configure Selenium
driver = webdriver.Chrome(service=Service())

# Target URL
url = "https://finance.yahoo.com/quote/NVDA/history/?frequency=1d&period1=1574082848&period2=1731931014"
driver.get(url)

# Wait for the table to load
try:
    WebDriverWait(driver, 20).until(
        EC.presence_of_element_located((By.CSS_SELECTOR, ".table"))
    )
except NoSuchElementException:
    print("The table was not found, verify the HTML structure.")
    driver.quit()
    exit()

# Locate the table and extract its rows
table = driver.find_element(By.CSS_SELECTOR, ".table")
rows = table.find_elements(By.TAG_NAME, "tr")

Bis jetzt macht dieser Code Folgendes:

  • Er richtet eine Selenium-Chrome-Treiber-Instanz ein.
  • Er legt die Ziel-URL fest und weist Selenium an, diese zu besuchen.
  • Er wartet darauf, dass die Tabelle geladen wird: In diesem Fall wird die Zieltabelle durch Javascript geladen, sodass der Web-Treiber 20 Sekunden wartet, um sicherzustellen, dass die Tabelle geladen wird.
  • Er fängt die gesamte Tabelle ab, indem der spezielle CSS-Selektor verwendet wird.

Schritt Nr. 3: Abrufen der Daten und Speichern in einer CSV-Datei

An dieser Stelle können Sie Folgendes machen:

  1. Extrahieren Sie die Headers aus der Tabelle (diese werden unverändert an die CSV-Datei angehängt).
  2. Rufen Sie alle Daten aus der Tabelle ab.
  3. Konvertieren Sie die Daten in einen Numpy-Datenrahmen.

Sie können dies mit dem folgenden Code machen:

# Extract headers from the first row of the table
headers = [header.text for header in rows[0].find_elements(By.TAG_NAME, "th")]

# Extract data from the subsequent rows
data = []
for row in rows[1:]:
    cols = [col.text for col in row.find_elements(By.TAG_NAME, "td")]
    if cols:
        data.append(cols)

# Convert data into a pandas DataFrame
df = pd.DataFrame(data, columns=headers)

Schritt Nr. 4: Speichern der CSV-Datei im Ordner data/ 

Wenn Sie sich die erstellte Ordnerstruktur ansehen, sollten Sie daran denken, dass sich die Datei data_retrieval.py im Ordner scripts/ befindet. Die CVS-Datei muss stattdessen im Ordner data/ gespeichert werden, sodass Sie dies in Ihrem Code berücksichtigen müssen:

# Determine the path to save the CSV file
current_dir = os.path.dirname(os.path.abspath(__file__))  

# Navigate to the "data/" directory
data_dir = os.path.join(current_dir, "../data") 

# Ensure the directory exists 
os.makedirs(data_dir, exist_ok=True)  

# Full path to the CSV file
csv_path = os.path.join(data_dir, "nvda_stock_data.csv")  

# Save the DataFrame to the CSV file
df.to_csv(csv_path, index=False)
print(f"Historical stock data saved to {csv_path}")

# Close the WebDriver
driver.quit()

Dieser Code ermittelt den (absoluten) aktuellen Pfad mit der Methode os.path.dirname(), navigiert zum Ordner data/ mit der Methode os.path.join(), stellt dessen Existenz mit der Methode os.makedirs(data_dir, exist_ok=True) sicher, speichert die Daten in eine CSV-Datei mit der Methode df.to_csv() aus der Pandas-Bibliothek und beendet schließlich den Treiber.

Schritt Nr. 5: Das Ganze zusammensetzen

Hier ist der vollständige Code für die Datei data_retrieval.py:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.common import NoSuchElementException
import pandas as pd
import os

# Configure Selenium
driver = webdriver.Chrome(service=Service())

# Target URL
url = "https://finance.yahoo.com/quote/NVDA/history/?frequency=1d&period1=1574082848&period2=1731931014"
driver.get(url)

# Wait for the table to load
try:
    WebDriverWait(driver, 5).until(
        EC.presence_of_element_located((By.CSS_SELECTOR, "table.table.yf-j5d1ld.noDl"))
    )
except NoSuchElementException:
    print("The table was not found, verify the HTML structure.")
    driver.quit()
    exit()

# Locate the table and extract its rows
table = driver.find_element(By.CSS_SELECTOR, ".table")
rows = table.find_elements(By.TAG_NAME, "tr")

# Extract headers from the first row of the table
headers = [header.text for header in rows[0].find_elements(By.TAG_NAME, "th")]

# Extract data from the subsequent rows
data = []
for row in rows[1:]:
    cols = [col.text for col in row.find_elements(By.TAG_NAME, "td")]
    if cols:
        data.append(cols)

# Convert data into a pandas DataFrame
df = pd.DataFrame(data, columns=headers)

# Determine the path to save the CSV file
current_dir = os.path.dirname(os.path.abspath(__file__))  

# Navigate to the "data/" directory
data_dir = os.path.join(current_dir, "../data") 

# Ensure the directory exists 
os.makedirs(data_dir, exist_ok=True)

# Full path to the CSV file  
csv_path = os.path.join(data_dir, "nvda_stock_data.csv")

# Save the DataFrame to the CSV file
df.to_csv(csv_path, index=False)
print(f"Historical stock data saved to {csv_path}")

# Close the WebDriver
driver.quit()

Mit ein paar Zeilen Code haben Sie 5 Jahre historische Daten zu den NVIDIA-Aktien abgerufen und in einer CSV-Datei gespeichert.

Unter Windows starten Sie das obige Skript mit:

python data_retrieval.py

Oder äquivalenterweise unter Linux/macOS:

python3 data_retrieval.py

Nachfolgend sehen Sie, wie die gescrapten Daten aussehen:

Die Ausgabe der gescrapten Tabelle

Verwenden von Machine Learning für gescrapte Daten

Da die Daten nun in einer CSV-Datei gespeichert sind, können Sie mithilfe von Machine Learning Prognosen aufstellen.

In den folgenden Schritten erfahren Sie, wie Sie dies machen können.

Schritt Nr. 1: Erstellen einer neuen Jupyter Notebook-Datei

Um eine neue Jupyter Notebook-Datei zu erstellen, navigieren Sie vom Hauptordner zum Ordner notebooks/

cd notebooks 

Öffnen Sie dann ein Jupyter Notebook wie folgt:

jupyter notebook

Wenn der Browser geöffnet ist, klicken Sie auf Neu > Python3 (ipykernel), um eine neue Jupyter Notebook-Datei zu erstellen:

Erstellen einer neuen Jupyter Notebook-Datei

Benennen Sie die Datei um, beispielsweise in analysis.ipynb.

Schritt Nr. 2: CSV-Datei öffnen und Kopf anzeigen

Nun können Sie die CSV-Datei mit den Daten öffnen und den Kopf des Datenrahmens anzeigen:

import pandas as pd

# Path to the CSV file
csv_path = "../data/nvda_stock_data.csv"

# Open the CVS file
df = pd.read_csv(csv_path)

# Show head
df.head()

Dieser Code wird im Ordner data/ mit csv_path = "../data/nvda_stock_data.csv"abgelegt. Dann öffnet er die CSV mit der Methode pd.read_csv() als Datenrahmen und zeigt dessen Kopf (die ersten 5 Zeilen) mit der Methode df.head() an.

Hier ist das erwartete Ergebnis:

Das erwartete Ergebnis

Schritt Nr. 3: Visualisieren Sie den zeitlichen Trend des ** Adj Close-Wertes.

Da der Datenrahmen nun korrekt geladen ist, können Sie den Trend des Adj Close-Wertes, der den bereinigten Schlusswert darstellt:

import matplotlib.pyplot as plt

# Ensure the "Date" column is in datetime forma
df["Date"] = pd.to_datetime(df["Date"])

# Sort the data by date (if not already sorted)
df = df.sort_values(by="Date")

# Plot the "Adj Close" values over time
plt.figure(figsize=(10, 6))
plt.plot(df["Date"], df["Adj Close"], label="Adj Close", linewidth=2)

# Customize the plot
plt.title("NVDA Stock Adjusted Close Prices Over Time", fontsize=16) # Sets title
plt.xlabel("Date", fontsize=12) # Sets x-axis label
plt.ylabel("Adjusted Close Price (USD)", fontsize=12) # Sets y-axis label
plt.grid(True, linestyle="--", alpha=0.6) # Defines styles of the line
plt.legend(fontsize=12) # Shows legend
plt.tight_layout()

# Show the plot
plt.show()

Dieses Snippet tut Folgendes:

  • df["Datum"] greift auf die Spalte Datum des Datenrahmens zu und stellt mit der Methode pd.to_datetime() sicher, dass die Daten im Datumsformat vorliegen.
  • Die Funktion df.sort_values() sortiert die Daten der Spalte Datum. Damit wird sichergestellt, dass die Daten in chronologischer Reihenfolge angezeigt werden.
  • plt.figure() setzt die Dimensionen der Darstellung und plt.plot() zeigt ihn an.
  • Die Codezeilen unter dem Kommentar # Anpassen der Darstellung sind nützlich, um die Darstellung anzupassen, indem der Titel, die Beschriftung der Achsen und die Anzeige der Legende angegeben werden.
  • Die Methode plt.show() ist diejenige, mit der die Darstellung tatsächlich angezeigt wird.

Das erwartete Ergebnis ist ungefähr so:

Beispiel für bereinigte Schlusskurse der NVDA-Aktie im Zeitverlauf

Diese Darstellung zeigt den aktuellen Trend der bereinigten Schlusswerte der NVIDIA-Aktien im Zeitverlauf. Das Machine-Learning-Modell, das Sie trainieren werden, muss diese so gut wie möglich prognostizieren.

Schritt Nr. 3: Aufbereitung von Daten für Machine Learning

Zeit, die Daten für Machine Learning aufzubereiten!

Zunächst können Sie die Daten bereinigen und aufbereiten:

from sklearn.preprocessing import MinMaxScaler

# Convert data types
df["Volume"] = pd.to_numeric(df["Volume"].str.replace(",", ""), errors="coerce")
df["Open"] = pd.to_numeric(df["Open"].str.replace(",", ""), errors="coerce")

# Handle missing values 
df = df.infer_objects().interpolate() 

# Select the target variable ("Adj Close") and scale the data
scaler = MinMaxScaler(feature_range=(0, 1))  # Scale data between 0 and 1
data = scaler.fit_transform(df[["Adj Close"]])

Dieser Code bewirkt Folgendes:

  • Konvertiert die Volumen– und Offene Werte mit der Methode to_numeric().
  • Behandelt fehlende Werte durch Interpolation, um sie mit der Methode interpolate() aufzufüllen.
  • Skaliert die Daten mit dem MinMaxScaler().
  • Wählt und transformiert (skaliert) die Zielvariable Adj Close mit der Methode fit_transform().

Schritt Nr. 4: Erstellen der Trainings- und Testsätze

Das Modell, das für dieses Tutorial verwendet wird, ist ein LSTM (Long Short-Term Memory), das ein RNN (Recurrent Neural Network) ist, also erstellen Sie eine Folge von Schritten, damit es die Daten lernen kann:

import numpy as np

# Create sequences of 60 time steps for prediction
sequence_length = 60
X, y = [], []

for i in range(sequence_length, len(data)):
    X.append(data[i - sequence_length:i, 0])  # Last 60 days
    y.append(data[i, 0])  # Target value

X, y = np.array(X), np.array(y)

# Split into training and test sets
split_index = int(len(X) * 0.8)  # 80% training, 20% testing
X_train, X_test = X[:split_index], X[split_index:]
y_train, y_test = y[:split_index], y[split_index:]

Dieser Code:

  • Erstellt eine Folge von 60 Zeitschritten. X ist das Array der Features, y ist das Array mit dem Zielwert.
  • Teilt den ursprünglichen Datenrahmen wie folgt auf: 80 % werden zum Trainingssatz, 20 % zum Testsatz.

Schritt Nr. 5: Modell trainieren

Sie können nun das RNN mit dem Trainingssatz trainieren:

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, LSTM

# Reshape X for LSTM [samples, time steps, features]
X_train = X_train.reshape((X_train.shape[0], X_train.shape[1], 1))
X_test = X_test.reshape((X_test.shape[0], X_test.shape[1], 1))

# Build the Sequential Neural Network
model = Sequential()
model.add(LSTM(32, activation="relu", return_sequences=False))
model.add(Dense(1))
model.compile(loss="mean_squared_error", optimizer="adam")

# Train the Model
history = model.fit(X_train, y_train, epochs=20, batch_size=32, validation_data=(X_test, y_test), verbose=1)

Dieser Code bewirkt Folgendes:

  • Umformt das Array der Features, die für das neuronale LSTM-Netzwerk bereit sein sollen, mit der Methode reshape()sowohl für die Trainings- als auch für die Testsätze
  • Baut das neuronale LSTM-Netz auf, indem es seine Parameter setzt.
  • Passt das LSTM mithilfe der Methode fit() an den Trainingssatz an.

Das Modell hat nun den Trainingssatz angepasst und ist bereit, Prognosen aufzustellen.

Schritt Nr. 6: Prognosen aufstellen und die Leistung des Modells bewerten

Das Modell ist nun bereit, die Adj Close-Werte zu prognostizieren und Sie können seine Leistung wie folgt bewerten:

from sklearn.metrics import mean_squared_error, r2_score

# Make Predictions
y_pred = model.predict(X_test)

# Inverse scale predictions and actual values for comparison
y_test = scaler.inverse_transform(y_test.reshape(-1, 1))
y_pred = scaler.inverse_transform(y_pred)

# Evaluate the Model
mse = mean_squared_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)

# print results
print("\nLSTM Neural Network Results:")
print(f"Mean Squared Error: {mse:.2f}")
print(f"R-squared Score: {r2:.2f}")

Dieser Code bewirkt Folgendes:

  • Kehrt die Werte auf der horizontalen Achse um, sodass die Daten in letzter Zeit in chronologischer Reihenfolge dargestellt werden können. Dies geschieht mit der Methode inverse_transform().
  • Bewertet das Modell anhand von mean squared error und R^2 score.

In Anbetracht der statistischen Fehler, die aufgrund der stochastischen Natur von ML-Modellen auftreten können, ist das erwartete Ergebnis in etwa so:

Erwartetes Ergebnis unter Berücksichtigung der statistischen Fehler

Dies sind ziemlich gute Werte, die darauf hinweisen, dass das gewählte Modell aufgrund seiner Features gut geeignet ist, Adj Close zu prognostizieren.

Schritt Nr. 7: Vergleich der tatsächlichen mit den vorhergesagten Werten mit einer Darstellung

Beim Machine Learning reicht es manchmal nicht aus, die Ergebnisse analytisch zu vergleichen, wie wir es im vorherigen Schritt getan haben. Um die Wahrscheinlichkeit zu erhöhen, dass das gewählte Modell ein gutes ist, besteht eine typische Lösung darin, auch eine Darstellung zu erstellen.

Eine gängige Lösung ist zum Beispiel die Erstellung einer Darstellung, das die tatsächlichen Werte von Adj Close mit den durch das LSTM-Modell prognostizierten Werten vergleicht:

# Visualize the Results
test_results = pd.DataFrame({
    "Date": df["Date"].iloc[len(df) - len(y_test):],  # Test set dates
    "Actual": y_test.flatten(),
    "Predicted": y_pred.flatten()
})

# Setting plot
plt.figure(figsize=(12, 6))
plt.plot(test_results["Date"], test_results["Actual"], label="Actual Adjusted Close", color="blue", linewidth=2)
plt.plot(test_results["Date"], test_results["Predicted"], label="Predicted Adjusted Close", color="orange", linestyle="--", linewidth=2)
plt.title("Actual vs Predicted Adjusted Close Prices (LSTM)", fontsize=16)
plt.xlabel("Date", fontsize=12)
plt.ylabel("Adjusted Close Price (USD)", fontsize=12)
plt.legend()
plt.grid(alpha=0.6)
plt.tight_layout()
plt.show()

Dieser Code:

  • Legt den Vergleich zwischen den tatsächlichen und den prognostizierten Werten auf der Ebene des Testsatz fest, sodass die tatsächlichen Werte auf die Form des Testsatzes getrimmt werden müssen. Dies geschieht mit den Methoden iloc() und flatten().
  • Erstellt die Darstellung, fügt Beschriftungen für die Achsen und den Titel hinzu und verwaltet andere Einstellungen zur Verbesserung der Visualisierung.

Das erwartete Ergebnis sieht etwa wie folgt aus:

Tatsächliche vs. prognostizierte bereinigte Schlusskurse

Wie die Darstellung zeigt, sagen die vom neuronalen LSTM-Netzwerks prognostizierten Werte (gelbe gepunktete Linie) die tatsächlichen Werte (durchgehende blaue Linie) recht gut voraus. Dies war respektabel, da die analytischen Ergebnisse gut waren, aber die Darstellung hilft sicherlich, das gute Ergebnis zu visualisieren.

Schritt Nr. 8: Das Ganze zusammensetzen

Hier ist der vollständige Code für das Notebook analysis.ipynb:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error, r2_score
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, LSTM

# Path to the CSV file
csv_path = "../data/nvda_stock_data.csv"  
# Open CSV as data frame
df = pd.read_csv(csv_path)

# Convert "Date" to datetime format
df["Date"] = pd.to_datetime(df["Date"])

# Sort by date
df = df.sort_values(by="Date")

# Convert data types
df["Volume"] = pd.to_numeric(df["Volume"].str.replace(",", ""), errors="coerce")
df["Open"] = pd.to_numeric(df["Open"].str.replace(",", ""), errors="coerce")

# Handle missing values 
df = df.infer_objects().interpolate()

# Select the target variable ("Adj Close") and scale the data
scaler = MinMaxScaler(feature_range=(0, 1))  # Scale data between 0 and 1
data = scaler.fit_transform(df[["Adj Close"]])

# Prepare the Data for LSTM
# Create sequences of 60 time steps for prediction
sequence_length = 60
X, y = [], []

for i in range(sequence_length, len(data)):
    X.append(data[i - sequence_length:i, 0])  # Last 60 days
    y.append(data[i, 0])  # Target value

X, y = np.array(X), np.array(y)

# Split into training and test sets
split_index = int(len(X) * 0.8)  # 80% training, 20% testing
X_train, X_test = X[:split_index], X[split_index:]
y_train, y_test = y[:split_index], y[split_index:]

# Reshape X for LSTM [samples, time steps, features]
X_train = X_train.reshape((X_train.shape[0], X_train.shape[1], 1))
X_test = X_test.reshape((X_test.shape[0], X_test.shape[1], 1))

# Build the Sequential Neural Network
model = Sequential()
model.add(LSTM(32, activation="relu", return_sequences=False))
model.add(Dense(1))
model.compile(loss="mean_squared_error", optimizer="adam")

# Train the Model
history = model.fit(X_train, y_train, epochs=20, batch_size=32, validation_data=(X_test, y_test), verbose=1)

# Make Predictions
y_pred = model.predict(X_test)

# Inverse scale predictions and actual values for comparison
y_test = scaler.inverse_transform(y_test.reshape(-1, 1))
y_pred = scaler.inverse_transform(y_pred)

# Evaluate the Model
mse = mean_squared_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)

# Print results
print("\nLSTM Neural Network Results:")
print(f"Mean Squared Error: {mse:.2f}")
print(f"R-squared Score: {r2:.2f}")

# Visualize the Results
test_results = pd.DataFrame({
    "Date": df["Date"].iloc[len(df) - len(y_test):],  # Test set dates
    "Actual": y_test.flatten(),
    "Predicted": y_pred.flatten()
})

# Setting plot
plt.figure(figsize=(12, 6))
plt.plot(test_results["Date"], test_results["Actual"], label="Actual Adjusted Close", color="blue", linewidth=2)
plt.plot(test_results["Date"], test_results["Predicted"], label="Predicted Adjusted Close", color="orange", linestyle="--", linewidth=2)
plt.title("Actual vs Predicted Adjusted Close Prices (LSTM)", fontsize=16)
plt.xlabel("Date", fontsize=12)
plt.ylabel("Adjusted Close Price (USD)", fontsize=12)
plt.legend()
plt.grid(alpha=0.6)
plt.tight_layout()
plt.show()

Beachten Sie, dass dieser gesamte Code direkt zum Ziel führt, indem er die Teile überspringt, die den Kopf des Datenrahmens beim Öffnen anzeigen, und nur die aktuellen Werte von Adj Close darstellt.

Diese Schritte wurden zu Beginn dieses Absatzes als Teil der vorläufigen Datenanalyse beschrieben und sind nützlich, um zu verstehen, was man mit den Daten macht, bevor man ein ML-Modell trainiert.

HINWEIS: Der Code wurde Stück für Stück vorgestellt, aber angesichts der stochastischen Natur von ML wird empfohlen, den gesamten Code auszuführen, um das LSTM-Modell ordnungsgemäß zu trainieren und zu validieren. Andernfalls kann die endgültige Darstellung sehr unterschiedlich ausfallen.

Hinweise zum Prozess des Trainings von ML-Modellen mit gescrapten Daten

Der Einfachheit halber geht die Schritt-für-Schritt-Anleitung in diesem Artikel direkt auf die Anpassung eines neuronalen LSTM-Netzwerkes ein.

In Wirklichkeit ist dies bei ML-Modellen nicht der Fall. Wenn Sie also versuchen, ein Problem zu lösen, für das ein ML-Modell benötigt wird, läuft der Prozess wie folgt ab:

  • Vorläufige Datenanalyse: Dies ist der wichtigste Teil des Prozesses, da Sie hier Ihre Daten verstehen, eine Datenbereinigung durch Entfernen von NaN-Werten durchführen, eventuelle Duplikate verwalten und andere mathematische Probleme im Zusammenhang mit Ihren Daten lösen.
  • Training von ML-Modellen: Man weiß nie, ob das erste Modell, das man im Kopf hat, das beste ist, um das Problem zu lösen, das man mit ML lösen möchte. Eine typische Lösung ist die sogenannte stichprobenartige Überprüfung, was bedeutet:
    • Trainieren von 3 bis 4 ML-Modellen auf dem Trainingssatz und Bewertung ihrer Leistung darauf.
    • Ermitteln der 2 bis 3 ML-Modellen, die im Trainingssatz am besten abschneiden, und Abstimmen ihrer Hyperparameter.
    • Vergleich der Leistung der besten Modelle mit abgestimmten Hyperparametern auf dem Testsatz.
    • Wählen Sie das Modell mit der besten Leistung im Testsatz.
  • Einsatz: Das Modell, das am besten abschneidet, wird dann in der Produktion eingesetzt.

Einrichten von ETLs beim Scraping von Daten für Machine Learning

Zu Beginn dieses Artikels haben wir definiert, warum Web-Scraping für Machine Learning nützlich ist. Möglicherweise ist Ihnen jedoch eine Inkohärenz im entwickelten Projekt aufgefallen, die darauf beruht, dass die per Web-Scraping abgerufenen Daten in einer CSV-Datei gespeichert wurden.

Dies ist eine gängige Praxis beim Machine Learning, aber Sie sollten bedenken, dass es besser ist, dies zu Beginn eines ML-Projekts zu tun, wenn das Ziel darin besteht, das beste Modell zu finden, das zukünftige Werte der Zielwerte prognostizieren kann.

Wenn das beste Modell gefunden ist, wird in der Folge eine ETL-Pipeline (Extract Transform Load) eingerichtet, um neue Daten aus dem Web abzurufen, zu bereinigen und in eine Datenbank zu laden.

Der Prozess kann etwa wie folgt aussehen:

  • Extrahieren: In dieser Phase werden die Daten aus verschiedenen Quellen abgerufen, u. a. aus dem Internet durch scrapen.
  • Transformieren: Die gesammelten Daten durchlaufen den Prozess der Datenbereinigung und -aufbereitung.
  • Laden: Die abgerufenen und transformierten Daten werden verarbeitet und in einer Datenbank oder einem Datenwarenhaus gespeichert.

Nachdem die Daten gespeichert wurden, erfolgt in der nächsten Phase die Integration mit den Machine-Learning-Workflows, die das Modell unter anderem anhand neuer Daten neu trainieren und erneut validieren.

Fazit

In diesem Artikel haben wir gezeigt, wie man durch Scraping Daten aus dem Internet abruft und sie für Machine Learning verwendet. Wir haben auch die Bedeutung von Web-Scraping für Machine Learning vorgestellt und den Prozess des Trainings und der Strukturierung von ETLs diskutiert.

Obwohl es sich bei dem vorgeschlagenen Projekt um ein einfaches Projekt handelt, ist es verständlich, dass die zugrundeliegenden Prozesse – insbesondere die Prozesse im Zusammenhang mit der Strukturierung von ETLs zum kontinuierlichen Abrufen von Daten aus dem Web zur Verbesserung des ML-Modells – Komplexitäten mit sich bringen, die weiter analysiert werden sollten.

Das Scraping von Yahoo Finanzen kann in realen Szenarien weitaus komplexer sein als hier gezeigt wurde. Auf der Website werden einige Anti-Scraping-Technologien verwendet, die besondere Aufmerksamkeit erfordern. Für eine professionelle, voll funktionsfähige Komplettlösung, sehen Sie sich Bright Datas Yahoo Finanzen-Scraper an!

Wenn Scraping nicht Ihre Stärke ist, Sie aber dennoch Daten für Machine-Learning-Projekte benötigen, erkunden Sie unsere Lösungen für effizienten Datenabruf, die auf die Anforderungen von KI und Machine Learning zugeschnitten sind.

Erstellen Sie noch heute ein kostenloses Bright Data-Konto, um unsere Scraper-APIs auszuprobieren oder unsere Datensätze zu erkunden.

Keine Kreditkarte erforderlich