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 ?