by Anonymous » 17 Mar 2025, 14:26
Beginnend mit dem folgenden Beispiel: < /p>
Code: Select all
import time
import numpy as np
import polars as pl
n_index = 1000
n_a = 10
n_b = 500
n_obs = 5000000
df = pl.DataFrame(
{
"id": np.random.randint(0, n_index, size=n_obs),
"a": np.random.randint(0, n_a, size=n_obs),
"b": np.random.randint(0, n_b, size=n_obs),
"x": np.random.normal(0, 1, n_obs),
}
).lazy()
dfs = [
pl.DataFrame(
{
"id": np.random.randint(0, n_index, size=n_obs),
"a": np.random.randint(0, n_a, size=n_obs),
f"b_{i}": np.random.randint(0, n_b, size=n_obs),
"x": np.random.normal(0, 1, n_obs),
}
).lazy()
for i in range(50)
]
res = [
df.join(
dfs[i], left_on=["id", "a", "b"], right_on=["id", "a", f"b_{i}"], how="inner"
)
.group_by("a", "b")
.agg((pl.col("x") * pl.col("x_right")).sum().alias(f"x_{i}"))
for i in range(50)
]
< /code>
Die Aufgabe verarbeitet wirklich verschiedene Datenrahmen, führen einige Berechnungen auf und verbinden Sie dann alle Ergebnisse. Der obige Code erstellt res
, der alle Ergebnisse als Liste enthält.
Code: Select all
start = time.perf_counter()
res2 = pl.collect_all(res)
res3 = res2[0]
for i in range(1, 50):
res3 = res3.join(res2[i], on=["a", "b"])
time.perf_counter() - start
< /code>
Option 2: < /p>
start = time.perf_counter()
res4 = res[0]
for i in range(1, 50):
res4 = res4.join(res[i], on=["a", "b"])
res4 = res4.collect()
time.perf_counter() - start
Option 1 sammelt_all zuerst alle einzelnen Datenrahmen an. Meine Benchmarking -Ergebnisse zeigen jedoch, dass
Option 2 Option 2 doppelt so lang wie Option 1 (21s gegenüber 10s auf meinem System mit 32 Kernen) . Oder gibt es einige Ineffizienzen in Bezug auf den Ansatz, den ich gewählt habe? Aber aus meinem Experiment wird die Leistung durch viel geopfert.
fragt sich, ob es eine Möglichkeit gibt, so etwas wie Option 2 zu tun, ohne die Leistung zu beeinträchtigen (Leistung vergleichbar mit Option 1)?
Beginnend mit dem folgenden Beispiel: < /p>
[code]import time
import numpy as np
import polars as pl
n_index = 1000
n_a = 10
n_b = 500
n_obs = 5000000
df = pl.DataFrame(
{
"id": np.random.randint(0, n_index, size=n_obs),
"a": np.random.randint(0, n_a, size=n_obs),
"b": np.random.randint(0, n_b, size=n_obs),
"x": np.random.normal(0, 1, n_obs),
}
).lazy()
dfs = [
pl.DataFrame(
{
"id": np.random.randint(0, n_index, size=n_obs),
"a": np.random.randint(0, n_a, size=n_obs),
f"b_{i}": np.random.randint(0, n_b, size=n_obs),
"x": np.random.normal(0, 1, n_obs),
}
).lazy()
for i in range(50)
]
res = [
df.join(
dfs[i], left_on=["id", "a", "b"], right_on=["id", "a", f"b_{i}"], how="inner"
)
.group_by("a", "b")
.agg((pl.col("x") * pl.col("x_right")).sum().alias(f"x_{i}"))
for i in range(50)
]
< /code>
Die Aufgabe verarbeitet wirklich verschiedene Datenrahmen, führen einige Berechnungen auf und verbinden Sie dann alle Ergebnisse. Der obige Code erstellt res [/code], der alle Ergebnisse als Liste enthält.[code]start = time.perf_counter()
res2 = pl.collect_all(res)
res3 = res2[0]
for i in range(1, 50):
res3 = res3.join(res2[i], on=["a", "b"])
time.perf_counter() - start
< /code>
Option 2: < /p>
start = time.perf_counter()
res4 = res[0]
for i in range(1, 50):
res4 = res4.join(res[i], on=["a", "b"])
res4 = res4.collect()
time.perf_counter() - start
[/code]
Option 1 sammelt_all zuerst alle einzelnen Datenrahmen an. Meine Benchmarking -Ergebnisse zeigen jedoch, dass [b] Option 2 Option 2 doppelt so lang wie Option 1 (21s gegenüber 10s auf meinem System mit 32 Kernen) [/b]. Oder gibt es einige Ineffizienzen in Bezug auf den Ansatz, den ich gewählt habe? Aber aus meinem Experiment wird die Leistung durch viel geopfert. [b] fragt sich, ob es eine Möglichkeit gibt, so etwas wie Option 2 zu tun, ohne die Leistung zu beeinträchtigen (Leistung vergleichbar mit Option 1)? [/b]