Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Corrige zone_logement_social pour retourner un vecteur #1395

Merged
merged 5 commits into from
Jan 7, 2020

Conversation

bonjourmauko
Copy link
Member

@bonjourmauko bonjourmauko commented Jan 2, 2020

Fixes #1394

  • Amélioration technique.
  • Périodes concernées : toutes.
  • Zones impactées : model/prestations/logement_social.py.
  • Détails :
    • La formule zone_logement_social retournait un scalar numpy.ndarray[int].
    • Corrige zone_logement_social pour retourner un vecteur numpy.ndarray[bool].
    • Note : à partir de Numpy 1.18, l'utilisation de select avec un valeur non bool est dépréciée.

Ces changements :

  • Corrigent ou améliorent un calcul déjà existant.

Quelques conseils à prendre en compte :

Copy link
Contributor

@Morendil Morendil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Je recommanderais plutôt de dépublier la version de Core qui a causé la régression, puis d'analyser ce qui est nécessaire pour la compatibilité avec Numpy. Je trouve aussi qu'introduire Mypy n'est pas pertinent car en dehors du scope de cette PR.

@benjello
Copy link
Member

benjello commented Jan 2, 2020

@maukoquiroga : j'ai corrigé le test qui passe maintenant avec la version de core master et la version de la PR openfisca/openfisca-core#923.

Je te laisse choisir avec @Morendil la stratégie adéquate.

@bonjourmauko
Copy link
Member Author

Merci @Morendil

Je recommanderais plutôt de dépublier la version de Core qui a causé la régression.

👍

Puis d'analyser ce qui est nécessaire pour la compatibilité avec Numpy.

Tu dis appart de l'utilisation de numpy.select ?

Je trouve aussi qu'introduire MyPy n'est pas pertinent car en dehors du scope de cette PR.

La première chose que j'ai faite pour cibler le problème est de faire une hypothèse de signature.

Je trouve donc au moins les annotations de type utiles, même si le type checking n'est effectivement pas nécessaire (or j'ai l'ai utilisé dans la cadre de cette PR).

Tu dis d'enlever MyPy lui-même ou les annotations aussi ?

@bonjourmauko
Copy link
Member Author

Merci @benjello ! Si l'attendu de sortie est toujours un vector et pas un scalar, effectivement c'est la solution pertinente.

Peut-on assumer ça ? Si oui je change les PR correspondantes pour refléter ce fait.

@guillett @Morendil

@bonjourmauko
Copy link
Member Author

bonjourmauko commented Jan 3, 2020

@Morendil en suivant tes conseils, j'ai fait une analyse de compatibilité OpenFisca Core avec Numpy 1.18 : openfisca/openfisca-core#924.

Bien que le code concerné par le changement utilise quasi-exclusivement numpy.select, il y a des bouts du code pas testés. Le changement n'est, donc, pas safe.

TODO :

  • Dépublier la version de Core qui a causé le problème
  • Faire un analyse de compatibilité sur Core
  • Faire un analyse de compatibilité sur France

Au-delà de ces considérations, cette PR reste d'actualité, j'actualise juste la description.

Merci!

@bonjourmauko bonjourmauko changed the title Corrige les tests « logement social » qui échouent S'assure que zone_logement_social retourne un vecteur Jan 3, 2020
@bonjourmauko bonjourmauko changed the title S'assure que zone_logement_social retourne un vecteur Corrige zone_logement_social pour qu'elle retourne un vecteur Jan 3, 2020
@bonjourmauko bonjourmauko changed the title Corrige zone_logement_social pour qu'elle retourne un vecteur Corrige zone_logement_social pour retourner un vecteur Jan 3, 2020
@Morendil
Copy link
Contributor

Morendil commented Jan 4, 2020

A mon sens ce n'est pas une question de scalaire ou de vecteur; la version 1.18 de Numpy a supprimé la possibilité d'utiliser des entiers dans les vecteurs fournis à select et impose désormais d'utiliser des vecteurs correctement typés comme booléens.

C'est moins la compatibilité de Core avec Numpy 1.18 qui me pose souci que la compatibilité de France, et par extension des autres pays.

Cela me mettait mal à l'aise de savoir que dans beaucoup d'endroits dans France on utilise des sommes ou des multiplications pour manipuler des valeurs logiques; sachant cela je me serais attendu à ce que le problème soit beaucoup plus étendu.

Je suis agréablement surpris que la formule de zone_logement_social soit la seule affectée par ce changement, c'est une bonne nouvelle. Et pour les auteurs de formules il serait utile de documenter "comment réaliser des combinaisons complexes de vecteurs de valeurs logiques".

