Organisation

Le 27 mars 2014, Logilab a accueilli un hackathon consacré aux codes libres de simulation des phénomènes mécaniques. Etaient présents:

  • Patrick Pizette, Sébastien Rémond (Ecole des Mines de Douai / DemGCE)
  • Frédéric Dubois, Rémy Mozul (LMGC Montpellier / LMGC90)
  • Mickaël Abbas, Mathieu Courtois (EDF R&D / Code_Aster)
  • Alexandre Martin (LAMSID / Code_Aster)
  • Luca Dall'Olio, Maximilien Siavelis (Alneos)
  • Florent Cayré, Nicolas Chauvat, Denis Laxalde, Alain Leufroy (Logilab)

DemGCE et LMGC90

Patrick Pizette et Sébastien Rémond des Mines de Douai sont venus parler de leur code de modélisation DemGCE de "sphères molles" (aussi appelé smooth DEM), des potentialités d'intégration de leurs algorithmes dans LMGC90 avec Frédéric Dubois du LMGC et de l'interface Simulagora développée par Logilab. DemGCE est un code DEM en 3D développé en C par le laboratoire des Mines de Douai. Il effectuera bientôt des calculs parallèles en mémoire partagée grâce à OpenMP. Après une présentation générale de LMGC90, de son écosystème et de ses applications, ils ont pu lancer leurs premiers calculs en mode dynamique des contacts en appelant via l'interface Python leurs propres configurations d'empilements granulaires.

Ils ont grandement apprécié l'architecture logicielle de LMGC90, et en particulier son utilisation comme une bibliothèque de calcul via Python, la prise en compte de particules de forme polyhédrique et les aspects visualisations avec Paraview. Il a été discuté de la réutilisation de la partie post/traitement visualisation via un fichier standard ou une bibliothèque dédiée visu DEM.

Frédéric Dubois semblait intéressé par l'élargissement de la communauté et du spectre des cas d'utilisation, ainsi que par certains algorithmes mis au point par les Mines de Douai sur la génération géométrique d'empilements. Il serait envisageable d'ajouter à LMGC90 les lois d'interaction de la "smooth DEM" en 3D, car elles ne sont aujourd'hui implémentées dans LMGC90 que pour les cas 2D. Cela permettrait de tester en mode "utilisateur" le code LMGC90 et de faire une comparaison avec le code des Mines de Douai (efficacité parallélisation, etc.).

Florent Cayré a fait une démonstration du potentiel de Simulagora.

LMGC90 et Code_Aster dans Debian

Denis Laxalde de Logilab a travaillé d'une part avec Rémy Mozul du LMGC sur l'empaquetage Debian de LMGC90 (pour intégrer en amont les modifications nécessaires), et d'autre part avec Mathieu Courtois d'EDF R&D, pour finaliser l'empaquetage de Code_Aster et notamment discuter de la problématique du lien avec la bibliothèque Metis: la version actuellement utilisée dans Code_Aster (Metis 4), n'est pas publiée dans une licence compatible avec la section principale de Debian. Pour cette raison, Code_Aster n'est pas compilé avec le support MED dans Debian actuellement. En revanche la version 5 de Metis a une licence compatible et se trouve déjà dans Debian. Utiliser cette version permettrait d'avoir Code_Aster avec le support Metis dans Debian. Cependant, le passage de la version 4 à la version 5 de Metis ne semble pas trivial.

Voir les tickets:

Replier LibAster dans Code_Aster

Alain Leufroy et Nicolas Chauvat de Logilab ont travaillé à transformer LibAster en une liste de pull request sur la forge bitbucket de Code_Aster. Ils ont présenté leurs modifications à Mathieu Courtois d'EDF R&D ce qui facilitera leur intégration.

Voir les tickets:

Suppression du superviseur dans Code_Aster

En fin de journée, Alain Leufroy, Nicolas Chauvat et Mathieu Courtois ont échangé leurs idées sur la simplification/suppression du superviseur de commandes actuel de Code_Aster. Il est souhaitable que la vérification de la syntaxe (choix des mots-clés) soit dissociée de l'étape d'exécution.

La vérification pourrait s'appuyer sur un outil comme pylint, la description de la syntaxe des commandes de Code_Aster pour pylint pourrait également permettre de produire un catalogue compréhensible par Eficas.

L'avantage d'utiliser pylint serait de vérifier le fichier de commandes avant l'exécution même si celui-ci contient d'autres instructions Python.

Allocation mémoire dans Code_Aster

Mickaël Abbas d'EDF R&D s'est intéressé à la modernisation de l'allocation mémoire dans Code_Aster et a listé les difficultés techniques à surmonter ; l'objectif visé est un accès facilité aux données numériques du Fortran depuis l'interface Python. Une des difficultés est le partage des types dérivés Fortran en Python. Rémy Mozul du LMGC et Denis Laxalde de Logilab ont exploré une solution technique basée sur Cython et ISO-C-Bindings. De son côté Mickaël Abbas a contribué à l'avancement de cette tâche directement dans Code_Aster.

Doxygen pour documentation des sources de Code_Aster

Luca Dall'Olio d'Alneos et Mathieu Courtois ont testé la mise en place de Doxygen pour documenter Code_Aster. Le fichier de configuration pour doxygen a été modifié pour extraire les commentaires à partir de code Fortran (les commentaires doivent se trouver au dessus de la déclaration de la fonction, par exemple). La configuration doxygen a été restituée dans le depôt Bitbucket. Reste à évaluer s'il y aura besoin de plusieurs configurations (pour la partie C, Python et Fortran) ou si une seule suffira. Une configuration particulière permet d'extraire, pour chaque fonction, les points où elle est appelée et les autres fonctions utilisées. Un exemple a été produit pour montrer comment écrire des équations en syntaxe Latex, la génération de la documentation nécessite plus d'une heure (seule la partie graphique peut être parallélisée). La documentation produite devrait être publiée sur le site de Code_Aster.

La suite envisagée est de coupler Doxygen avec Breathe et Sphinx pour compléter la documentation extraite du code source de textes plus détaillés.

La génération de cette documentation devrait être une cible de waf, par exemple waf doc. Un aperçu rapide du rendu de la documentation d'un module serait possible par waf doc file1.F90 [file2.c [...]].

Voir Code Aster #18 configure doxygen to comment the source files

Catalogue d'éléments finis

Maximilien Siavelis d'Alneos et Alexandre Martin du LAMSID, rejoints en fin de journée par Frédéric Dubois du LMGC ainsi que Nicolas Chauvat et Florent Cayré de Logilab, ont travaillé à faciliter la description des catalogues d'éléments finis dans Code_Aster. La définition de ce qui caractérise un élément fini a fait l'objet de débats passionnés. Les points discutés nourriront le travail d'Alexandre Martin sur ce sujet dans Code_Aster. Alexandre Martin a déjà renvoyé aux participants un article qu'il a écrit pour résumer les débats.

Remontée d'erreurs de fortran vers Python

Mathieu Courtois d'EDF R&D a montré à Rémy Mozul du LMGC un mécanisme de remontée d'exception du Fortran vers le Python, qui permettra d'améliorer la gestion des erreurs dans LMGC90, qui a posé problème dans un projet réalisé par Denis Laxalde de Logilab pour la SNCF.

