Skip to content

Commit 551ab5a

Browse files
committed
Merge branch 'feature/21.4_update' into 'release/v0.21.4'
0.21.4 features & fixes See merge request ai-lab-pmo/mltools/recsys/RePlay!348
2 parents 37a96c3 + a582787 commit 551ab5a

8 files changed

Lines changed: 152 additions & 139 deletions

File tree

projects/pyproject.toml.template

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ priority = "explicit"
127127

128128
[tool.poetry-dynamic-versioning]
129129
enable = true
130-
format-jinja = """0.21.3{{ env['PACKAGE_SUFFIX'] }}"""
130+
format-jinja = """0.21.4{{ env['PACKAGE_SUFFIX'] }}"""
131131
vcs = "git"
132132

133133
[tool.ruff]

replay/data/nn/parquet/parquet_dataset.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ class ParquetDataset(IterableDataset):
4848
4949
* ``ParquetDataset`` supports only numeric values (boolean/integer/float),
5050
therefore, the data paths passed as arguments must contain encoded data.
51-
* For optimal performance, set the ``OMP_NUM_THREADS`` and ``ARROW_IO_THREADS`` to match
52-
the number of available CPU cores.
51+
* For achieving maximum performance, set the ARROW_NUM_THREADS and ARROW_IO_THREADS to match
52+
the number of available CPU cores and set the OMP_NUM_THREADS and MKL_NUM_THREADS to 1, also set
53+
*torch.set_num_threads(1)* and *torch.set_num_interop_threads(1)*.
5354
5455
"""
5556

replay/data/nn/parquet/parquet_module.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ class ParquetModule(L.LightningDataModule):
3030
3131
* ``ParquetModule`` supports only numeric values (boolean/integer/float),
3232
therefore, the data paths passed as arguments must contain encoded data.
33-
* For optimal performance, set the OMP_NUM_THREADS and ARROW_IO_THREADS to match
34-
the number of available CPU cores.
33+
* For achieving maximum performance, set the ARROW_NUM_THREADS and ARROW_IO_THREADS to match
34+
the number of available CPU cores and set the OMP_NUM_THREADS and MKL_NUM_THREADS to 1, also set
35+
*torch.set_num_threads(1)* and *torch.set_num_interop_threads(1)*.
3536
* It's possible to use all train/validate/test/predict splits, then paths to splits should be passed
3637
as corresponding arguments of ``ParquetModule``.
3738
Alternatively, all the paths to the splits may be not specified

replay/nn/lightning/callback/metrics_callback.py

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Any, Optional
1+
from typing import Optional
22

33
import lightning
44
import torch
@@ -62,29 +62,22 @@ def __init__(
6262
self._ground_truth_column = ground_truth_column
6363
self._train_column = train_column
6464

65-
def _get_dataloaders_size(self, dataloaders: Optional[Any]) -> list[int]:
66-
if isinstance(dataloaders, list):
67-
return [len(dataloader) for dataloader in dataloaders]
68-
return [len(dataloaders)]
69-
7065
def on_validation_epoch_start(
7166
self,
7267
trainer: lightning.Trainer,
7368
pl_module: LightningModule, # noqa: ARG002
7469
) -> None:
75-
self._dataloaders_size = self._get_dataloaders_size(trainer.val_dataloaders)
76-
self._metrics_builders = [
77-
TorchMetricsBuilder(self._metrics, self._ks, self._item_count) for _ in self._dataloaders_size
78-
]
79-
for builder in self._metrics_builders:
80-
builder.reset()
70+
self._epoch_start(dataloaders_size=trainer.num_val_batches)
8171

8272
def on_test_epoch_start(
8373
self,
8474
trainer: lightning.Trainer,
8575
pl_module: LightningModule, # noqa: ARG002
8676
) -> None:
87-
self._dataloaders_size = self._get_dataloaders_size(trainer.test_dataloaders)
77+
self._epoch_start(dataloaders_size=trainer.num_test_batches)
78+
79+
def _epoch_start(self, dataloaders_size: list[int]) -> None:
80+
self._dataloaders_size = dataloaders_size
8881
self._metrics_builders = [
8982
TorchMetricsBuilder(self._metrics, self._ks, self._item_count) for _ in self._dataloaders_size
9083
]
@@ -146,7 +139,6 @@ def _batch_end(
146139
self._metrics_builders[dataloader_idx].add_prediction(
147140
sampled_items, batch[self._ground_truth_column], batch.get(self._train_column)
148141
)
149-
150142
if batch_idx + 1 == self._dataloaders_size[dataloader_idx]:
151143
pl_module.log_dict(
152144
self._metrics_builders[dataloader_idx].get_metrics(),

replay/preprocessing/label_encoder.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -630,13 +630,22 @@ def partial_fit(self, df: DataFrameLike) -> "SequenceEncodingRule":
630630
return self
631631

632632
def _transform_spark(self, df: SparkDataFrame, default_value: Optional[int]) -> SparkDataFrame:
633+
fake_column_name = "__fake_column__"
634+
df = df.withColumn(fake_column_name, sf.rand(0).cast("string"))
635+
633636
other_columns = [col for col in df.columns if col != self._col]
634637

635638
mapping_on_spark = get_spark_session().createDataFrame(
636639
data=list(self.get_mapping().items()), schema=[self._col, self._target_col]
637640
)
641+
642+
array_size_column_name = "__array_size__"
643+
df_with_sz = df.withColumn(array_size_column_name, sf.size(self._col))
644+
empty_arrays = df_with_sz.filter(sf.col(array_size_column_name) == 0).drop(array_size_column_name)
645+
non_empty_arrays = df_with_sz.filter(sf.col(array_size_column_name) != 0).drop(array_size_column_name)
646+
638647
encoded_df = (
639-
df.select(*other_columns, sf.posexplode(self._col))
648+
non_empty_arrays.select(*other_columns, sf.posexplode(self._col))
640649
.withColumnRenamed("col", self._col)
641650
.join(mapping_on_spark, on=self._col, how="left")
642651
)
@@ -663,7 +672,9 @@ def _transform_spark(self, df: SparkDataFrame, default_value: Optional[int]) ->
663672
LabelEncoderTransformWarning,
664673
)
665674

666-
return result
675+
# for correct concatenation, it is necessary that the column schemes match
676+
empty_arrays = empty_arrays.withColumn(self._col, sf.col(self._col).cast(result.schema[self._col].dataType))
677+
return result.unionByName(empty_arrays).drop(fake_column_name)
667678

668679
def _transform_pandas(self, df: PandasDataFrame, default_value: Optional[int]) -> PandasDataFrame:
669680
mapping = self.get_mapping()

tests/experimental/preprocessing/test_sequence_generator.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,17 @@
1010
columns,
1111
columns_target,
1212
columns_target_list_len,
13+
data_target,
14+
data_target_ordered,
15+
data_target_ordered_list_len,
1316
schema_target,
1417
schema_target_list_len,
1518
simple_dataframe,
1619
simple_dataframe_additional,
20+
simple_dataframe_additional_data,
1721
simple_dataframe_additional_pandas,
1822
simple_dataframe_array,
23+
simple_dataframe_array_data,
1924
simple_dataframe_array_pandas,
2025
simple_dataframe_pandas,
2126
simple_dataframe_target,

tests/preprocessing/conftest.py

Lines changed: 74 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -785,31 +785,48 @@ def generate_random_string(length=10):
785785

786786

787787
@pytest.fixture(scope="module")
788-
def simple_dataframe_array(spark):
789-
columns_array = ["user_id", "item_id", "timestamp"]
790-
data_array = [
791-
(1, [2, 1, 0], 19842),
788+
def simple_dataframe_array_data():
789+
columns = ["user_id", "item_id", "timestamp"]
790+
data = [
791+
(1, [], 19842),
792792
(1, [4, 1], 19844),
793793
(1, [3, 1, 0], 19843),
794794
(1, [5, 1], 19845),
795-
(1, [6, 1, 0], 19846),
795+
(1, [], 19846),
796796
(1, [7, 1], 19847),
797797
(2, [1, 0, 1], 19841),
798-
(2, [2, 0], 19842),
798+
(2, [], 19842),
799799
(2, [3, 0, 1], 19843),
800800
(2, [4, 0], 19844),
801801
(3, [10, 0], 19844),
802802
(4, [11, 0, 1], 19843),
803803
(4, [12, 0], 19845),
804-
(1, [1, 0], 19841),
804+
(1, [], 19841),
805805
]
806-
return spark.createDataFrame(data_array, schema=columns_array)
806+
return data, columns
807+
808+
809+
@pytest.fixture(scope="module")
810+
def simple_dataframe_array(simple_dataframe_array_data, spark):
811+
data, columns = simple_dataframe_array_data
812+
return spark.createDataFrame(data, schema=columns)
813+
814+
815+
@pytest.fixture(scope="module")
816+
def simple_dataframe_array_pandas(simple_dataframe_array_data):
817+
data, columns = simple_dataframe_array_data
818+
return pd.DataFrame(data, columns=columns)
819+
820+
821+
@pytest.fixture(scope="module")
822+
def simple_dataframe_array_polars(simple_dataframe_array_pandas):
823+
return pl.from_pandas(simple_dataframe_array_pandas)
807824

808825

809826
@pytest.fixture(scope="module")
810-
def simple_dataframe_additional(spark):
811-
columns_additional = ["user_id", "item_id", "timestamp", "other_column"]
812-
data_additional = [
827+
def simple_dataframe_additional_data():
828+
columns = ["user_id", "item_id", "timestamp", "other_column"]
829+
data = [
813830
(1, 2, 19842, 0),
814831
(1, 4, 19844, 1),
815832
(1, 3, 19843, 0),
@@ -825,12 +842,24 @@ def simple_dataframe_additional(spark):
825842
(4, 12, 19845, 1),
826843
(1, 1, 19841, 1),
827844
]
828-
return spark.createDataFrame(data_additional, schema=columns_additional)
845+
return data, columns
829846

830847

831848
@pytest.fixture(scope="module")
832-
def simple_dataframe_target(spark, schema_target):
833-
data_target = [
849+
def simple_dataframe_additional(simple_dataframe_additional_data, spark):
850+
data, columns = simple_dataframe_additional_data
851+
return spark.createDataFrame(data, schema=columns)
852+
853+
854+
@pytest.fixture(scope="module")
855+
def simple_dataframe_additional_pandas(simple_dataframe_additional_data):
856+
data, columns = simple_dataframe_additional_data
857+
return pd.DataFrame(data, columns=columns)
858+
859+
860+
@pytest.fixture(scope="module")
861+
def data_target():
862+
return [
834863
(1, 4, 19844, [2], [19842]),
835864
(1, 3, 19843, [2, 4], [19842, 19844]),
836865
(1, 5, 19845, [2, 4, 3], [19842, 19844, 19843]),
@@ -842,12 +871,21 @@ def simple_dataframe_target(spark, schema_target):
842871
(2, 4, 19844, [1, 2, 3], [19841, 19842, 19843]),
843872
(4, 12, 19845, [11], [19843]),
844873
]
874+
875+
876+
@pytest.fixture(scope="module")
877+
def simple_dataframe_target(spark, data_target, schema_target):
845878
return spark.createDataFrame(data_target, schema=schema_target)
846879

847880

848881
@pytest.fixture(scope="module")
849-
def simple_dataframe_target_ordered(spark, schema_target):
850-
data_target_ordered = [
882+
def simple_dataframe_target_pandas(data_target, columns_target):
883+
return pd.DataFrame(data_target, columns=columns_target)
884+
885+
886+
@pytest.fixture(scope="module")
887+
def data_target_ordered():
888+
return [
851889
(1, 2, 19842, [1], [19841]),
852890
(1, 3, 19843, [1, 2], [19841, 19842]),
853891
(1, 4, 19844, [1, 2, 3], [19841, 19842, 19843]),
@@ -859,12 +897,21 @@ def simple_dataframe_target_ordered(spark, schema_target):
859897
(2, 4, 19844, [1, 2, 3], [19841, 19842, 19843]),
860898
(4, 12, 19845, [11], [19843]),
861899
]
900+
901+
902+
@pytest.fixture(scope="module")
903+
def simple_dataframe_target_ordered(spark, data_target_ordered, schema_target):
862904
return spark.createDataFrame(data_target_ordered, schema=schema_target)
863905

864906

865907
@pytest.fixture(scope="module")
866-
def simple_dataframe_target_ordered_list_len(spark, schema_target_list_len):
867-
data_target_ordered_list_len = [
908+
def simple_dataframe_target_ordered_pandas(data_target_ordered, columns_target):
909+
return pd.DataFrame(data_target_ordered, columns=columns_target)
910+
911+
912+
@pytest.fixture(scope="module")
913+
def data_target_ordered_list_len():
914+
return [
868915
(1, 2, 19842, [1], [19841], 1),
869916
(1, 3, 19843, [1, 2], [19841, 19842], 2),
870917
(1, 4, 19844, [1, 2, 3], [19841, 19842, 19843], 3),
@@ -876,9 +923,18 @@ def simple_dataframe_target_ordered_list_len(spark, schema_target_list_len):
876923
(2, 4, 19844, [1, 2, 3], [19841, 19842, 19843], 3),
877924
(4, 12, 19845, [11], [19843], 1),
878925
]
926+
927+
928+
@pytest.fixture(scope="module")
929+
def simple_dataframe_target_ordered_list_len(spark, data_target_ordered_list_len, schema_target_list_len):
879930
return spark.createDataFrame(data_target_ordered_list_len, schema=schema_target_list_len)
880931

881932

933+
@pytest.fixture(scope="module")
934+
def simple_dataframe_target_ordered_list_len_pandas(data_target_ordered_list_len, columns_target_list_len):
935+
return pd.DataFrame(data_target_ordered_list_len, columns=columns_target_list_len)
936+
937+
882938
@pytest.fixture(scope="module")
883939
def simple_dataframe_pandas(columns):
884940
data = [
@@ -910,106 +966,6 @@ def dataframe_not_implemented(simple_dataframe_pandas):
910966
return simple_dataframe_pandas.to_numpy()
911967

912968

913-
@pytest.fixture(scope="module")
914-
def simple_dataframe_array_pandas():
915-
columns_array = ["user_id", "item_id", "timestamp"]
916-
data_array = [
917-
(1, [2, 1, 0], 19842),
918-
(1, [4, 1], 19844),
919-
(1, [3, 1, 0], 19843),
920-
(1, [5, 1], 19845),
921-
(1, [6, 1, 0], 19846),
922-
(1, [7, 1], 19847),
923-
(2, [1, 0, 1], 19841),
924-
(2, [2, 0], 19842),
925-
(2, [3, 0, 1], 19843),
926-
(2, [4, 0], 19844),
927-
(3, [10, 0], 19844),
928-
(4, [11, 0, 1], 19843),
929-
(4, [12, 0], 19845),
930-
(1, [1, 0], 19841),
931-
]
932-
return pd.DataFrame(data_array, columns=columns_array)
933-
934-
935-
@pytest.fixture(scope="module")
936-
def simple_dataframe_array_polars(simple_dataframe_array_pandas):
937-
return pl.from_pandas(simple_dataframe_array_pandas)
938-
939-
940-
@pytest.fixture(scope="module")
941-
def simple_dataframe_additional_pandas():
942-
columns_additional = ["user_id", "item_id", "timestamp", "other_column"]
943-
data_additional = [
944-
(1, 2, 19842, 0),
945-
(1, 4, 19844, 1),
946-
(1, 3, 19843, 0),
947-
(1, 5, 19845, 1),
948-
(1, 6, 19846, 0),
949-
(1, 7, 19847, 1),
950-
(2, 1, 19841, 0),
951-
(2, 2, 19842, 0),
952-
(2, 3, 19843, 0),
953-
(2, 4, 19844, 1),
954-
(3, 10, 19844, 0),
955-
(4, 11, 19843, 1),
956-
(4, 12, 19845, 1),
957-
(1, 1, 19841, 1),
958-
]
959-
return pd.DataFrame(data_additional, columns=columns_additional)
960-
961-
962-
@pytest.fixture(scope="module")
963-
def simple_dataframe_target_pandas(columns_target):
964-
data_target = [
965-
(1, 4, 19844, [2], [19842]),
966-
(1, 3, 19843, [2, 4], [19842, 19844]),
967-
(1, 5, 19845, [2, 4, 3], [19842, 19844, 19843]),
968-
(1, 6, 19846, [2, 4, 3, 5], [19842, 19844, 19843, 19845]),
969-
(1, 7, 19847, [2, 4, 3, 5, 6], [19842, 19844, 19843, 19845, 19846]),
970-
(1, 1, 19841, [4, 3, 5, 6, 7], [19844, 19843, 19845, 19846, 19847]),
971-
(2, 2, 19842, [1], [19841]),
972-
(2, 3, 19843, [1, 2], [19841, 19842]),
973-
(2, 4, 19844, [1, 2, 3], [19841, 19842, 19843]),
974-
(4, 12, 19845, [11], [19843]),
975-
]
976-
return pd.DataFrame(data_target, columns=columns_target)
977-
978-
979-
@pytest.fixture(scope="module")
980-
def simple_dataframe_target_ordered_pandas(columns_target):
981-
data_target_ordered = [
982-
(1, 2, 19842, [1], [19841]),
983-
(1, 3, 19843, [1, 2], [19841, 19842]),
984-
(1, 4, 19844, [1, 2, 3], [19841, 19842, 19843]),
985-
(1, 5, 19845, [1, 2, 3, 4], [19841, 19842, 19843, 19844]),
986-
(1, 6, 19846, [1, 2, 3, 4, 5], [19841, 19842, 19843, 19844, 19845]),
987-
(1, 7, 19847, [2, 3, 4, 5, 6], [19842, 19843, 19844, 19845, 19846]),
988-
(2, 2, 19842, [1], [19841]),
989-
(2, 3, 19843, [1, 2], [19841, 19842]),
990-
(2, 4, 19844, [1, 2, 3], [19841, 19842, 19843]),
991-
(4, 12, 19845, [11], [19843]),
992-
]
993-
return pd.DataFrame(data_target_ordered, columns=columns_target)
994-
995-
996-
@pytest.fixture(scope="module")
997-
def simple_dataframe_target_ordered_list_len_pandas(columns_target_list_len):
998-
data_target_ordered_list_len = [
999-
(1, 2, 19842, [1], [19841], 1),
1000-
(1, 3, 19843, [1, 2], [19841, 19842], 2),
1001-
(1, 4, 19844, [1, 2, 3], [19841, 19842, 19843], 3),
1002-
(1, 5, 19845, [1, 2, 3, 4], [19841, 19842, 19843, 19844], 4),
1003-
(1, 6, 19846, [1, 2, 3, 4, 5], [19841, 19842, 19843, 19844, 19845], 5),
1004-
(1, 7, 19847, [2, 3, 4, 5, 6], [19842, 19843, 19844, 19845, 19846], 5),
1005-
(2, 2, 19842, [1], [19841], 1),
1006-
(2, 3, 19843, [1, 2], [19841, 19842], 2),
1007-
(2, 4, 19844, [1, 2, 3], [19841, 19842, 19843], 3),
1008-
(4, 12, 19845, [11], [19843], 1),
1009-
]
1010-
return pd.DataFrame(data_target_ordered_list_len, columns=columns_target_list_len)
1011-
1012-
1013969
@pytest.fixture(scope="module")
1014970
def dataframe_sessionizer(spark):
1015971
columns = ["user_id", "item_id", "timestamp"]

0 commit comments

Comments
 (0)