A mon avis il vaut mieux utiliser np.logical_or.reduce plutôt que sum et ensuite caster le résultat vers un dtype=bool: l'idée c'est bien de se dire que les vecteurs sont typés et qu'il faut les manipuler avec les primitives Numpy qui correspondent à leur type.

in_paris_communes_limitrophes = sum([depcom == commune_proche_paris for commune_proche_paris in paris_communes_limitrophes])
in_idf = sum([startswith(depcom, departement) for departement in departements_idf])
in_paris_communes_limitrophes = array(
sum(
Copy link
Contributor

@Morendil Morendil Jan 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Utiliser np.logical_or.reduce ; les array depcom == … sont de type booléen, c'est dommage de les forcer en valeurs entières puis refaire l'opération inverse.

in_paris_communes_limitrophes = np.logical_or.reduce([depcom == commune_proche_paris
                for commune_proche_paris in paris_communes_limitrophes])

…mais d'ailleurs est-ce que Numpy ne propose pas une primitive pour tester l'appartenance d'une valeur à un ensemble ou à une liste ?

Copy link
Member Author

@bonjourmauko bonjourmauko Jan 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merci ! Si j'ai bien compris

np.logical_or.reduce

est l'équivalent de

np.any_(foo, axis = 0)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

…oui mais comme je le disais plus haut il est encore préférable d'utiliser np.isin que je découvre à l'instant dans Numpy:

>>> import numpy as np
>>> test_values = [3,5,7]
>>> a = np.array([1,2,3,4,5,6,7,8,9,10])
>>> np.logical_or.reduce([a == v for v in test_values])
array([False, False,  True, False,  True, False,  True, False, False, False])
>>> np.isin(a,test_values)
array([False, False,  True, False,  True, False,  True, False, False, False])

…soit dans notre cas:

np.isin(depcom, paris_communes_limitrophes)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Soit l'exemple complet :

in_paris_communes_limitrophes = isin(depcom, paris_communes_limitrophes)
in_idf = isin([True], startswith(depcom, departements_idf))

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in_idf = isin([True], startswith(depcom, departements_idf))

Je pense que ce n'est pas correct. isin va renvoyer un vecteur de la même taille que son premier argument, donc un seul élément dans la formulation ci-dessus, même si le vecteur depcom a une taille différente de 1.

Là encore il vaut mieux utiliser une opération Numpy (vectorisée) sur les chaines, à la place de l'opération correspondante en Python; en fait ce qu'on veut c'est les 2 premiers caractères de depcom, qui correspondent au département. C'est numpy.char.ljust.

>>> a = np.array(["93451","75001","45001"])
>>> np.isin(np.char.ljust(a,2),["93","75"])
array([ True,  True, False])

Donc

in_idf = np.isin(np.char.ljust(depcom,2), departements_idf)

Tout ça me fait penser au passage à openfisca/openfisca-core#673 - on a eu tendance à sous-estimer l'importance pour les utilisateurs de comprendre le calcul vectoriel en général et Numpy en particulier.

Pour cette raison d'ailleurs je suis plus favorable à l'import en bloc import numpy as np (ou même comme recommandé par Matti import numpy) de préférence à l'import sélectif from numpy import (isin, char, …) de façon à mettre en évidence les portions du code qui appellent les primitives Numpy.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in_idf = np.isin(np.char.ljust(depcom,2), departements_idf)

👍

Pour cette raison d'ailleurs je suis plus favorable à l'import en bloc import numpy as np (ou même comme recommandé par Matti import numpy) de préférence à l'import sélectif from numpy import (isin, char, …)

C'est pour cela que j'essaie d'éviter les imports globaux :

from openfisca_france.model.base import *

Concernant l'import du module vs. l'import selectif, après lire cet article, je suis d'accord.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JE suis aussi pour virer les import globaux aussi souvent que possible

@benjello
Copy link
Member

benjello commented Jan 6, 2020

@maukoquiroga : je garderais l'ancienne convention de passer par des alias raccourcis (import numpy.isin as isin_ par exemple pour merger cette PR. Et surtout merger le calcul du taux marginal et de la tranche qu'attends @PhunkyBob.

Copy link
Member

@benjello benjello left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Voir mon commentaire (désolé).

@bonjourmauko
Copy link
Member Author

@benjello OK pour garder la convention et continuer la discussion sur #1398

@bonjourmauko bonjourmauko force-pushed the fix-select-numpy-error branch 2 times, most recently from fca398d to 2469a00 Compare January 6, 2020 22:04
@bonjourmauko bonjourmauko merged commit 1abc526 into master Jan 7, 2020
@bonjourmauko bonjourmauko deleted the fix-select-numpy-error branch January 7, 2020 00:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Tests échouent suite au passage à Numpy 1.18
3 participants