devoo - info pour les ours

Aller au contenu | Aller au menu | Aller à la recherche

programmation

programmation web, système, réseau...

Fil des billets - Fil des commentaires

samedi, novembre 11 2006

Preprocessing DataMining : transformation de champs binaires en attribut discret

C'est l'une des rares fois ou je vais parler de mon taff ici, profitez-en :)

Lorsque l'on a affaire à des champs sous forme binaire exclusif les uns aux autres, il est parfois utile de les regrouper pour n'avoir qu'un attribut de differentes valeur à afficher. Par exemple, on peut vouloir transformer : 1000, 0010, 0010, 0100, 0001 en 1, 3, 3, 1, 4. L'espace des dimensions est ainsi réduit (ici on passe de 4 dimension à une seule). Générallement, en Data Mining, c'est plutôt l'inverse qui est réalisé. Mais lorsqu'on veut traiter des données déja classifier/discrétiser on peut se retrouver dans cette situation.

On voit donc qu'il suffit de définir la catégorie comme étant la position du bit à 1 dans les dimensions analysées. Avec un script shell, c'est rapidement réalisé.

#!/bin/sh

#-------------------------------------------------------------------------------
# author : Guillem LEFAIT
# Goal   : transform exclusive binary attributes to one categorical attribute
#          inside a data file as fast as possible
# credit : works done in ucd.ie
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# GLOBAL VARIABLE
OUT=0
COMPRESS_OUT=""
LINE_OUT=""
PROGRAMME_TMP="biniou.$$"
PROGRAMME_RES="$1.converted"

#-------------------------------------------------------------------------------
# what  : check if binary attributes are really exclusives
# input :
#         $1 = some binary values separated by $2
#         $2 = separator
#         $3 = start column
#         $4 = end column
function exclusif_binary()
{
  nb_match=`cat $1 | cut -d "$2" -f$3-$4 | tr -d "$2" | grep -e "^0*10*$" -c`
  nb_lines=`cat $1 | wc -l`
  if [ $nb_match -eq $nb_lines ]
      then
      OUT=0
  else
      OUT=1
  fi
  return $OUT
}

#-------------------------------------------------------------------------------
# what  : converting an attribute to its category
# input : 
#         $1 = binary list to "compress"
#         $2 = separator
function converting_one()
{
  binary=`echo $1 | tr -d "$2"`
  COMPRESS_OUT=`expr index "$binary" 1`
}

