Skip to content

Commit

Permalink
reformat tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mdekstrand committed Nov 11, 2023
1 parent 2a4c190 commit 2c1adf8
Show file tree
Hide file tree
Showing 33 changed files with 926 additions and 874 deletions.
108 changes: 59 additions & 49 deletions tests/test_als_explicit.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@

_log = logging.getLogger(__name__)

simple_df = pd.DataFrame({'item': [1, 1, 2, 3],
'user': [10, 12, 10, 13],
'rating': [4.0, 3.0, 5.0, 2.0]})
simple_df = pd.DataFrame(
{"item": [1, 1, 2, 3], "user": [10, 12, 10, 13], "rating": [4.0, 3.0, 5.0, 2.0]}
)

methods = mark.parametrize('m', ['lu', 'cd'])
methods = mark.parametrize("m", ["lu", "cd"])


@methods
Expand Down Expand Up @@ -80,7 +80,7 @@ def test_als_predict_basic_for_new_ratings():

assert algo.bias.mean_ == approx(simple_df.rating.mean())

new_ratings = pd.Series([4.0, 5.0], index=[1, 2]) # items as index and ratings as values
new_ratings = pd.Series([4.0, 5.0], index=[1, 2]) # items as index and ratings as values

preds = algo.predict_for_user(15, [3], new_ratings)

Expand All @@ -100,7 +100,7 @@ def test_als_predict_basic_for_new_user_with_new_ratings():
preds = algo.predict_for_user(u, [i])

new_u_id = -1
new_ratings = pd.Series([4.0, 5.0], index=[1, 2]) # items as index and ratings as values
new_ratings = pd.Series([4.0, 5.0], index=[1, 2]) # items as index and ratings as values

new_preds = algo.predict_for_user(new_u_id, [i], new_ratings)

Expand All @@ -127,9 +127,13 @@ def test_als_predict_for_new_users_with_new_ratings():

user_data = ratings[ratings.user == u]

_log.debug("user_features from fit: " + str(algo.user_features_[algo.user_index_.get_loc(u), :]))
_log.debug(
"user_features from fit: " + str(algo.user_features_[algo.user_index_.get_loc(u), :])
)

new_ratings = pd.Series(user_data.rating.to_numpy(), index=user_data.item) # items as index and ratings as values
new_ratings = pd.Series(
user_data.rating.to_numpy(), index=user_data.item
) # items as index and ratings as values
new_preds = algo.predict_for_user(new_u_id, items, new_ratings)

_log.debug("preds: " + str(preds.values))
Expand Down Expand Up @@ -186,9 +190,13 @@ def test_als_predict_no_user_features_basic():

user_data = ratings[ratings.user == u]

_log.debug("user_features from fit: " + str(algo.user_features_[algo.user_index_.get_loc(u), :]))
_log.debug(
"user_features from fit: " + str(algo.user_features_[algo.user_index_.get_loc(u), :])
)

new_ratings = pd.Series(user_data.rating.to_numpy(), index=user_data.item) # items as index and ratings as values
new_ratings = pd.Series(
user_data.rating.to_numpy(), index=user_data.item
) # items as index and ratings as values
new_preds = algo_no_user_features.predict_for_user(new_u_id, items, new_ratings)

_log.debug("preds: " + str(preds.values))
Expand All @@ -209,8 +217,8 @@ def test_als_train_large():
assert algo.n_items == ratings.item.nunique()
assert algo.n_users == ratings.user.nunique()

icounts = ratings.groupby('item').rating.count()
isums = ratings.groupby('item').rating.sum()
icounts = ratings.groupby("item").rating.count()
isums = ratings.groupby("item").rating.sum()
is2 = isums - icounts * ratings.rating.mean()
imeans = is2 / (icounts + 5)
ibias = pd.Series(algo.bias.item_offsets_, index=algo.item_index_)
Expand All @@ -220,14 +228,14 @@ def test_als_train_large():

# don't use wantjit, use this to do a non-JIT test
def test_als_save_load():
original = als.BiasedMF(5, iterations=5, method='lu')
original = als.BiasedMF(5, iterations=5, method="lu")
ratings = lktu.ml_test.ratings
original.fit(ratings)

assert original.bias.mean_ == approx(ratings.rating.mean())

mod = pickle.dumps(original)
_log.info('serialized to %d bytes', len(mod))
_log.info("serialized to %d bytes", len(mod))

algo = pickle.loads(mod)
assert algo.bias.mean_ == original.bias.mean_
Expand All @@ -239,26 +247,26 @@ def test_als_save_load():
assert np.all(algo.user_index_ == original.user_index_)

# make sure it still works
preds = algo.predict_for_user(10, np.arange(0, 50, dtype='i8'))
preds = algo.predict_for_user(10, np.arange(0, 50, dtype="i8"))
assert len(preds) == 50


@mark.skipif(not binpickle, reason='binpickle not available')
@mark.skipif(not binpickle, reason="binpickle not available")
def test_als_binpickle(tmp_path):
"Test saving ALS with BinPickle"

original = als.BiasedMF(20, iterations=5, method='lu')
original = als.BiasedMF(20, iterations=5, method="lu")
ratings = lktu.ml_test.ratings
original.fit(ratings)

assert original.bias.mean_ == approx(ratings.rating.mean())

file = tmp_path / 'als.bpk'
file = tmp_path / "als.bpk"
binpickle.dump(original, file)

with binpickle.BinPickleFile(file) as bpf:
# the pickle data should be small
_log.info('serialized to %d pickle bytes', bpf.entries[-1].dec_length)
_log.info("serialized to %d pickle bytes", bpf.entries[-1].dec_length)
pickle_dis(bpf._read_buffer(bpf.entries[-1]))
assert bpf.entries[-1].dec_length < 2048

