

Bild von Autor | Leinwand
Was ist, wenn es eine Möglichkeit gibt, Ihren Python -Code schneller zu gestalten? __slots__ In Python ist es einfach zu implementieren und kann die Leistung Ihres Codes verbessern und gleichzeitig die Speicherverwendung reduzieren.
In diesem Artikel werden wir mithilfe eines Datenwissenschaftsprojekts aus der realen Welt, in dem Allegro dies als Herausforderung für den Rekrutierungsprozess für Datenwissenschaften nutzt, durchlaufen. Bevor wir uns jedoch mit diesem Projekt befassen, lassen Sie uns ein solides Verständnis dafür aufbauen, was __slots__ tut.
Was ist __slots__ in Python?
In Python hält jedes Objekt ein Wörterbuch seiner Attribute. Auf diese Weise können Sie sie hinzufügen, ändern oder löschen, aber es ist auch mit Kosten erhältlich: zusätzlicher Speicher und langsamerer Attributzugriff.
Der __slots__ Die Erklärung sagt Python, dass dies die einzigen Attribute sind, die dieses Objekt jemals benötigen wird. Es ist eine Artwork Einschränkung, aber es wird uns Zeit retten. Lassen Sie uns mit einem Beispiel sehen.
class WithoutSlots:
def __init__(self, title, age):
self.title = title
self.age = age
class WithSlots:
__slots__ = ('title', 'age')
def __init__(self, title, age):
self.title = title
self.age = age
In der zweiten Klasse, __slots__ fordert Python an, für jedes Objekt kein Wörterbuch zu erstellen. Stattdessen reserviert es einen festen Punkt im Speicher für den Namen und die Alterswerte, wodurch er schneller und die Speicherverwendung verringert wird.
Warum benutzen __slots__?
Lassen Sie uns nun den Grund nennen, warum Sie verwenden sollten __slots__.
- Speicher: Objekte nehmen weniger Platz ein, wenn Python ein Wörterbuch erstellt.
- Geschwindigkeit: Der Zugriff auf Werte ist schneller, da Python weiß, wo jeder Wert gespeichert ist.
- Bugs: Diese Struktur vermeidet stille Fehler, da nur die definierten erlaubt sind.
Verwenden Sie die Information Science Problem von Allegro als Beispiel
In diesem Datenprojekt forderte Allegro Information Science -Kandidaten auf, Laptoppreise durch Erstellen von Modellen für maschinelles Lernen vorherzusagen.

Hyperlink zu diesem Datenprojekt: https://platform.stratascratch.com/data-projects/laptop-price-prediction
Es gibt drei verschiedene Datensätze:
- Train_dataset.json
- val_dataset.json
- test_dataset.json
Intestine. Fahren wir mit dem Datenexplorationsprozess fort.
Datenexploration
Laden wir nun einen von ihnen, um die Struktur des Datensatzes zu sehen.
with open('train_dataset.json', 'r') as f:
train_data = json.load(f)
df = pd.DataFrame(train_data).dropna().reset_index(drop=True)
df.head()
Hier ist die Ausgabe.

Intestine, lass uns die Spalten sehen.
Hier ist die Ausgabe.

Lassen Sie uns nun die numerischen Spalten überprüfen.
Hier ist die Ausgabe.

Datenexploration mit __slots__ gegen reguläre Klassen
Lassen Sie uns eine Klasse namens SlottedDataExploration erstellen, die das verwenden wird __slots__ Attribut. Es ermöglicht nur ein Attribut namens DF. Lassen Sie uns den Code sehen.
class SlottedDataExploration:
__slots__ = ('df')
def __init__(self, df):
self.df = df
def data(self):
return self.df.data()
def head(self, n=5):
return self.df.head(n)
def tail(self, n=5):
return self.df.tail(n)
def describe(self):
return self.df.describe(embrace="all")
Lassen Sie uns nun die Implementierung sehen und anstatt zu verwenden __slots__ Verwenden wir reguläre Klassen.
class DataExploration:
def __init__(self, df):
self.df = df
def data(self):
return self.df.data()
def head(self, n=5):
return self.df.head(n)
def tail(self, n=5):
return self.df.tail(n)
def describe(self):
return self.df.describe(embrace="all")
Sie können mehr darüber erfahren, wie Klassenmethoden dabei funktionieren Python -Klassenmethoden Führung.
Leistungsvergleich: Zeitbenchmark
Messen wir nun die Leistung, indem wir Zeit und Speicher messen.
import time
from pympler import asizeof # reminiscence measurement
start_normal = time.time()
de = DataExploration(df)
_ = de.head()
_ = de.tail()
_ = de.describe()
_ = de.data()
end_normal = time.time()
normal_duration = end_normal - start_normal
normal_memory = asizeof.asizeof(de)
start_slotted = time.time()
sde = SlottedDataExploration(df)
_ = sde.head()
_ = sde.tail()
_ = sde.describe()
_ = sde.data()
end_slotted = time.time()
slotted_duration = end_slotted - start_slotted
slotted_memory = asizeof.asizeof(sde)
print(f"⏱️ Regular class length: {normal_duration:.4f} seconds")
print(f"⏱️ Slotted class length: {slotted_duration:.4f} seconds")
print(f"📦 Regular class reminiscence utilization: {normal_memory:.2f} bytes")
print(f"📦 Slotted class reminiscence utilization: {slotted_memory:.2f} bytes")
Jetzt sehen wir das Ergebnis.