Voir aster_exceptions.c

Conclusion

Tous les participants semblaient contents de ce deuxième hackathon, qui faisait suite à la première édition de mars 2013 . La prochaine édition aura lieu à l'automne 2014 ou au printemps 2015, ne la manquez pas !

blog entry of

Logilab.org - en VF

Ils étaient une vingtaine à se (re)trouver à l’occasion du premier apéritif & barcamp Open Science à Toulouse organisé par Logilab et Hack your PhD. La plupart étaient avant tout curieux de voir qui et quoi se cachaient derrière cette annonce :

un rendez-vous périodique, informel et sympathique a pour but de favoriser les échanges entre tous les acteurs intéressés par un aspect de l’Open Science : Open Data, les rapports Sciences & Société, Open Source, Open Access, Big Data & Data Science, etc.

Curieux souvent parce qu’ils s’étaient reconnus dans l’une ou l’autre – et souvent plusieurs – de ces facettes de l’Open Science sans avoir déjà rencontré l’étiquette Open Science pour autant.

Les échangent se nouent dans la communauté Open Science

Mais alors l’Open Science : c’est quoi ?

Heureusement personne n’a asséné de définition définitive. J’ai tenté de montrer, à travers une brève présentation de Hack your PhD et de Logilab comment l’Open Science est avant tout une démarche d’ouverture dans la pratique de la recherche scientifique qui s’étend au delà du cadre du laboratoire.

L’objectif de la soirée était de permettre à la communauté Open Science locale de se découvrir ; aux acteurs de science ou d’ouverture de faire connaissance. De fait les discussions et prises de contacts informelles allaient bon train autour d’un verre et quelques tapas… et c’est donc à chacun des participants de partager ses échanges sur le thème que fait-on à Toulouse ?

Le fournisseur d’accès associatif tetaneutral nous met à disposition une liste de diffusion à l’adresse open-science-toulouse@lists.tetaneutral.net. Merci à eux ! J’invite vivement les participants à l’apéro à s’y présenter en quelques mots : faites nous part de votre perception de cet événement et partager vos intérêts et projets.

On se retrouvera bientôt pour un prochain événement qui tiendra plus de l’atelier. Quelques suggestion qui sont dores et déjà apparues : un atelier sur les outils pratiques pour être ouvert, un séminaire dans un centre de recherche universitaire, un atelier sur les alignements de données publiques et l’évolutivité des schéma de données avec CubicWeb, …

Vos propositions sont très bienvenues : la communauté Open Science Toulousaine deviendra ce qu’ensemble nous en ferons !

Ce compte rendu a été initialement publié sur le site de hackyourphd : http://hackyourphd.org/2014/02/naissance-de-la-communaute-toulousaine/

blog entry of

Logilab.org - en VF

Last week, a new release of Code_Aster entered Debian unstable. Code_Aster is a finite element solver for partial differential equations in mechanics, mainly developed by EDF R&D (Électricité de France). It is arguably one of the most feature complete free software available in this domain.

Aster has been in Debian since 2012 thanks to the work of debian-science team. Yet it has always been somehow a problematic package with a couple of persistent Release Critical (RC) bugs (FTBFS, instalability issues) and actually never entered a stable release of Debian.

Logilab has committed to improving Code_Aster for a long time in various areas, notably through the LibAster friendly fork, which aims at turning the monolithic Aster into a library, usable from Python.

Recently, the EDF R&D team in charge of the development of Code_Aster took several major decisions, including:

  • the move to Bitbucket forge as a sign of community opening (following the path opened by LibAster that imported the code of Code_Aster into a Mercurial repository) and,
  • the change of build system from a custom makefile-style architecture to a fine-grained Waf system (taken from that of LibAster).