Expand All @@ -273,27 +281,27 @@ def test_als_binpickle(tmp_path):
assert np.all(algo.user_index_ == original.user_index_)

# make sure it still works
preds = algo.predict_for_user(10, np.arange(0, 50, dtype='i8'))
preds = algo.predict_for_user(10, np.arange(0, 50, dtype="i8"))
assert len(preds) == 50


@lktu.wantjit
@mark.slow
def test_als_method_match():
lu = als.BiasedMF(20, iterations=15, reg=(2, 0.001), method='lu', rng_spec=42)
cd = als.BiasedMF(20, iterations=20, reg=(2, 0.001), method='cd', rng_spec=42)
lu = als.BiasedMF(20, iterations=15, reg=(2, 0.001), method="lu", rng_spec=42)
cd = als.BiasedMF(20, iterations=20, reg=(2, 0.001), method="cd", rng_spec=42)

ratings = lktu.ml_test.ratings

timer = Stopwatch()
lu.fit(ratings)
timer.stop()
_log.info('fit with LU solver in %s', timer)
_log.info("fit with LU solver in %s", timer)

timer = Stopwatch()
cd.fit(ratings)
timer.stop()
_log.info('fit with CD solver in %s', timer)
_log.info("fit with CD solver in %s", timer)

assert lu.bias.mean_ == approx(ratings.rating.mean())
assert cd.bias.mean_ == approx(ratings.rating.mean())
Expand All @@ -307,60 +315,62 @@ def test_als_method_match():
cd_preds = cd.predict_for_user(u, items)
diff = lu_preds - cd_preds
adiff = np.abs(diff)
_log.info('user %s diffs: L2 = %f, min = %f, med = %f, max = %f, 90%% = %f', u,
np.linalg.norm(diff, 2),
np.min(adiff), np.median(adiff), np.max(adiff), np.quantile(adiff, 0.9))

preds.append(pd.DataFrame({
'user': u,
'item': items,
'lu': lu_preds,
'cd': cd_preds,
'adiff': adiff
}))
_log.info(
"user %s diffs: L2 = %f, min = %f, med = %f, max = %f, 90%% = %f",
u,
np.linalg.norm(diff, 2),
np.min(adiff),
np.median(adiff),
np.max(adiff),
np.quantile(adiff, 0.9),
)

preds.append(
pd.DataFrame({"user": u, "item": items, "lu": lu_preds, "cd": cd_preds, "adiff": adiff})
)

preds = pd.concat(preds, ignore_index=True)
_log.info('LU preds:\n%s', preds.lu.describe())
_log.info('CD preds:\n%s', preds.cd.describe())
_log.info('overall differences:\n%s', preds.adiff.describe())
_log.info("LU preds:\n%s", preds.lu.describe())
_log.info("CD preds:\n%s", preds.cd.describe())
_log.info("overall differences:\n%s", preds.adiff.describe())
# there are differences. our check: the 90% are under a quarter star
assert np.quantile(adiff, 0.9) <= 0.27


@mark.slow
@mark.eval
@mark.skipif(not lktu.ml100k.available, reason='ML100K data not present')
@mark.skipif(not lktu.ml100k.available, reason="ML100K data not present")
def test_als_batch_accuracy():
from lenskit.algorithms import bias
import lenskit.crossfold as xf
import lenskit.metrics.predict as pm

ratings = lktu.ml100k.ratings

lu_algo = als.BiasedMF(25, iterations=20, damping=5, method='lu')
cd_algo = als.BiasedMF(25, iterations=25, damping=5, method='cd')
lu_algo = als.BiasedMF(25, iterations=20, damping=5, method="lu")
cd_algo = als.BiasedMF(25, iterations=25, damping=5, method="cd")
# algo = bias.Fallback(svd_algo, bias.Bias(damping=5))

def eval(train, test):
_log.info('training LU')
_log.info("training LU")
lu_algo.fit(train)
_log.info('training CD')
_log.info("training CD")
cd_algo.fit(train)
_log.info('testing %d users', test.user.nunique())
_log.info("testing %d users", test.user.nunique())
return test.assign(lu_pred=lu_algo.predict(test), cd_pred=cd_algo.predict(test))

folds = xf.partition_users(ratings, 5, xf.SampleFrac(0.2))
preds = pd.concat(eval(train, test) for (train, test) in folds)
preds['abs_diff'] = np.abs(preds.lu_pred - preds.cd_pred)
_log.info('predictions:\n%s', preds.sort_values('abs_diff', ascending=False))
_log.info('diff summary:\n%s', preds.abs_diff.describe())
preds["abs_diff"] = np.abs(preds.lu_pred - preds.cd_pred)
_log.info("predictions:\n%s", preds.sort_values("abs_diff", ascending=False))
_log.info("diff summary:\n%s", preds.abs_diff.describe())

lu_mae = pm.mae(preds.lu_pred, preds.rating)
assert lu_mae == approx(0.73, abs=0.045)
cd_mae = pm.mae(preds.cd_pred, preds.rating)
assert cd_mae == approx(0.73, abs=0.045)

user_rmse = preds.groupby('user').apply(lambda df: pm.rmse(df.lu_pred, df.rating))
user_rmse = preds.groupby("user").apply(lambda df: pm.rmse(df.lu_pred, df.rating))
assert user_rmse.mean() == approx(0.94, abs=0.05)
user_rmse = preds.groupby('user').apply(lambda df: pm.rmse(df.cd_pred, df.rating))
user_rmse = preds.groupby("user").apply(lambda df: pm.rmse(df.cd_pred, df.rating))
assert user_rmse.mean() == approx(0.94, abs=0.05)
Loading

0 comments on commit 2c1adf8

Please sign in to comment.