Feat/sum mult profiles#369
Conversation
|
Just a thought, but using a python loop to repeatedly call It could speed things up to copy all the underlying |
|
Upon further thought, mimicking the Sorry to be nosing in to this PR, I think the work you're doing is awesome! |
peterrrock2
left a comment
There was a problem hiding this comment.
Notes:
- Move to internal methods with guaranteed return types (e.g.
_sum_rank_profiles)
| def sum_profiles(profiles: Sequence[RankProfile | ScoreProfile]) -> RankProfile | ScoreProfile: | ||
| """ | ||
| Combines multiple PreferenceProfiles by combining their ball lists. | ||
|
|
||
| Args: | ||
| profiles (Sequence[PreferenceProfile]): The profiles to sum. | ||
|
|
||
| Returns: | ||
| PreferenceProfile: The combined preference profile. | ||
|
|
||
| Raises: | ||
| ValueError: Cannot sum an empty list of profiles. | ||
| TypeError: All profiles must be of the same type. | ||
| """ | ||
|
|
||
| from votekit.pref_profile.pref_profile import RankProfile, ScoreProfile | ||
|
|
||
| if len(profiles) == 0: | ||
| raise ValueError("Cannot sum an empty list of profiles.") | ||
|
|
||
| if len(profiles) == 1: | ||
| return profiles[0] |
There was a problem hiding this comment.
| def sum_profiles(profiles: Sequence[RankProfile | ScoreProfile]) -> RankProfile | ScoreProfile: | |
| """ | |
| Combines multiple PreferenceProfiles by combining their ball lists. | |
| Args: | |
| profiles (Sequence[PreferenceProfile]): The profiles to sum. | |
| Returns: | |
| PreferenceProfile: The combined preference profile. | |
| Raises: | |
| ValueError: Cannot sum an empty list of profiles. | |
| TypeError: All profiles must be of the same type. | |
| """ | |
| from votekit.pref_profile.pref_profile import RankProfile, ScoreProfile | |
| if len(profiles) == 0: | |
| raise ValueError("Cannot sum an empty list of profiles.") | |
| if len(profiles) == 1: | |
| return profiles[0] | |
| def sum_profiles(profiles: Sequence[RankProfile | ScoreProfile]) -> RankProfile | ScoreProfile: | |
| """ | |
| Combines multiple PreferenceProfiles by combining their ball lists. | |
| Args: | |
| profiles (Sequence[PreferenceProfile]): The profiles to sum. | |
| Returns: | |
| PreferenceProfile: A new PreferenceProfile object containing the combined preference profile. | |
| Raises: | |
| ValueError: Cannot sum an empty list of profiles. | |
| TypeError: All profiles must be of the same type. | |
| """ | |
| from votekit.pref_profile.pref_profile import RankProfile, ScoreProfile | |
| if len(profiles) == 0: | |
| raise ValueError("Cannot sum an empty list of profiles.") | |
| if len(profiles) == 1: | |
| return profiles[0] # Change to copy. Might be worth adding a __copy__ method |
There was a problem hiding this comment.
Added a copy method to RankProfile and ScoreProfile. Updated the return comment
No worries @EdouardHeitzmann. Thank you for including your input! |
peterrrock2
left a comment
There was a problem hiding this comment.
Just a couple of quick things on this!
| total_cand = set().union(*[set(profile.candidates) for profile in score_profiles]) | ||
| total_dfs = [] | ||
| for p in score_profiles: | ||
| curr_df = p.df.copy() | ||
| curr_cand = set(p.candidates) | ||
| for cand in total_cand - curr_cand: | ||
| curr_df[cand] = [np.nan] * len(curr_df) | ||
| total_dfs.append(curr_df) |
There was a problem hiding this comment.
We could speed this up a little bit by not copying the dataframes that already contain a score for every candidate in total_cand. Avoids a secondary df copy.
There was a problem hiding this comment.
Did not copy the data frame if they already contain a score for each candidate or the same ranking length for summing ScoreProfiles and RankProfiles respectively.
| max_ranking_length=3, | ||
| ) | ||
| summed_profile = sum_profiles([profile]) | ||
| assert summed_profile == profile |
There was a problem hiding this comment.
| assert summed_profile == profile | |
| assert summed_profile == profile | |
| assert id(summed_profile) != id(profile) # make sure that we return a copy |
| candidates=["A", "B", "C", "D"], | ||
| ) | ||
| summed_profile = sum_profiles([profile]) | ||
| assert summed_profile == profile |
There was a problem hiding this comment.
| assert summed_profile == profile | |
| assert summed_profile == profile | |
| assert id(summed_profile) != id(profile) |
Closes #331
Adds a utility method 'sum_profiles' for summing a list of profiles (RankProfile or ScoreProfile).
Implementation
Iterates through the list and accumulates with
+, delegating the actual combination to the existing__add__methods onRankProfileandScoreProfile.Raises
ValueErroron empty list because the correct empty profile type can't be inferred. RaisesTypeErrorif a mix of RankProfiles and ScoreProfiles are given as input. Checks before iterating through list to avoid performing unnecessary adds.Tests
Added test cases for:
sum_profiles([...])with an empty listsum_profiles([...])with a list of 1 profilesum_profiles([...])with a list of mixed ScoreProfiles and RankProfilessum_profiles([...])for list of ScoreProfiles and list of RankProfiles