Die Dauer der Schlitzklassen beträgt 46,45% schneller, aber die Speicherverwendung ist für dieses Beispiel dieselbe.
Maschinelles Lernen in Aktion
Lassen Sie uns nun in diesem Abschnitt mit dem maschinellen Lernen fortfahren. Aber bevor wir dies tun, machen wir einen Zug und testen wir.
Trainieren und testen aufgeteilt
Jetzt haben wir drei verschiedene Datensätze, Zug, Val und Take a look at, additionally finden wir zuerst ihre Indizes.
train_indeces = train_df.dropna().index
val_indeces = val_df.dropna().index
test_indeces = test_df.dropna().index
Jetzt ist es Zeit, diese Indizes zuzuweisen, um diese Datensätze im nächsten Schritt problemlos auszuwählen.
train_df = new_df.loc(train_indeces)
val_df = new_df.loc(val_indeces)
test_df = new_df.loc(test_indeces)
Großartig, jetzt formatieren wir diese Datenrahmen, weil Numpy das flache (n,) Format anstelle von
die (n, 1). Dazu müssen wir .Ravel () nach to_numpy () verwenden.
X_train, X_val, X_test = train_df(selected_features).to_numpy(), val_df(selected_features).to_numpy(), test_df(selected_features).to_numpy()
y_train, y_val, y_test = df.loc(train_indeces)(label_col).to_numpy().ravel(), df.loc(val_indeces)(label_col).to_numpy().ravel(), df.loc(test_indeces)(label_col).to_numpy().ravel()
Anwendung maschineller Lernmodelle
import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.ensemble import ExtraTreesRegressor
from sklearn.ensemble import VotingRegressor
from sklearn import linear_model
from sklearn.neural_network import MLPRegressor
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler, MaxAbsScaler
import matplotlib.pyplot as plt
from sklearn import tree
import seaborn as sns
def rmse(y_true, y_pred):
return mean_squared_error(y_true, y_pred, squared=False)
def regression(regressor_name, regressor):
pipe = make_pipeline(MaxAbsScaler(), regressor)
pipe.match(X_train, y_train)
predicted = pipe.predict(X_test)
rmse_val = rmse(y_test, predicted)
print(regressor_name, ':', rmse_val)
pred_df(regressor_name+'_Pred') = predicted
plt.determine(regressor_name)
plt.title(regressor_name)
plt.xlabel('predicted')
plt.ylabel('precise')
sns.regplot(y=y_test,x=predicted)
Als nächstes werden wir ein Wörterbuch der Regressoren definieren und jedes Modell ausführen.
regressors = {
'Linear' : LinearRegression(),
'MLP': MLPRegressor(random_state=42, max_iter=500, learning_rate="fixed", learning_rate_init=0.6),
'DecisionTree': DecisionTreeRegressor(max_depth=15, random_state=42),
'RandomForest': RandomForestRegressor(random_state=42),
'GradientBoosting': GradientBoostingRegressor(random_state=42, criterion='squared_error',
loss="squared_error",learning_rate=0.6, warm_start=True),
'ExtraTrees': ExtraTreesRegressor(n_estimators=100, random_state=42),
}
pred_df = pd.DataFrame(columns =("Precise"))
pred_df("Precise") = y_test
for key in regressors.keys():
regression(key, regressors(key))
Hier sind die Ergebnisse.

