ist ein mathematisches System, in dem Zahlen nach Erreichen eines Wertes, der als Erreicht wird, zyklieren Modul. Das System wird häufig als „Uhrarithmetik“ bezeichnet, da analoge 12-Stunden-Uhren die Zeit darstellen. Dieser Artikel bietet einen konzeptionellen Überblick über die modulare Arithmetik und untersucht praktische Anwendungsfälle in der Datenwissenschaft.
Konzeptuelle Übersicht
Die Grundlagen
Die modulare Arithmetik definiert ein Operationssystem für Ganzzahlen, die auf einer bestimmten Ganzzahl basieren, die als Modul bezeichnet wird. Der Ausdruck x mod d entspricht dem Relaxation, der erhalten wurde, wenn X ist geteilt durch D. Wenn R ≡ x mod dDann R soll sein kongruent Zu x mod d. Mit anderen Worten, das bedeutet das R Und X unterscheiden sich durch ein Vielfachen von Doder das x – r ist teilbar durch D. Das Image ‚≡‘ (drei horizontale Linien) wird in der modularen Arithmetik anstelle von ‚=‘ verwendet, um zu betonen, dass wir uns eher mit Kongruenz als mit Gleichheit im üblichen Sinne befassen.
Zum Beispiel ist in Modulo 7 die Zahl 10 zu 3 übereinstimmend, da 10 geteilt durch 7 einen Relaxation von 3. 3. Additionally können wir 3 ≡ 10 schreiben Mod 7. Im Falle einer 12-Stunden-Uhr ist 2 Uhr morgens bis 14 Uhr kongruent (14 Jahre alt (14) Mod 12). In Programmiersprachen wie Python dient das Prozentzeichen (‚%‘) als Modul -Operator (z. B., z. 10 % 7 würde auf 3 bewerten).
Hier ist ein Video, das diese Konzepte genauer erklärt:
Lösung linearer Kongruenzen
A lineare Kongruenz Kann ein modularer Ausdruck der Type sein N ⋅ y ≡ X (Mod D), wo der Koeffizient NZiel Xund Modul D sind Ganzzahlen bekannt und die unbekannte Ganzzahl y hat einen Grad von einem (dh es ist nicht quadratisch, gewürzt und so weiter). Der Ausdruck 2017 ≤ y ≡ 2025 (mod 10000) ist ein Beispiel für eine lineare Kongruenz; Es heißt, wenn 2017 mit einer Ganzzahl multipliziert wird ydas Produkt hinterlässt einen Relaxation von 2025, wenn es durch 10000 geteilt wird. y im Ausdruck N ⋅ y ≡ X (Mod D), folgen Sie folgenden Schritten:
- Finde die Größter gemeinsamer Divisor (GCD) des Koeffizienten N und Modul Dauch als GCD geschrieben (NAnwesend D), was die größte optimistic Ganzzahl ist, die ein Teil des Teils von beiden ist N Und D. Der Erweiterter euklidischer Algorithmus kann verwendet werden, um die GCD effizient zu berechnen; Dies führt auch zu einem Kandidaten für N-1Die Modular Inverse des Koeffizienten N.
- Bestimmen Sie, ob eine Lösung vorhanden ist. Wenn das Ziel X ist durch GCD nicht teilbar (NAnwesend D), dann hat die Gleichung keine Lösung. Dies liegt daran, dass die Kongruenz nur lösbar ist, wenn das GCD das Ziel teilt.
- Vereinfachen Sie bei Bedarf den modularen Ausdruck, indem Sie den Koeffizienten teilen NZiel Xund Modul D von GCD (NAnwesend D), um das Drawback auf eine einfachere äquivalente Type zu reduzieren; Nennen wir diese vereinfachten Mengen N0Anwesend X0Und D0jeweils. Dies sorgt dafür N0 Und D0 Sind Coprime (dh 1 ist ihr einziger häufiger Divisor), der für die Suche nach einem modularen Inversen erforderlich ist.
- Berechnen Sie die modulare Inverse N0-1 von N0 Mod D0 (Wieder mit dem erweiterten euklidischen Algorithmus).
- Finden Sie eine Lösung für den unbekannten Wert y. Multiplizieren Sie dazu den modularen Inversen N0-1 durch das reduzierte Ziel X0 um eine gültige Lösung für zu erhalten y Mod D0.
- Wenn Sie schließlich auf dem Ergebnis von Schritt 5 aufbauen, erzeugen Sie alle möglichen Lösungen. Da die ursprüngliche Gleichung durch GCD reduziert wurde (NAnwesend D), Es gibt GCD (NAnwesend D) unterschiedliche Lösungen. Diese Lösungen sind durch den reduzierten Modul gleichmäßig auseinander geraten D0und alle sind in Bezug auf den ursprünglichen Modul gültig D.
Im Folgenden finden Sie eine Python -Implementierung des obigen Verfahrens:
def extended_euclidean_algorithm(a, b):
"""
Computes the best widespread divisor of optimistic integers a and b,
together with coefficients x and y such that: a*x + b*y = gcd(a, b)
"""
if b == 0:
return (a, 1, 0)
else:
gcd, x_prev, y_prev = extended_euclidean_algorithm(b, a % b)
x = y_prev
y = x_prev - (a // b) * y_prev
return (gcd, x, y)
def solve_linear_congruence(coefficient, goal, modulus):
"""
Solves the linear congruence: coefficient * y ≡ goal (mod modulus)
Returns all integer options for y with respect to the modulus.
"""
# Step 1: Compute the gcd
gcd, _, _ = extended_euclidean_algorithm(coefficient, modulus)
# Step 2: Test if an answer exists
if goal % gcd != 0:
print("No answer exists: goal will not be divisible by gcd.")
return None
# Step 3: Scale back the equation by gcd
reduced_coefficient = coefficient // gcd
reduced_target = goal // gcd
reduced_modulus = modulus // gcd
# Step 4: Discover the modular inverse of reduced_coefficient with respect to the reduced_modulus
_, inverse_reduced, _ = extended_euclidean_algorithm(reduced_coefficient, reduced_modulus)
inverse_reduced = inverse_reduced % reduced_modulus
# Step 5: Compute one answer
base_solution = (inverse_reduced * reduced_target) % reduced_modulus
# Step 6: Generate all options modulo the unique modulus
all_solutions = ((base_solution + i * reduced_modulus) % modulus for i in vary(gcd))
return all_solutions
Hier sind einige Beispieltests:
options = solve_linear_congruence(coefficient=2009, goal=2025, modulus=10000)
print(f"Options for y: {options}")
options = solve_linear_congruence(coefficient=20, goal=16, modulus=28)
print(f"Options for y: {options}")
Ergebnisse:
Options for y: (225)
Options for y: (5, 12, 19, 26)
In diesem Video wird erläutert, wie man lineare Kongruenzen genauer löst:
Datenwissenschaftswendungsfälle
Anwendungsfall 1: Characteristic Engineering
Die modulare Arithmetik hat eine Reihe interessanter Anwendungsfälle in der Datenwissenschaft. Ein intuitives ist im Kontext von Characteristic Engineering, um zyklische Merkmale wie Stunden des Tages zu codieren. Da die Zeit etwa alle 24 Stunden wickelt, kann die Behandlung von Stunden als lineare Werte Beziehungen falsch darstellen (z. B., 23 Uhr und 1 Uhr sind numerisch weit voneinander entfernt, aber zeitlich eng). Durch die Anwendung der modularen Codierung (z. B. mit Sinus- und Cosinus -Transformationen des Stundenmodulo 24) können wir die kreisförmige Zeit der Zeit bewahren und ermöglichen, maschinelles Lernen (ML) -Modelle zu erkennen, die Muster erkennen, die in bestimmten Zeiträumen wie Nacht wie Nacht auftreten. Der folgende Python -Code zeigt, wie eine solche Codierung implementiert werden kann:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# Instance: Listing of incident hours (in 24-hour format)
incident_hours = (22, 23, 0, 1, 2) # 10 PM to 2 AM
# Convert to a DataFrame
df = pd.DataFrame({'hour': incident_hours})
# Encode utilizing sine and cosine transformations
df('hour_sin') = np.sin(2 * np.pi * df('hour') / 24)
df('hour_cos') = np.cos(2 * np.pi * df('hour') / 24)
Der resultierende Datenrahmen df:
hour hour_sin hour_cos
0 22 -0.500000 0.866025
1 23 -0.258819 0.965926
2 0 0.000000 1.000000
3 1 0.258819 0.965926
4 2 0.500000 0.866025
Beachten Sie, wie sich die Verwendung von Sinus immer noch zwischen den Stunden vor und nach 12 unterscheidet (z. B. codiert 23 Uhr und 1 Uhr als -0,258819 bzw. 0,258819), während die Verwendung von Cosinus nicht (z. B. sowohl 23 Uhr als auch 1 Uhr auf 0,965926 zugeordnet ist. Die optimale Auswahl der Codierung hängt vom geschäftlichen Kontext ab, in dem das ML -Modell bereitgestellt werden soll. Letztendlich verbessert die Technik das Merkmalstechnik für Aufgaben wie Anomalie -Erkennung, Prognose und Klassifizierung, bei denen zeitliche Nähe wichtig ist.
In den folgenden Abschnitten werden wir zwei größere Verwendungsfälle für die Datenwissenschaft in der linearen Kongruenz betrachten y in modularen Ausdrücken der Type N ⋅ y ≡ X (Mod D).
Anwendungsfall 2: Umformung in verteilten Datenbanksystemen
In verteilten Datenbanken werden Daten häufig partitioniert (oder Sharded) über mehrere Knoten mit einer Hash -Funktion hinweg. Wenn sich die Anzahl der Scherben ändert – sagen wir aus D Zu D‘ – wir müssen Reshard Die Daten effizient, ohne alles von Grund auf neu aufzuholen.
Angenommen, jedes Datenelement wird wie folgt einer Scherbe zugewiesen:
shard = hash(key) mod d
Beim Umteilen von Gegenständen in einen neuen Satz von D‘ Scherben, wir möchten vielleicht die alten Shard -Indizes den neuen abbilden, die das Gleichgewicht bewahren und die Datenbewegung minimieren. Dies kann zur Lösung für die Lösung führen y im Ausdruck N ⋅ y ≡ X (Mod D), Wo:
- X ist der ursprüngliche Shard -Index,
- D ist die alte Anzahl von Scherben,
- N ist ein Skalierungsfaktor (oder Transformationskoeffizient),
- y ist der neue Shard -Index, für den wir lösen
Die Verwendung modularer Arithmetik in diesem Kontext sorgt dafür, dass die konsistente Zuordnung zwischen alten und neuen Shard -Layouts, minimiert die Neuzuweisung, bewahrt die Datenlokalität und ermöglicht deterministische und reversible Transformationen während der Umformung.
Unten finden Sie eine Python -Implementierung dieses Szenarios:
def extended_euclidean_algorithm(a, b):
"""
Computes gcd(a, b) and coefficients x, y such that: a*x + b*y = gcd(a, b)
Used to search out modular inverses.
"""
if b == 0:
return (a, 1, 0)
else:
gcd, x_prev, y_prev = extended_euclidean_algorithm(b, a % b)
x = y_prev
y = x_prev - (a // b) * y_prev
return (gcd, x, y)
def modular_inverse(a, m):
"""
Returns the modular inverse of a modulo m, if it exists.
"""
gcd, x, _ = extended_euclidean_algorithm(a, m)
if gcd != 1:
return None # Inverse does not exist if a and m usually are not coprime
return x % m
def reshard(old_shard_index, old_num_shards, new_num_shards):
"""
Maps an outdated shard index to a brand new one utilizing modular arithmetic.
Solves: n * y ≡ x (mod d)
The place:
x = old_shard_index
d = old_num_shards
n = new_num_shards
y = new shard index (to resolve for)
"""
x = old_shard_index
d = old_num_shards
n = new_num_shards
# Step 1: Test if modular inverse of n modulo d exists
inverse_n = modular_inverse(n, d)
if inverse_n is None:
print(f"No modular inverse exists for n = {n} mod d = {d}. Can't reshard deterministically.")
return None
# Step 2: Clear up for y utilizing modular inverse
y = (inverse_n * x) % d
return y
Beispieltest:
import hashlib
def custom_hash(key, num_shards):
hash_bytes = hashlib.sha256(key.encode('utf-8')).digest()
hash_int = int.from_bytes(hash_bytes, byteorder='huge')
return hash_int % num_shards
# Instance utilization
old_num_shards = 10
new_num_shards = 7
# Simulate resharding for a couple of keys
keys = ('user_123', 'item_456', 'session_789')
for key in keys:
old_shard = custom_hash(key, old_num_shards)
new_shard = reshard(old_shard, old_num_shards, new_num_shards)
print(f"Key: {key} | Outdated Shard: {old_shard} | New Shard: {new_shard}")
Beachten Sie, dass wir eine benutzerdefinierte Hash -Funktion verwenden, die in Bezug auf deterministisch ist key Und num_shards Um die Reproduzierbarkeit zu gewährleisten.
Ergebnisse:
Key: user_123 | Outdated Shard: 9 | New Shard: 7
Key: item_456 | Outdated Shard: 7 | New Shard: 1
Key: session_789 | Outdated Shard: 2 | New Shard: 6
Anwendungsfall 3: Differentiale Privatsphäre im Föderierten Lernen
Beim Föderierten Studying werden ML -Modelle auf dezentralen Geräten geschult und gleichzeitig die Privatsphäre der Benutzer erhalten. Differentiale Privatsphäre fügt Gradientenaktualisierungen Rauschen hinzu, um einzelne Beiträge über Geräte hinweg zu verdecken. Oft wird dieses Rauschen aus einer diskreten Verteilung abgetastet und muss modulo reduziert werden, um in begrenzte Bereiche zu passen.
Angenommen, ein Kunde sendet ein Replace Xund der Server wendet eine Transformation des Formulars an N ≤ (y + ok) ≡ X (Mod D), Wo:
- X ist das lautes Gradienten -Replace, das an den Server gesendet wird,
- y ist das ursprüngliche (oder wahre) Gradienten -Replace,
- ok ist der Rauschbegriff (zufällig aus einer Reihe von Ganzzahlen gezeichnet),
- N ist der Codierungsfaktor,
- D ist der Modul (z. B. Größe des endlichen Feldes oder Quantisierungsbereichs, in dem alle Operationen stattfinden)
Aufgrund der Datenschutzbekämpfung dieses Setups kann sich der Server nur wiederherstellen y + okdas laute Replace, aber nicht das wahre Replace y selbst.
Unten ist das jetzt beruhigte Python-Setup:
def extended_euclidean_algorithm(a, b):
if b == 0:
return a, 1, 0
else:
gcd, x_prev, y_prev = extended_euclidean_algorithm(b, a % b)
x = y_prev
y = x_prev - (a // b) * y_prev
return gcd, x, y
def modular_inverse(a, m):
gcd, x, _ = extended_euclidean_algorithm(a, m)
if gcd != 1:
return None
return x % m
Beispieltest Simulation einiger Purchasers:
import random
# Parameters
d = 97 # modulus (finite area)
noise_scale = 20 # controls magnitude of noise
# Simulated purchasers
purchasers = (
{"id": 1, "y": 12, "n": 17},
{"id": 2, "y": 23, "n": 29},
{"id": 3, "y": 34, "n": 41},
)
# Step 1: Purchasers add noise and masks their gradients
random.seed(10)
for shopper in purchasers:
noise = random.randint(-noise_scale, noise_scale)
shopper("noise") = noise
noisy_y = shopper("y") + noise
shopper("x") = (shopper("n") * noisy_y) % d
# Step 2: Server receives x, is aware of n, and recovers noisy gradients
for shopper in purchasers:
inv_n = modular_inverse(shopper("n"), d)
shopper("y_noisy") = (shopper("x") * inv_n) % d
# Output
print("Shopper-side masking with noise:")
for shopper in purchasers:
print(f"Shopper {shopper('id')}:")
print(f" True gradient y = {shopper('y')}")
print(f" Added noise = {shopper('noise')}")
print(f" Masked worth x = {shopper('x')}")
print(f" Recovered y + noise = {shopper('y_noisy')}")
print()
Ergebnisse:
Shopper-side masking with noise:
Shopper 1:
True gradient y = 12
Added noise = 16
Masked worth x = 88
Recovered y + noise = 28
Shopper 2:
True gradient y = 23
Added noise = -18
Masked worth x = 48
Recovered y + noise = 5
Shopper 3:
True gradient y = 34
Added noise = 7
Masked worth x = 32
Recovered y + noise = 41
Beachten Sie, dass der Server nur die lauten Gradienten anstelle der ursprünglichen abgeben kann.
Der Wrap
Die modulare Arithmetik mit ihrer eleganten zyklischen Struktur bietet weit mehr als nur eine clevere Möglichkeit, Zeit zu erzählen – sie untermauert einige der kritischsten Mechanismen in der modernen Datenwissenschaft. Durch die Erforschung modularer Transformationen und linearer Kongruenzen haben wir gesehen, wie dieses mathematische Rahmen zu einem leistungsstarken Werkzeug zur Lösung realer Probleme wird. In Anwendungsfällen, die so vielfältig wie Characteristic Engineering, Umformungen in verteilten Datenbanken und das Schutz der Privatsphäre des Benutzer durch differentielle Privatsphäre durch unterschiedliche Privatsphäre schützen, bietet modulare Arithmetik sowohl die Abstraktion als auch die Präzision, die zum Aufbau robuster, skalierbarer Systeme erforderlich ist. Während sich die Datenwissenschaft weiterentwickelt, wird die Relevanz dieser modularen Techniken wahrscheinlich wachsen, was darauf hindeutet, dass der Schlüssel zu Innovation manchmal im Relaxation liegt.