The latter obviously led to significant changes on the Debian packaging side, most of which going into a sane direction: the debian/rules file slimed down from 239 lines to 51 and a bunch of tricky install-step manipulations were dropped leading to something much simpler and closer to upstream (see #731211 for details). From upstream perspective, this re-packaging effort based on the new build-system may be the opportunity to update the installation scheme (in particular by declaring the Python library as private).

Clearly, there's still room for improvements on both side (like building with the new metis library, shipping several versions of Aster stable/testing, MPI/serial). All in all, this is good for both Debian users and upstream developers. At Logilab, we hope that this effort will consolidate our collaboration with EDF R&D.

blog entry of

Logilab.org - en

Hier soir, je suis allé au premier meetup Debian à Nantes. C'était bien sympatique, une vingtaine de personnes ont répondu présent à l'appel de Damien Raude-Morvan et Thomas Vincent. Merci à eux d'avoir lancé l'initiative (le pad d'organisation).

//www.logilab.org/file/228927/raw/debian-france.jpg

Après un tour de table des participants, et de quelques discussions sur debian en général (et une explication par Damien de l'état de Java dans Debian), Damien a présenté l'association Debian France ainsi que le concours du nouveau contributeur Debian. La liste d'idées est longue et sympatique n'hésitez pas à aller jeter un oeil et faire une contribution.

Ensuite Thomas nous a présenté l'équipe de traduction francaise de debian et ses principles de fonctionnement (qualité avant quantité, listes de discussion, IRC, processus de traduction, etc.).

//www.logilab.org/file/228931/raw/saltstack_logo.jpg

Finalement, j'ai rapidement présenté Salt et sa place dans Debian. Pour l'archive publique : les diapos de la présentation.

À la prochaine !

Pour faire un commentaire, il faut s'authentifier ou s'enregistrer.

blog entry of

Logilab.org - en VF

http://www.logilab.org/file/226609/raw/200px-Mini-debconf-paris.png

Nous sommes heureux d'avoir participé à la MiniDebConf Paris.

Nous avons sponsorisé l'évenement mais aussi effectué deux présentations :

Avec une cinquantaine de participants sur les deux jours, c'est toujours agréable de rencontrer la communauté francaise autour de Debian. Merci donc à l'association Debian France d'avoir organisé cette conférence.

blog entry of

Logilab.org - en VF

On the 6th of February, the Salt community in France met in Paris to discuss Salt and choose the tools to federate itself. The meetup was kindly hosted by IRILL.

There were two formal presentations :

  • Logilab did a short introduction of Salt,
  • Majerti presented a feedback of their experience with Salt in various professional contexts.

The presentation space was then opened to other participants and Boris Feld did a short presentation of how Salt was used at NovaPost.

http://www.logilab.org/file/226420/raw/saltstack_meetup.jpeg

We then had a short break to share some pizza (sponsored by Logilab).

After the break, we had some open discussion about various subjects, including "best practices" in Salt and some specific use cases. Regis Leroy talked about the states that Makina Corpus has been publishing on github. The idea of reconciling the documentation and the monitoring of an infrastructure was brought up by Logilab, that calls it "Test Driven Infrastructure".

The tools we collectively chose to form the community were the following :

  • a mailing-list kindly hosted by the AFPY (a pythonic french organization)
  • a dedicated #salt-fr IRC channel on freenode

We decided that the meetup would take place every two months, hence the third one will be in April. There is already some discussion about organizing events to tell as many people as possible about Salt. It will probably start with an event at NUMA in March.

After the meetup was officially over, a few people went on to have some drinks nearby. Thank you all for coming and your participation.

login or register to comment on this blog

blog entry of

Logilab.org - en

I attended PGDay on January 31st, in Brussels. This event was held just before FOSDEM, which I also attended (expect another blog post). Here are some of the notes I took during the conference.

https://fosdem.org/2014/support/promote/wide.png

Statistics in PostgreSQL, Heikki Linnakangas

Due to transit delays, I only caught the last half of that talk.

The main goal of this talk was to explain some of Postgres' per-column statistics. In a nutshell, Postgres needs to have some idea about tables' content in order to choose an appropriate query plan.

Heikki explained which sorts of statistics gathers, such as most common values and histograms. Another interesting stat is the correlation between physical pages and data ordering (see CLUSTER).

Column statistics are gathered when running ANALYZE and stored in the pg_statistic system catalog. The pg_stats view provides a human-readable version of these stats.

Heikki also explained how to determine whether performance issues are due to out-of-date statistics or not. As it turns out, EXPLAIN ANALYZE shows for each step of the query planner how many rows it expects to process and how many it actually processed. The rule of thumb is that similar values (no more than an order of magnitude apart) mean that column statistics are doing their job. A wider margin between expected and actual rows mean that statistics are possibly preventing the query planner from picking a more optimized plan.

It was noted though that statistics-related performance issues often happen on tables with very frequent modifications. Running ANALYZE manually or increasing the frequency of the automatic ANALYZE may help in those situations.

Advanced Extension Use Cases, Dimitri Fontaine

Dimitri explained with very simple cases the use of some of Postgres' lesser-known extensions and the overall extension mechanism.

Here's a grocery-list of the extensions and types he introduced:

  • intarray extension, which adds operators and functions to the standard ARRAY type, specifically tailored for arrays of integers,
  • the standard POINT type which provides basic 2D flat-earth geometry,
  • the cube extension that can represent N-dimensional points and volumes,
  • the earthdistance extension that builds on cube to provide distance functions on a sphere-shaped Earth (a close-enough approximation for many uses),
  • the pg_trgm extension which provides text similarity functions based on trigram matching (a much simpler thus faster alternative to Levenshtein distances), especially useful for "typo-resistant" auto-completion suggestions,
  • the hstore extension which provides a simple-but-efficient key value store that has everyone talking in the Postgres world (it's touted as the NoSQL killer),
  • the hll extensions which implements the HyperLogLog algorithm which seems very well suited to storing and counting unique visitor on a web site, for example.

An all-around great talk with simple but meaningful examples.

http://tapoueh.org/images/fosdem_2014.jpg

Integrated cache invalidation for better hit ratios, Magnus Hagander

What Magnus presented almost amounted to a tutorial on caching strategies for busy web sites. He went through simple examples, using the ubiquitous Django framework for the web view part and Varnish for the HTTP caching part.

The whole talk revolved around adding private (X-prefixed) HTTP headers in replies containing one or more "entity IDs" so that Varnish's cache can be purged whenever said entities change. The hard problem lies in how and when to call PURGE on Varnish.

The obvious solution is to override Django's save() method on Model-derived objects. One can then use httplib (or better yet requests) to purge the cache. This solution can be slightly improved by using Django's signal mechanism instead, which sound an awful-lot like CubicWeb's hooks.

The problem with the above solution is that any DB modification not going through Django (and they will happen) will not invalidate the cached pages. So Magnus then presented how to write the same cache-invalidating code in PL/Python in triggers.

While this does solve that last issue, it introduces synchronous HTTP calls in the DB, killing write performance completely (or killing it completely if the HTTP calls fail). So to fix those problems, while introducing limited latency, is to use SkyTools' PgQ, a simple message queue based on Postgres. Moving the HTTP calls outside of the main database and into a Consumer (a class provided by PgQ's python bindings) makes the cache-invalidating trigger asynchronous, reducing write overhead.

http://www.logilab.org/file/210615/raw/varnish_django_postgresql.png

A clear, concise and useful talk for any developer in charge of high-traffic web sites or applications.

The Worst Day of Your Life, Christophe Pettus

Christophe humorously went back to that dreadful day in the collective Postgres memory: the release of 9.3.1 and the streaming replication chaos.

My overall impression of the talk: Thank $DEITY I'm not a DBA!

But Christophe also gave some valuable advice, even for non-DBAs:

  • Provision 3 times the necessary disk space, in case you need to pg_dump or otherwise do a snapshot of your currently running database,
  • Do backups and test them:
    • give them to developers,
    • use them for analytics,
    • test the restore, make it foolproof, try to automate it,
  • basic Postgres hygiene:
    • fsync = on (on by default, DON'T TURN IT OFF, there are better ways)
    • full_page_writes = on (on by default, don't turn it off)
    • deploy minor versions as soon as possible,
    • plan upgrade strategies before EOL,
    • 9.3+ checksums (createdb option, performance cost is minimal),
    • application-level consistency checks (don't wait for auto vacuum to "discover" consistency errors).

Materialised views now and in the future, Thom Brown

Thom presented on of the new features of Postgres 9.3, materialized views.

In a nutshell, materialized views (MV) are read-only snapshots of queried data that's stored on disk, mostly for performance reasons. An interesting feature of materialized views is that they can have indexes, just like regular tables.

The REFRESH MATERIALIZED VIEW command can be used to update an MV: it will simply run the original query again and store the new results.

There are a number of caveats with the current implementation of MVs:

  • pg_dump never saves the data, only the query used to build it,
  • REFRESH requires an exclusive lock,
  • due to implementation details (frozen rows or pages IIRC), MVs may exhibit non-concurrent behavior with other running transactions.

Looking towards 9.4 and beyond, here are some of the upcoming MV features:

  • 9.4 adds the CONCURRENTLY keyword:
    • + no longer needs an exclusive lock, doesn't block reads
    • - requires a unique index
    • - may require VACUUM
  • roadmap (no guarantees):
    • unlogged (disables the WAL),
    • incremental refresh,
    • lazy automatic refresh,
    • planner awareness of MVs (would use MVs as cache/index).

Indexes: The neglected performance all-rounder, Markus Winand

http://use-the-index-luke.com/img/alchemie.png

Markus' goal with this talk showed that very few people in the SQL world actually know - let alone really care - about indexes. According to his own experience and that of others (even with competing RDBMS), poorly written SQL is still a leading cause of production downtime (he puts the number at around 50% of downtime though others he quoted put that number higher). SQL queries can indeed put such stress on DB systems and cause them to fail.

One major issue, he argues, is poorly designed indexes. He went back in time to explain possible reasons for the lack of knowledge about indexes with both SQL developers and DBAs. One such reason may be that indexes are not part of the SQL standard and are left as implementation-specific details. Thus many books about SQL barely cover indexes, if at all.

He then took us through a simple quiz he wrote on the topic, with only 5 questions. The questions and explanations were very insightful and I must admit my knowledge of indexes was not up to par. I think everyone in the room got his message loud and clear: indexes are part of the schema, devs should care about them too.

Try out the test : http://use-the-index-luke.com/3-minute-test

PostgreSQL - Community meets Business, Michael Meskes

For the last talk of the day, Michael went back to the history of the Postgres project and its community. Unlike other IT domains such as email, HTTP servers or even operating systems, RDBMS are still largely dominated by proprietary vendors such as Oracle, IBM and Microsoft. He argues that the reasons are not technical: from a developer stand point, Postgres has all the features of the leading RDMBS (and many more) and the few missing administrative features related to scalability are being addressed.

Instead, he argues decision makers inside companies don't yet fully trust Postgres due to its (perceived) lack of corporate backers.

He went on to suggest ways to overcome those perceptions, for example with an "official" Postgres certification program.

A motivational talk for the Postgres community.

http://fosdem2014.pgconf.eu/files/img/frontrotate/slonik.jpg

blog entry of

Logilab.org - en

http://www.logilab.org/file/204916/raw/SaltStack-Logo.png

At Logilab, we've been using Salt for one year to manage our own infrastructure. I wanted to use it to manage a specific configuration: C++ development. When I instantiate a Virtual Machine with a Debian image, I don't want to spend time to install and configure a system which fits my needs as a C++ developer:

This article is a very simple recipe to get a C++ development environment, ready to use, ready to hack.

Give Me an Editor and a DVCS

Quite simple: I use the YAML file format used by Salt to describe what I want. To install these two editors, I just need to write:

vim-nox:
  pkg.installed

emacs23-nox:
  pkg.installed

For Mercurial, you'll guess:

mercurial:
 pkg.installed

You can write these lines in the same init.sls file, but you can also decide to split your configuration into different subdirectories: one place for each thing. I decided to create a dev and editor directories at the root of my salt config with two init.sls inside.

That's all for the editors. Next step: specific C++ development packages.

Install Several "C++" Packages

In a cpp folder, I write a file init.sls with this content:

gcc:
    pkg.installed

g++:
    pkg.installed

gdb:
    pkg.installed

cmake:
    pkg.installed

automake:
    pkg.installed

libtool:
    pkg.installed

pkg-config:
    pkg.installed

colorgcc:
    pkg.installed

The choice of these packages is arbitrary. You add or remove some as you need. There is not a unique right solution. But I want more. I want some LLVM packages. In a cpp/llvm.sls, I write:

llvm:
 pkg.installed

clang:
    pkg.installed

libclang-dev:
    pkg.installed

{% if not grains['oscodename'] == 'wheezy' %}
lldb-3.3:
    pkg.installed
{% endif %}

The last line specifies that you install the lldb package if your Debian release is not the stable one, i.e. jessie/testing or sid in my case. Now, just include this file in the init.sls one:

# ...
# at the end of 'cpp/init.sls'
include:
  - .llvm

Organize your sls files according to your needs. That's all for packages installation. You Salt configuration now looks like this:

.
|-- cpp
|   |-- init.sls
|   `-- llvm.sls
|-- dev
|   `-- init.sls
|-- edit
|   `-- init.sls
`-- top.sls

Launching Salt

Start your VM and install a masterless Salt on it (e.g. apt-get install salt-minion). For launching Salt locally on your naked VM, you need to copy your configuration (through scp or a DVCS) into /srv/salt/ directory and to write the file top.sls:

base:
  '*':
    - dev
    - edit
    - cpp

Then just launch:

> salt-call --local state.highstate

as root.

And What About Configuration Files?

You're right. At the beginning of the post, I talked about a "ready to use" Mercurial with some HG extensions. So I use and copy the default /etc/mercurial/hgrc.d/hgext.rc file into the dev directory of my Salt configuration. Then, I edit it to set some extensions such as color, rebase, pager. As I also need Evolve, I have to clone the source code from https://bitbucket.org/marmoute/mutable-history. With Salt, I can tell "clone this repo and copy this file" to specific places.

So, I add some lines to dev/init.sls.

https://bitbucket.org/marmoute/mutable-history:
    hg.latest:
      - rev: tip
      - target: /opt/local/mutable-history
      - require:
         - pkg: mercurial

/etc/mercurial/hgrc.d/hgext.rc:
    file.managed:
      - source: salt://dev/hgext.rc
      - user: root
      - group: root
      - mode: 644

The require keyword means "install (if necessary) this target before cloning". The other lines are quite self-explanatory.

In the end, you have just six files with a few lines. Your configuration now looks like:

.
|-- cpp
|   |-- init.sls
|   `-- llvm.sls
|-- dev
|   |-- hgext.rc
|   `-- init.sls
|-- edit
|   `-- init.sls
`-- top.sls

You can customize it and share it with your teammates. A step further would be to add some configuration files for your favorite editor. You can also imagine to install extra packages that your library depends on. Quite simply add a subdirectory amazing_lib and write your own init.sls. I know I often need Boost libraries for example. When your Salt configuration has changed, just type: salt-call --local state.highstate.

As you can see, setting up your environment on a fresh system will take you only a couple commands at the shell before you are ready to compile your C++ library, debug it, fix it and commit your modifications to your repository.

blog entry of

Logilab.org - en

http://www.logilab.org/file/203841/raw/pandas_logo.png

Do you know pandas, a Python library for data analysis? Version 0.13 came out on January the 16th and this post describes a few new features and improvements that I think are important.

Each release has its list of bug fixes and API changes. You may read the full release note if you want all the details, but I will just focus on a few things.

You may be interested in one of my previous blog post that showed a few useful Pandas features with datasets from the Quandl website and came with an IPython Notebook for reproducing the results.

Let's talk about some new and improved Pandas features. I suppose that you have some knowledge of Pandas features and main objects such as Series and DataFrame. If not, I suggest you watch the tutorial video by Wes McKinney on the main page of the project or to read 10 Minutes to Pandas in the documentation.

Refactoring

I welcome the refactoring effort: the Series type, subclassed from ndarray, has now the same base class as DataFrame and Panel, i.e. NDFrame. This work unifies methods and behaviors for these classes. Be aware that you can hit two potential incompatibilities with versions less that 0.13. See internal refactoring for more details.

Timeseries

to_timedelta()

Function pd.to_timedelta to convert a string, scalar or array of strings to a Numpy timedelta type (np.timedelta64 in nanoseconds). It requires a Numpy version >= 1.7. You can handle an array of timedeltas, divide it by an other timedelta to carry out a frequency conversion.

from datetime import timedelta
import numpy as np
import pandas as pd

# Create a Series of timedelta from two DatetimeIndex.
dr1 = pd.date_range('2013/06/23', periods=5)
dr2 = pd.date_range('2013/07/17', periods=5)
td = pd.Series(dr2) - pd.Series(dr1)

# Set some Na{N,T} values.
td[2] -= np.timedelta64(timedelta(minutes=10, seconds=7))
td[3] = np.nan
td[4] += np.timedelta64(timedelta(hours=14, minutes=33))
td
0   24 days, 00:00:00
1   24 days, 00:00:00
2   23 days, 23:49:53
3                 NaT
4   24 days, 14:33:00
dtype: timedelta64[ns]

Note the NaT type (instead of the well-known NaN). For day conversion:

td / np.timedelta64(1, 'D')
0    24.000000
1    24.000000
2    23.992975
3          NaN
4    24.606250
dtype: float64

You can also use the DateOffSet as:

td + pd.offsets.Minute(10) - pd.offsets.Second(7) + pd.offsets.Milli(102)

Nanosecond Time

Support for nanosecond time as an offset. See pd.offsets.Nano. You can use N of this offset in the pd.date_range function as the value of the argument freq.

Daylight Savings

The tz_localize method can now infer a fall daylight savings transition based on the structure of the unlocalized data. This method, as the tz_convert method is available for any DatetimeIndex, Series and DataFrame with a DatetimeIndex. You can use it to localize your datasets thanks to the pytz module or convert your timeseries to a different time zone. See the related documentation about time zone handling. To use the daylight savings inference in the method tz_localize, set the infer_dst argument to True.

DataFrame Features

New Method isin()

New DataFrame method isin which is used for boolean indexing. The argument to this method can be an other DataFrame, a Series, or a dictionary of a list of values. Comparing two DataFrame with isin is equivalent to do df1 == df2. But you can also check if values from a list occur in any column or check if some values for a few specific columns occur in the DataFrame (i.e. using a dict instead of a list as argument):

df = pd.DataFrame({'A': [3, 4, 2, 5],
                   'Q': ['f', 'e', 'd', 'c'],
                   'X': [1.2, 3.4, -5.4, 3.0]})
   A  Q    X
0  3  f  1.2
1  4  e  3.4
2  2  d -5.4
3  5  c  3.0

and then:

df.isin(['f', 1.2, 3.0, 5, 2, 'd'])
       A      Q      X
0   True   True   True
1  False  False  False
2   True   True  False
3   True  False   True

Of course, you can use the previous result as a mask for the current DataFrame.

mask = _
df[mask.any(1)]
      A  Q    X
   0  3  f  1.2
   2  2  d -5.4
   3  5  c  3.0

When you pass a dictionary to the ``isin`` method, you can specify the column
labels for each values.
mask = df.isin({'A': [2, 3, 5], 'Q': ['d', 'c', 'e'], 'X': [1.2, -5.4]})
df[mask]
    A    Q    X
0   3  NaN  1.2
1 NaN    e  NaN
2   2    d -5.4
3   5    c  NaN

See the related documentation for more details or different examples.

New Method str.extract

The new vectorized extract method from the StringMethods object, available with the suffix str on Series or DataFrame. Thus, it is possible to extract some data thanks to regular expressions as followed:

s = pd.Series(['doe@umail.com', 'nobody@post.org', 'wrong.mail', 'pandas@pydata.org', ''])
# Extract usernames.
s.str.extract(r'(\w+)@\w+\.\w+')

returns:

0       doe
1    nobody
2       NaN
3    pandas
4       NaN
dtype: object

Note that the result is a Series with the re match objects. You can also add more groups as:

# Extract usernames and domain.
s.str.extract(r'(\w+)@(\w+\.\w+)')
        0           1
0     doe   umail.com
1  nobody    post.org
2     NaN         NaN
3  pandas  pydata.org
4     NaN         NaN

Elements that do no math return NaN. You can use named groups. More useful if you want a more explicit column names (without NaN values in the following example):

# Extract usernames and domain with named groups.
s.str.extract(r'(?P<user>\w+)@(?P<at>\w+\.\w+)').dropna()
     user          at
0     doe   umail.com
1  nobody    post.org
3  pandas  pydata.org

Thanks to this part of the documentation, I also found out other useful strings methods such as split, strip, replace, etc. when you handle a Series of str for instance. Note that the most of them have already been available in 0.8.1. Take a look at the string handling API doc (recently added) and some basics about vectorized strings methods.

Interpolation Methods

DataFrame has a new interpolate method, similar to Series. It was possible to interpolate missing data in a DataFrame before, but it did not take into account the dates if you had index timeseries. Now, it is possible to pass a specific interpolation method to the method function argument. You can use scipy interpolation functions such as slinear, quadratic, polynomial, and others. The time method is used to take your index timeseries into account.

from datetime import date
# Arbitrary timeseries
ts = pd.DatetimeIndex([date(2006,5,2), date(2006,12,23), date(2007,4,13),
                       date(2007,6,14), date(2008,8,31)])
df = pd.DataFrame(np.random.randn(5, 2), index=ts, columns=['X', 'Z'])
# Fill the DataFrame with missing values.
df['X'].iloc[[1, -1]] = np.nan
df['Z'].iloc[3] = np.nan
df
                   X         Z
2006-05-02  0.104836 -0.078031
2006-12-23       NaN -0.589680
2007-04-13 -1.751863  0.543744
2007-06-14  1.210980       NaN
2008-08-31       NaN  0.566205

Without any optional argument, you have:

df.interpolate()
                   X         Z
2006-05-02  0.104836 -0.078031
2006-12-23 -0.823514 -0.589680
2007-04-13 -1.751863  0.543744
2007-06-14  1.210980  0.554975
2008-08-31  1.210980  0.566205

With the time method, you obtain:

df.interpolate(method='time')
                   X         Z
2006-05-02  0.104836 -0.078031
2006-12-23 -1.156217 -0.589680
2007-04-13 -1.751863  0.543744
2007-06-14  1.210980  0.546496
2008-08-31  1.210980  0.566205

I suggest you to read more examples in the missing data doc part and the scipy documentation about the module interpolate.

Misc

Convert a Series to a single-column DataFrame with its method to_frame.

Misc & Experimental Features

Retrieve R Datasets

Not a killing feature but very pleasant: the possibility to load into a DataFrame all R datasets listed at http://stat.ethz.ch/R-manual/R-devel/library/datasets/html/00Index.html

import pandas.rpy.common as com
titanic = com.load_data('Titanic')
titanic.head()
  Survived    Age     Sex Class value
0       No  Child    Male   1st   0.0
1       No  Child    Male   2nd   0.0
2       No  Child    Male   3rd  35.0
3       No  Child    Male  Crew   0.0
4       No  Child  Female   1st   0.0

for the datasets about survival of passengers on the Titanic. You can find several and different datasets about New York air quality measurements, body temperature series of two beavers, plant growth results or the violent crime rates by US state for instance. Very useful if you would like to show pandas to a friend, a colleague or your Grandma and you do not have a dataset with you.

And then three great experimental features.

Eval and Query Experimental Features

The eval and query methods which use numexpr which can fastly evaluate array expressions as x - 0.5 * y. For numexpr, x and y are Numpy arrays. You can use this powerfull feature in pandas to evaluate different DataFrame columns. By the way, we have already talked about numexpr a few years ago in EuroScipy 09: Need for Speed.

df = pd.DataFrame(np.random.randn(10, 3), columns=['x', 'y', 'z'])
df.head()
          x         y         z
0 -0.617131  0.460250 -0.202790
1 -1.943937  0.682401 -0.335515
2  1.139353  0.461892  1.055904
3 -1.441968  0.477755  0.076249
4 -0.375609 -1.338211 -0.852466
df.eval('x + 0.5 * y - z').head()
0   -0.184217
1   -1.267222
2    0.314395
3   -1.279340
4   -0.192248
dtype: float64

About the query method, you can select elements using a very simple query syntax.

df.query('x >= y > z')
          x         y         z
9  2.560888 -0.827737 -1.326839

msgpack Serialization

New reading and writing functions to serialize your data with the great and well-known msgpack library. Note this experimental feature does not have a stable storage format. You can imagine to use zmq to transfer msgpack serialized pandas objects over TCP, IPC or SSH for instance.

Google BigQuery

A recent module pandas.io.gbq which provides a way to load into and extract datasets from the Google BigQuery Web service. I've not installed the requirements for this feature now. The example of the release note shows how you can select the average monthly temperature in the year 2000 across the USA. You can also read the related pandas documentation. Nevertheless, you will need a BigQuery account as the other Google's products.

Take Your Keyboard

Give it a try, play with some data, mangle and plot them, compute some stats, retrieve some patterns or whatever. I'm convinced that pandas will be more and more used and not only for data scientists or quantitative analysts. Open an IPython Notebook, pick up some data and let yourself be tempted by pandas.

I think I will use more the vectorized strings methods that I found out about when writing this post. I'm glad to learn more about timeseries because I know that I'll use these features. I'm looking forward to the two experimental features such as eval/query and msgpack serialization.

You can follow me on Twitter (@jazzydag). See also Logilab (@logilab_org).

blog entry of

Logilab.org - en

Pylint 1.1 eventually got released on pypi!

A lot of work has been achieved since the latest 1.0 release. Various people have contributed to add several new checks as well as various bug fixes and other enhancement.

Here is the changes summary, check the changelog for more info.

New checks:

  • 'deprecated-pragma', for use of deprecated pragma directives "pylint:disable-msg" or "pylint:enable-msg" (was previously emmited as a regular warn().
  • 'superfluous-parens' for unnecessary parentheses after certain keywords.
  • 'bad-context-manager' checking that '__exit__' special method accepts the right number of arguments.
  • 'raising-non-exception' / 'catching-non-exception' when raising/catching class non inheriting from BaseException
  • 'non-iterator-returned' for non-iterators returned by '__iter__'.
  • 'unpacking-non-sequence' for unpacking non-sequences in assignments and 'unbalanced-tuple-unpacking' when left-hand-side size doesn't match right-hand-side.

Command line:

  • New option for the multi-statement warning to allow single-line if statements.
  • Allow to run pylint as a python module 'python -m pylint' (anatoly techtonik).
  • Various fixes to epylint

Bug fixes:

  • Avoid false used-before-assignment for except handler defined identifier used on the same line (#111).
  • 'useless-else-on-loop' not emited if there is a break in the else clause of inner loop (#117).
  • Drop 'badly-implemented-container' which caused several problems in its current implementation.
  • Don't mark input as a bad function when using python3 (#110).
  • Use attribute regexp for properties in python3, as in python2
  • Fix false-positive 'trailing-whitespace' on Windows (#55)

Other:

  • Replaced regexp based format checker by a more powerful (and nit-picky) parser, combining 'no-space-after-operator', 'no-space-after-comma' and 'no-space-before-operator' into a new warning 'bad-whitespace'.
  • Create the PYLINTHOME directory when needed, it might fail and lead to spurious warnings on import of pylint.config.
  • Fix setup.py so that pylint properly install on Windows when using python3.
  • Various documentation fixes and enhancements

Packages will be available in Logilab's Debian and Ubuntu repository in the next few weeks.

Happy christmas!

blog entry of

Logilab.org - en

Logilab has set up the second meetup for salt users in Paris on Feb 6th, 2014 at IRILL, near Place d'Italie, starting at 18:00. The address is 23 avenue d'Italie, 75013 Paris.

Here is the announce in french http://www.logilab.fr/blogentry/1981

Please forward it to whom may be interested, underlining that pizzas will be offered to refuel the chatters ;)

Conveniently placed a week after the Salt Conference, topics will include anything related to salt and its uses, demos, new ideas, exchange of salt formulas, commenting the talks/videos of the saltconf, etc.

If you are interested in Salt, Python and Devops and will be in Paris at that time, we hope to see you there !

blog entry of

Logilab.org - en

Some time ago, we moved Pylint from this forge to Bitbucket (more on this here).

https://bitbucket-assetroot.s3.amazonaws.com/c/photos/2012/Oct/11/master-logo-2562750429-5_avatar.png

Since then, I somewhat continued to use the continuous integration (CI) service we provide on logilab.org to run tests on new commits, and to do the release job (publish a tarball on pypi, on our web site, build Debian and Ubuntu packages, etc.). This is fine, but not really handy since the logilab.org's CI service is not designed to be used for projects hosted elsewhere. Also I wanted to see what others have to offer, so I decided to find a public CI service to host Pylint and Astroid automatic tests at least.

Here are the results of my first swing at it. If you have others suggestions, some configuration proposal or whatever, please comment.

First, here are the ones I didn't test along with why:

The first one I actually tested, also the first one to show up when looking for "bitbucket continuous integration" on Google is https://drone.io. The UI is really simple, I was able to set up tests for Pylint in a matter of minutes: https://drone.io/bitbucket.org/logilab/pylint. Tests are automatically launched when a new commit is pushed to Pylint's Bitbucket repository and that setup was done automatically.

Trying to push Drone.io further, one missing feature is the ability to have different settings for my project, e.g. to launch tests on all the python flavor officially supported by Pylint (2.5, 2.6, 2.7, 3.2, 3.3, pypy, jython, etc.). Last but not least, the missing killer feature I want is the ability to launch tests on top of Pull Requests, which travis-ci supports.

Then I gave http://wercker.com a shot, but got stuck at the Bitbucket repository selection screen: none were displayed. Maybe because I don't own Pylint's repository, I'm only part of the admin/dev team? Anyway, wercker seems appealing too, though the configuration using yaml looks a bit more complicated than drone.io's, but as I was not able to test it further, there's not much else to say.

http://wercker.com/images/logo_header.png

So for now the winner is https://drone.io, but the first one allowing me to test on several Python versions and to launch tests on pull requests will be the definitive winner! Bonus points for automating the release process and checking test coverage on pull requests as well.

https://drone.io/drone3000/images/alien-zap-header.png

blog entry of

Logilab.org - en

InfoLab Rennes - 17 décembre

Le mardi 17 décembre, nous avons participé à la 4ème rencontre du groupe national infolab à Rennes. Voici quelques notes et reflexions prises à cette occasion. La journée a été dense, donc vous ne trouverez que des bribes des sujets dans ce compte rendu.

http://www.fing.org/local/cache-vignettes/L680xH165/_info_lab_V3_logo_petit-d6f63.jpg

Présentation générale le matin

Une présentation générale de la mission "infolab" menée par le Fing a permis d'initier la réflexion et la discussion sur ce qu'est un infolab. Sarah Labelle (Université Paris XIII), Amandine Brugières (Poitiers), Claire Gallon (Nantes, Libertic), Simon Chignard (Rennes), Charles Nepote (Marseille), et Thierry Marcou (Paris) se sont succédé pour expliquer les réflexions et outils en cours d'élaboration. Nous avons noté :

  • une liste de 150 outils répertoriés pour aider à manipuler les données,
  • un prototype de méthodologie,
  • des documents récapitulatifs sur les différents métiers autour de la donnée.

L'assemblée se pose la question de comment rendre accessible les technologies, les données, les outils. Il nous semble qe cette démarche n'est possible qu'en ayant des mécanismes transparents, reproductibles et collaboratifs. Nous y voyons donc les principes de "logiciel libre", des "standards" et des "outils collaboratifs". Comment rendre le traitement de la donnée reproductible et transparent ?

À Logilab, nous avons adoptés les outils suivants pour traiter la données :

  • CubicWeb (en python) avec un certain nombre de cubes (modules type plugins)
  • les standards du web sémantique pour faire de la publication et de l'échange de données (publication de dumps, negociation de contenu et sparql endpoints),
  • les outils de versionning et de collaboration (en logiciel libre) : mercurial qui permettent une co-construction décentralisée sur du code source, mais aussi sur certaines données (voir par exemple les jeux de données publié sur github).

Au sujet de l'annuaire des outils : comporte-t-il une évaluation de l'accessibilité ? D'un outil WYSIWYG à un outil de programmation... quelle grille de notation ? Faut-il faire son propre graphisme ou est-ce "configurable" sans compétence... Grille d'évaluation aussi sur l'autonomie de l'outil ? Par exemple utiliser Google Drive pose des questions des droits sur les données (exemple récent sur la propriété des données lorsqu'elles sont affichées sur une carte google à travers l'API). Dans le domaine du logiciel libre, avec lequel nous pouvons établir un bon nombre de parallèles, il existe des méthodes formelles d'évaluation.

D'autres questions ont été abordées :

  • stockage et pérennité des démarches et des données : dans l'industrie logicielle une formalisation pertinente en rapport avec cette question est le semantic versionning qui permet d'établir une traçabilité. Sur l'archivage, de nombreuses solutions sont envisageables mais pas forcément formalisées (stockage P2P, hébergement mutualisé, etc).
  • le contrôle d'accès : qui accède comment, comment partage-t-on de manière sécurisée ? Ceci nous fait penser aux études menées par le MIT sur leur projet OpenPDS.
  • comment rendre le crowdsourcing efficace ? Des outils comme CrowdCarfting (PyBossa en Python) permettraient de "simplement" définir une application de crowdsourcing (eg. cartographie, annotation d'image, classement d'image, OCR collaboratif, etc.) mais comment faire le lien avec les données "officielles" ?

Atelier l'après-midi

Suite à une visite du labfab de Rennes, nous avons participé aux ateliers, étant deux personnes de chez Logilab, nous avons pu participer à trois ateliers :

  • travail sur la charte des infolabs,
  • datavisualisation et réflexions autour des données,
  • comment mener une campagne de crowdsourcing et sur quels types de données.

Dans l'atelier sur le crowdsourcing, nous avons parlé rapidement de CKAN et http://datahub.io/ qui sont des moteurs de recherche sur les jeux de données ouverts.

La suite

Nous avons participé à DataPride (à Nantes) et comptons participer dans le futur à DataLab (à Nantes) et DataShacker (à Paris), s'agit-il d'initiatives "compatibles" avec les principes des infolabs ? Sont-ce des infolabs ? La suite de l'initiative nous le dira sûrement.

Les prochaines rencontres Infolab auront probablement lieu à Bordeaux en janvier et à Paris lors de Futur en Seine (du 12 au 15 juin : au CNAM, à la Gaité Lyrique, au Square Emile Chautemps).

blog entry of

Logilab.org - en VF

Ce billet est un petit retour d'expérience sur l'utilisation de Numpy pour lire et extraire des données tabulées depuis des fichiers texte.

Chaque section, hormis les objectifs ou la conclusion, correspond soit à une difficulté rencontrée, une remarque technique, des explications et références vers la documentation officielle sur un point précis qui m'a fait patauger quelques temps. Il y a de forte chance, pour certains d'entre vous, que les points décrits ici vous paraissent évidents, que vous vous disiez "mais qui ne sait pas ça ?!". J'étais moi-même le premier étonné, depuis que je connais Numpy, de ne pas savoir ce genre de choses. Je l'étais moins quand autour de moi, mes camarades ne semblaient pas non plus connaître les petites histoires numpysiennes que je vais vous conter.

http://www.logilab.org/file/203839/raw/numpylogo.png

Objectifs

Le Pourquoi et le Où on va au fait ?

J'avais sous la main des fichiers aux données tabulées, type CSV, où les types de données par colonne étaient clairement identifiés. Je ne souhaitais pas passer du temps avec le module csv de la bibliothèque standard à convertir chaque élément en type de base, str, flottants ou dates. Numpy étant déjà une dépendance du projet, et connaissant la fonction np.genfromtxt, j'ai évidemment souhaité l'utiliser.

Il était nécessaire de ne lire que certaines colonnes. Je souhaitais associer un nom à chaque colonne. L'objectif était ensuite d'itérer sur ces données ligne par ligne et les traiter dans des générateurs Python. Je n'utilise pas ici Numpy pour faire des opérations mathématiques sur ces tableaux à deux dimensions avec des types hétérogènes. Et je ne pense d'ailleurs pas qu'il soit pertinent d'utiliser ce type de tableau pour faire ces opérations.

dtypes différents, str et extraction de chaînes vides

On utilise ici l'argument dtype des fonctions telles que np.genfromtxt pour lire des fichiers tabulés dont les colonnes sont de types différents.

Attention au dtype à passer à np.genfromtxt ou np.recfromtxt quand on parse des données tabulée (file ou stream). Pour parser une colonne de chaînes de caratères, lui passer [('colname', str)] renvoie des chaînes vides si les autres dtypes sont de types différents.

Il faut préciser la taille :

dtype=[('colname', str, 10)]
# or
dtype=[('colname', 'S10')]

Ou alors prendre un "vrai" objet str Python :

dtype=[('colname', object)]

aussi équivalent à:

dtype=[('colname', 'object')]

Et oui, je suis littéralement tombé sur l'évidence, les "types Numpy", c'est du type C. Et les chaînes, c'est du char * et il y a donc besoin de la taille. La solitude s'est fait moindre quand j'ai su que je n'étais pas le seul à être tombé sur des données tronquées voire vides.

dtype et tableau à zéro dimension

Attention au tableau Numpy 0D quand le contenu tabulé à parser n'a qu'une seule ligne (cas d'un np.[rec]array avec plusieurs dtypes). Impossible d'itérer sur les éléments puisque dimension nulle.

Supposons que vous ayez un fichier tabulé d'une seule ligne :

Name,Play,Age
Coltrane,Saxo,28

J'utilise np.genfromtxt en précisant le type des colonnes que je souhaite récupérer (je ne prends pas en compte ici la première ligne).

data = np.genfromtxt(filename, delimiter=',',
                     dtype=[('name', 'S12'), ('play', object), ('age', int)],
                     skip_header=1)

Voici la représentation de mon array :

array(('Coltrane', 'Saxo', 28),
    dtype=[('name', 'S12'), ('play', 'O'), ('age', '<i8')])

Si dans votre code, vous avez eu la bonne idée de parcourir vos données avec :

for name, instrument, age in data:
    # ...

vous pourrez obenir un malheureux TypeError: 'numpy.int64' object is not iterable par exemple. Vous n'avez pas eu de chance, votre tableau Numpy est à zéro dimension et une shape nulle (i.e. un tuple vide). Effectivement, itérer sur un objet de dimension nulle n'est pas chose aisée. Ce que je veux, c'est un tableau à une dimension avec un seul élément (ici un tuple avec mes trois champs) sur lequel il est possible d'itérer.

Pour cela, faire:

>>> print data
array(('Coltrane', 'Saxo', 28),
      dtype=[('name', 'S12'), ('play', 'O'), ('age', '<i8')])array(('babar', 42.), dytpe=[('f0', 'S5'), ('f1', '<f8')])
>>> print data.shape, data.ndim
(), 0
>>> data = data[np.newaxis]
>>> print data.shape, data.ndim
(1,), 1

dtype et str : chararray ou ndarray de strings ?

Pour les chararray, lire help(np.chararray) ou http://docs.scipy.org/doc/numpy/reference/generated/numpy.chararray.html. En particulier:

The chararray class exists for backwards compatibility with Numarray, it is not recommended for new development. Starting from numpy 1.4, if one needs arrays of strings, it is recommended to use arrays of dtype object_, string_ or unicode_, and use the free functions in the numpy.char module for fast vectorized string operations.

On fera donc la distinction entre:

# ndarray of str
na = np.array(['babar', 'celeste'], dtype=np.str_)
# chararray
ca = np.chararray(2)
ca[0], ca[1] = 'babar', 'celeste'

Le type de tableau est ici différent : np.ndarray pour le premier et np.chararray pour le second. Malheureusement pour np.recfromtxt et en particulier pour np.recarray, si on transpose le label de la colonne en tant qu'attribut, np.recarray il est transformé en chararray avec le bon type Numpy --- |S7 dans notre cas --- au lieu de conserver un np.ndarray de type |S7.

Exemple :

from StringIO import StringIO
rawtxt = 'babar,36\nceleste,12'
a = np.recfromtxt(StringIO(rawtxt), delimiter=',', dtype=[('name', 'S7'), ('age', int)])
print(type(a.name))

Le print rend bien un objet de type chararray. Alors que :

a = np.genfromtxt(StringIO(rawtxt), delimiter=',', dtype=[('name', 'S7'), ('age', int)])
print(type(a['name']))

affiche ndarray. J'aimerais que tout puisse être du même type, peu importe la fonction utilisée. Au vue de la documentation et de l'aspect déprécié du type charray, on souhaiterait avoir que du ndarray de type np.str. J'ai par ailleurs ouvert le ticket Github 3993 qui n'a malheureusement que peu de succès :-(

Tableau de chaînes : quel dtype ?

Si certains se demandent quoi mettre pour représenter le type "une chaîne de caractères" dans un tableau numpy, ils ont le choix :

np.array(['coltrane', 'hancock'], dtype=np.str)
np.array(['coltrane', 'hancock'], dtype=np.str_)
np.array(['coltrane', 'hancock'], dtype=np.string_)
np.array(['coltrane', 'hancock'], dtype='S')
np.array(['coltrane', 'hancock'], dtype='S10')
np.array(['coltrane', 'hancock'], dtype='|S10')

Les questions peuvent être multiples : est-ce la même chose ? pourquoi tant de choses différentes ? Pourquoi tant de haine quand on lit la doc Numpy et que l'info ne saute pas aux yeux ? À savoir que le tableau construit sera identique dans chacun des cas. Il existe peut-être même d'autres moyens de construire un tableau de type identique en lui passant encore un n-ième argument dtype différent.

  • np.str représente le type str de Python. Il est converti automatiquement en type chaines de caractère Numpy dont la longueur correspond à la longueur maximale rencontrée.
  • np.str_ et np.string_ sont équivalents et représentent le type "chaîne de caractères" pour Numpy (longueur = longueur max.).
  • Les trois autres utilisent la représentation sous forme de chaîne de caractères du type np.string_.
    • S ne précise pas la taille de la chaîne (Numpy prend donc la chaîne la plus longue)
    • S10 précise la taille de la chaîne (données tronquées si la taille est plus petite que la chaîne la plus longue)
    • |S10 est strictement identique au précédent. Il faut savoir qu'il existe cette notation <f8 ou >f8 pour représenter un flottant. Les chevrons signifient little endian ou big endian respectivement. Le | sert à dire "pas pertinent". Source: la section typestr sur la page http://docs.scipy.org/doc/numpy/reference/arrays.interface.html

À noter que j'ai particulièrement apprécié l'utilisation d'un symbole pour spécifier une information non pertinente --- depuis le temps que je me demandais ce que voulait bien pouvoir dire ce pipe devant le 'S'.

Conclusion (et pourquoi pas pandas ?)

http://www.logilab.org/file/203841/raw/pandas_logo.png

Pandas, bibliothèque Python d'analyse de données basée sur Numpy, propose, via sa fonction read_csv, le même genre de fonctionnalités. Il a l'avantage de convertir les types par colonne sans lui donner d'information de type, qu'on lise toutes les colonnes ou seulement quelques unes. Pour les colonnes de type "chaîne de caractères", il prend un dtype=object et n'essaie pas de deviner la longueur maximale pour le type np.str_. Vous ne rencontrerez donc pas "le coup des chaînes vides/tronquées" comme avec dtype='S'.

Je ne m'étalerai pas sur tout le bien que je pense de cette bibliothèque. Je vous invite par ailleurs à lire/ parcourir un billet de novembre qui expose un certain nombre de fonctionnalités croustillantes et accompagné d'un IPython Notebook.

Et pourquoi pas Pandas ? Il ne me semble pas pertinent de dépendre d'une nouvelle bibliothèque, aussi bien soit-elle, pour une fonction, aussi utile soit-elle. Pandas est un projet intéressant, mais jeune, qui ne se distribue pas aussi bien que Numpy pour l'instant. De plus, le projet sur lequel je travaillais utilisait déjà Numpy. Je n'avais besoin de rien d'autre pour réaliser mon travail, et dépendre de Pandas ne me semblait pas très pertinent. Je me suis donc contenté des fonctions np.{gen,rec}fromtxt qui font très bien le boulot, avec un dtype comme il faut, tout en retenant les boulettes que j'ai faites.

blog entry of

Logilab.org - en VF

was the topic of the talk I gave last saturday at the Capitol du Libre in Toulouse.

Here are the slides (pdf) for those interested (in french). A video of the talk should be available soon on the Capitol du Libre web site. The slides are mirrored on slideshare (see below):

blog entry of

Logilab.org - en