Implementieren Sie dies nun sowohl mit Slots als auch mit regulären Klassen.
Maschinelles Lernen mit __slots__ gegen reguläre Klassen
Überprüfen Sie nun den Code mit Slots.
class SlottedMachineLearning:
__slots__ = ('X_train', 'y_train', 'X_test', 'y_test', 'pred_df')
def __init__(self, X_train, y_train, X_test, y_test):
self.X_train = X_train
self.y_train = y_train
self.X_test = X_test
self.y_test = y_test
self.pred_df = pd.DataFrame({'Precise': y_test})
def rmse(self, y_true, y_pred):
return mean_squared_error(y_true, y_pred, squared=False)
def regression(self, title, mannequin):
pipe = make_pipeline(MaxAbsScaler(), mannequin)
pipe.match(self.X_train, self.y_train)
predicted = pipe.predict(self.X_test)
self.pred_df(title + '_Pred') = predicted
rating = self.rmse(self.y_test, predicted)
print(f"{title} RMSE:", rating)
plt.determine(figsize=(6, 4))
sns.regplot(x=predicted, y=self.y_test, scatter_kws={"s": 10})
plt.xlabel('Predicted')
plt.ylabel('Precise')
plt.title(f'{title} Predictions')
plt.grid(True)
plt.present()
def run_all(self):
fashions = {
'Linear': LinearRegression(),
'MLP': MLPRegressor(random_state=42, max_iter=500, learning_rate="fixed", learning_rate_init=0.6),
'DecisionTree': DecisionTreeRegressor(max_depth=15, random_state=42),
'RandomForest': RandomForestRegressor(random_state=42),
'GradientBoosting': GradientBoostingRegressor(random_state=42, learning_rate=0.6, warm_start=True),
'ExtraTrees': ExtraTreesRegressor(n_estimators=100, random_state=42)
}
for title, mannequin in fashions.gadgets():
self.regression(title, mannequin)
Hier ist die reguläre Klassenanwendung.
class MachineLearning:
def __init__(self, X_train, y_train, X_test, y_test):
self.X_train = X_train
self.y_train = y_train
self.X_test = X_test
self.y_test = y_test
self.pred_df = pd.DataFrame({'Precise': y_test})
def rmse(self, y_true, y_pred):
return mean_squared_error(y_true, y_pred, squared=False)
def regression(self, title, mannequin):
pipe = make_pipeline(MaxAbsScaler(), mannequin)
pipe.match(self.X_train, self.y_train)
predicted = pipe.predict(self.X_test)
self.pred_df(title + '_Pred') = predicted
rating = self.rmse(self.y_test, predicted)
print(f"{title} RMSE:", rating)
plt.determine(figsize=(6, 4))
sns.regplot(x=predicted, y=self.y_test, scatter_kws={"s": 10})
plt.xlabel('Predicted')
plt.ylabel('Precise')
plt.title(f'{title} Predictions')
plt.grid(True)
plt.present()
def run_all(self):
fashions = {
'Linear': LinearRegression(),
'MLP': MLPRegressor(random_state=42, max_iter=500, learning_rate="fixed", learning_rate_init=0.6),
'DecisionTree': DecisionTreeRegressor(max_depth=15, random_state=42),
'RandomForest': RandomForestRegressor(random_state=42),
'GradientBoosting': GradientBoostingRegressor(random_state=42, learning_rate=0.6, warm_start=True),
'ExtraTrees': ExtraTreesRegressor(n_estimators=100, random_state=42)
}
for title, mannequin in fashions.gadgets():
self.regression(title, mannequin)
Leistungsvergleich: Zeitbenchmark
Vergleichen wir jetzt jeden Code mit dem, den wir im vorherigen Abschnitt gemacht haben.
import time
start_normal = time.time()
ml = MachineLearning(X_train, y_train, X_test, y_test)
ml.run_all()
end_normal = time.time()
normal_duration = end_normal - start_normal
normal_memory = (
ml.X_train.nbytes +
ml.X_test.nbytes +
ml.y_train.nbytes +
ml.y_test.nbytes
)
start_slotted = time.time()
sml = SlottedMachineLearning(X_train, y_train, X_test, y_test)
sml.run_all()
end_slotted = time.time()
slotted_duration = end_slotted - start_slotted
slotted_memory = (
sml.X_train.nbytes +
sml.X_test.nbytes +
sml.y_train.nbytes +
sml.y_test.nbytes
)
print(f"⏱️ Regular ML class length: {normal_duration:.4f} seconds")
print(f"⏱️ Slotted ML class length: {slotted_duration:.4f} seconds")
print(f"📦 Regular ML class reminiscence utilization: {normal_memory:.2f} bytes")
print(f"📦 Slotted ML class reminiscence utilization: {slotted_memory:.2f} bytes")
time_diff = normal_duration - slotted_duration
percent_faster = (time_diff / normal_duration) * 100
if percent_faster > 0:
print(f"✅ Slotted ML class is {percent_faster:.2f}% quicker than the common ML class.")
else:
print(f"ℹ️ No velocity enchancment with slots on this run.")
memory_diff = normal_memory - slotted_memory
percent_smaller = (memory_diff / normal_memory) * 100
if percent_smaller > 0:
print(f"✅ Slotted ML class makes use of {percent_smaller:.2f}% much less reminiscence than the common ML class.")
else:
print(f"ℹ️ No reminiscence financial savings with slots on this run.")
Hier ist die Ausgabe.

Abschluss
Durch Verhinderung der Schaffung von Dynamik __dict__ Für jeden Fall Python __slots__ sind sehr intestine darin, die Speicherverwendung zu reduzieren und das Attributzugriff zu beschleunigen. Sie haben gesehen, wie es in der Praxis sowohl durch Datenerforschung als auch durch maschinelle Lernaufgaben mit dem Actual Recruitment -Projekt von Allegro funktioniert.
In kleinen Datensätzen können die Verbesserungen gering sein. Da Daten jedoch skaliert werden, werden die Vorteile jedoch auffälliger, insbesondere in Speicher- oder leistungskritischen Anwendungen.
Nate Rosidi ist Datenwissenschaftler und in Produktstrategie. Er ist außerdem eine zusätzliche Professorin für Lehranalysen und Gründer von Stratascratch, einer Plattform, die Datenwissenschaftlern hilft, sich auf ihre Interviews mit echten Interviewfragen von High -Unternehmen vorzubereiten. Nate schreibt über die neuesten Traits auf dem Karrieremarkt, gibt Interviewberatung, teilt Datenwissenschaftsprojekte und deckt alles SQL ab.