#-------------------------------------------------------------------------------
# what  : compressing an instance with some (at least 1) intervall of binary
#         attributes
# input :
#         $1 = the line to process
#         $2 = separator
#         $2+i   } ith interval (column starting)
#         $2+i+1 } ith interval (column ending)
#
function converting_line()
{ 
  line=$1
  sep=$2
  shift 2
  res=""
  last=1
  min=`expr $1 - 1`
  add=""
  while [ $# -ge 2 ]
  do
    if [ $last -lt $1 ]
	then
	v=`echo $line | cut -d "$sep" -f$last-$min`
	res="$res$add$v"
    fi
    add="$sep"
    v=`echo $line | cut -d "$sep" -f$1-$2`
    converting_one $v $sep
    res="$res$add$COMPRESS_OUT"
    min=$last
    last=`expr $2 + 1`
    shift 2
  done
  v=`echo $line | cut -d "$sep" -f$last-`
  if [ "$v" != "" ]
      then
      res="$res$add$v"
  fi
  LINE_OUT="$res"
}

#-------------------------------------------------------------------------------
# what  : processing a file
# input : $1 = file
#         $2 = separator
#         $3,$4, ...., $n-1, $n = intervall list 
function process_all()
{
  file_in="$1"
  in=`cat $file_in`
  shift
  for line in $in
  do
    converting_line $line $*
    echo "$LINE_OUT" >> "$PROGRAMME_TMP"
  done
}

#-------------------------------------------------------------------------------
# checking and lauching the process
if [ $# -lt 4 ]
then
    echo "usage : $0 file separator (colum_start column_end)+"
    exit 1
fi


date
rm "$PROGRAMME_TMP"
process_all $*
cat "$PROGRAMME_TMP" | tr "," "\t" > "$PROGRAMME_RES"
date
# EOF
################################################################################

L'avantage de cette solution, par rapport à la première version est que le fichier préparé se construit au fur et à mesure. Dans la première version je transformais les intervalles "colonne" par "colonne".

Quel est donc mon "problème" ? Et bien mes solutions ne sont pas performantes. Je cherche à transformer des données : environ 600 000 instances, 55 attributs dont 2 intervalles d'attributs binaires à réduire en 2 dimensions (de taille 4 et 40 respectivement). Pour transformer 10 000 données, mon script shell met un peu moins de 5min, soit un traitement de 33 instances par seconde, soit plus de 5 heures pour transformer mon fichier.

Est-ce que quelqu'un a une/des solution(s)/idée(s) pour augmenter les performances d'un script de ce type ?

mercredi, mai 24 2006

google code jam europe 2006

Bon ba j'ai participé hier au google code jam. Deux exos à faire en une heure. Chaque exécution des programmes soumis à partir des jeux de tests ne doit pas dépasser 2 secondes. La contraintes de temps est donc double : pour le codage et pour l'execution.

Première chose, je me suis bien fait avoir ! Je me suis connecté pour voir quand est-ce que j'allais participé et paf, le concours a démarré. J'avoue ne pas avoir compris pourquoi cela a démarré comme ça. Normalement, les sessions devaient commencer à heures fixes. Bref, un bon moment de cafouillage ou je ne savais pas si j'avais plus que 30 minutes ou bien une heure. Finalement, j'ai eut une heure entière. Bref, je n'ai pas compris le biniou.

Concernant les exos, le premier ne posait aucune difficulté, je me choppe 161.60 points sur 250, soit fait en une vingtaine de minutes. J'aurais bien gagné 5 minutes si je n'avais pas eut mon repas de midi sur la table, la doc java sous les yeux et un éditeur lancé. Ceci étant, j'ai voulu trop soigner le premier (notemment en voulant être sur qu'il n'y a pas d'erreur). En codant comme un porc, c'était possible de le faire en moins de 10 minutes.

Pour le deuxième exos, par contre, c'était un peu plus chaud. Le problème est un problème d'optimisation ou, sur un espace en trois dimensions et à partir de points donnés, il s'agit d'installer un "émetteur" sur chaque point capable d'atteindre l'émetteur de chaque autre points, de telle façon que l'emetteur le plus puissant, soit d'une puissance minimale. J'ai eut le temps de résoudre les configurations triviales. J'ai commencé le cas général mais n'ai eut le temps de le terminer.

Aujourd'hui, je fais un tour sur les résultats, histoire de voir un peu ou je me place. A vu de nez, je vais être entre la 600 et la 900ème place. Vu ce que j'ai fait (c'est à dire pas grand chose), je ne suis pas déçu. Le concours était sympa.

Par contre en regardant les résultats de certains, j'avoue ne pas vraiment comprendre. Certains ont en effet plus de 488 points pour le deuxième exo, ce qui, puisque la formule pour calculer les points a été publié, représente un developpement d'1 minute. Si en une minute, on a le temps de faire le deuxième exo (à mon avis en une minute, j'ai eut à peine le temps de lire le "sujet") et que celui-ci passe les tests (même en virant la contraintes d'éxécution en moins de 2 secondes) franchement je crois que je ne peut que présenter mes respects au developpeur qui ne doit pas vivre sur la même planète que moi.

dimanche, mars 20 2005

Projet TSP roadmap viewer !

Voilà le deuxième projet réalisé pour et pendant mon stage de maitrise. Il s'agit en fait d'offrir une interface C --> php -> mysql.
Cette interface a deux buts :

  1. pouvoir sauvegarder les résultats d'un bench
  2. pouvoir visualiser graphiquement ces résultats.

Cette interface couplée au solveur TSP en C (qui trouve le chemin optimal de façon récursive) permet donc d'enregistrer et de visualiser la solution à un probleme donné. Celle-ci permet donc de se concentrer sur la résolution du problème sans soucis de l'affichage ou du traitement de la solution puisque cette étape est gérée par php.
Le système est basé sur un envoi de requete C -> serveur Web. Il y a donc une étape de construction de la requete (requete POST pour pouvoir passer une grande quantite de données) et une étape de transmission.
Une autre solution aurait été de se connecter directement sous mysql en C, mais cette façon supposerait l'utilisation de bibliothèque spécifique, d'une connaisance de la structure des tables de la base de données et des paramètres de connexion (login, password, ...), ce qui ne m'apparait pas nécessaire ici.

Je n'ai toujours pas réglé mon problème de publication des sources, mais le résultat de l'application (visualisation des résultats) est visibile sur : tsp roadmap viewer

mercredi, janvier 26 2005

Projet benchoo v0.1

demo benchooJ'ai fini ce soir (au lieu de réviser mon réseau...) la première version de ma classe benchoo qui permet d'afficher un reporting graphique sur des résultats de bench. Le projet permet actuellement de saisir manuellement les temps et le nom du bench et de créer une image au format PNG, reprenant :

  • La moyenne du bench
  • Le temps minimum et maximum
  • L'histogramme des différents temps saisis

Je pense rajouter rapidement 2 autres fonctionnalités :

  • Un format d'affichage (complet, minimal, normal) afin de pouvoir n'afficher que les informations pertinantes.
  • Une personnalisation plus complete : saisie de l'échelle et précision des temps.

Si un hypothétique visiteur a une remarque à faire sur ce projet, il est le bienvenu.

lundi, janvier 24 2005

pig : programming in progress

Je suis en train de préparer différentes petites choses :

  • La fin de "l'article" sur le stockage/transformation d'adresse ip, cette fois du côté de la base de données.
  • Une classe de benchmark simple (comme la classe benchmark de pear) produisant un report sous forme d'image (histogrammes des differentes mesures + moyenne).
  • Je finis mon adaptation de geshi (un analyseur syntaxique multi-langage). Le seul problème restant est que le parsing de geshi ne permet pas de repasser plusieurs fois pour trouver plusieurs fois la même fonction. Donc certains appels de fonction ne sont pas liés à la page de documentation sur php.net.
  • J'ai encore une vieille fonction de simulation de requete 'post' à finir. (Le but ultime étant de récupérer les références d'un bouquin sur amazon à partir de son titre :d).

Bref je suis pas couché. Je crois que le voyage à Amsterdam risque d'être reporté..

samedi, janvier 22 2005

Stockage et transformation des adresses ip

Transformation PHP

Un problème qui se pose souvent lors de la création de module permettant le suivi et l'analyse des visites est le stockage des adresses ip. En effet, différentes solutions sont envisageables. Faisons rapidement le tour de celles-ci :

Solution 1 : vérification simple

stockage direct de l'adresse ip.

Avantage : aucun coût de transformation et une grande visibilité.
Inconvénient : Stockage dans la base en varchar (la taille pouvant varier de 7 à 15 caractères). Coût de comparaison important.
Requis : explode : PHP >= 3


Solution 2 : codage hexadecimal

stockage de l'adresse en hexadecimal (base 16). Etant donné la spécificité de la plage d'adressage (de 0 à 255), on peut donc stocker l'adresse sur 8 caractères (exemple : 192.168.0.1 devient c0a801).

Avantage : stockage sur 8 caractères (fixe et reduit). Facile a convertir.
Inconvénient : Temps de comparaison encore long, temps de transformation long.
Requis : ctype_digit : PHP >= 4.0.4


Solution 3 : codage par décalage

stockage de l'adresse par décalage. On ajoute au fur et à mesure les quatres parties de l'adresse en opérant un décalage de 256 (é puissance 8) à chaque tour et en ajoutant la sous-partie suivante. (exemple : 192.168.0.1 devient 3198681089). Utilisation et uniformisation de la fonction ip2long en renvoyant false en cas de problème sur l'ip (et pas -1 en php 4 et false en php5).

avantage : facilite de comparaison, temps de conversion très rapide (trois fois plus rapide que ipv4_to_hex).
inconvenient : stockage de type long
Requis : ctype_digit : PHP >= 4.0.4


temps pour générer 25146 adresses (moyenne sur 5 essais)

Solution 1 : 0,446603489 sec
Solution 2 : 1.52481599808 sec
Solution 3 : 0,410049963 sec

Dès lors on peut envisager plusieurs hypothèses selon le type de traitement que l'on veut réaliser. Pour une consultation rapide des adresses, le stockage direct des ip peut être envisagé. Pour une taille de stockage minimale on peut passer par une compression de l'adresse en hexadécimal. Enfin pour une comparaison d'adresse : logs, surveillances, la transformation par décalage semble idéale.

à suivre comparatif recherche/stockage des adresses ip dans MySQL