Преобразувайте сумите в относителни вероятности

Заден план

Създайте вероятен лексикон въз основа на CSV файл с думи и суми. Това е прелюдия към проблем със сегментиране на текст, а не проблем с домашна работа.

проблем

Даден е CSV файл със следните думи и суми:

aardvark,10
aardwolf,9
armadillo,9
platypus,5
zebra,1

Създайте файл с вероятности спрямо най-големия резултат във файла:

aardvark,1
aardwolf,0.9
armadillo,0.9
platypus,0.5
zebra,0.1

Където например aardvark,1 се изчислява като aardvark,10/10, а platypus,0.5 се изчислява като platypus,5/10.

Въпрос

Кой е най-ефективният начин за внедряване на шел скрипт за създаване на файл с относителни вероятности?

Ограничения

  • Нито думите, нито числата са в някакъв ред.
  • Няма основни езици за програмиране (като Perl, Ruby, Python, Java, C, Fortran или Cobol).
  • Стандартните Unix инструменти като awk, sed или sort са добре дошли.
  • Всички вероятности трябва да са относителни към най-високата вероятност във файла.
  • Думите са уникални, числата не са.
  • Резултатите са естествени числа.

Благодаря ти!


person Dave Jarvis    schedule 04.02.2011    source източник
comment
@Marshall: bc не е bashcalc, това е настолен калкулатор, тъй като dc е настолен калкулатор.   -  person Dennis Williamson    schedule 07.02.2011
comment
@Dennis: Благодаря ви, извинете за объркването   -  person marshall.ward    schedule 07.02.2011


Отговори (2)


Няма нужда да четете файла два пъти:

awk 'BEGIN {OFS = FS = ","} {a[$1] = $2} $2 > max {max=$2} END {for (w in a) print w, a[w]/max}' inputfile

Ако имате нужда от изхода, сортиран по дума:

awk ... | sort

or

awk 'BEGIN {OFS = FS = ","} {a[$1] = $2; ind[j++] = $1} $2 > max {max=$2} END {n = asort(ind); for (i=1; i<=n; i++) print ind[i], a[ind[i]]/max}' inputfile

Ако имате нужда от изхода, сортиран по вероятност:

awk ... | sort -t, -k2,2n -k1,1
person Dennis Williamson    schedule 04.02.2011
comment
Да не четете файла два пъти определено е ефективен подход. - person Dave Jarvis; 04.02.2011
comment
Ако искате да форматирате числата, можете да замените {print w, a[w]/max} с {printf %s,%.3f\n, w, a[w]/max} (за да запазите 3 цифри в края) - person marshall.ward; 07.02.2011

Това не е защитено от грешки, но нещо подобно трябва да работи:

#!/bin/bash

INPUT=data.cvs
OUTPUT=tally.cvs
DIGITS=1

OLDIFS=$IFS
IFS=,

maxval=0  # Assuming all $val are positive

while read name val
do
    if (( val > maxval )); then maxval=$val; fi
done < $INPUT

# Make sure $OUTPUT doesn't exist

touch $OUTPUT

while read name val
do
    tally=`echo "scale=$DIGITS; result=$val/$maxval; if (0 <= result && result < 1) { print "0" }; print result" | bc`
    echo "$name,$tally" >> $OUTPUT
done < $INPUT

IFS=$OLDIFS

Взаимствано от този въпрос и различни търсения в Google.

person marshall.ward    schedule 04.02.2011
comment
Отличен отговор и добър пример за четене на CSV файлове в bash. Чистото awk решение обаче вероятно е по-ефективно. Благодаря ти. - person Dave Jarvis; 04.02.2011
comment
@Дейв: Определени реквизити за куруми - person marshall.ward; 04.02.2011