Как рассчитать n значений в столбце и общее среднее?

Я модифицировал свой тезаурус для завершения предложений. Некоторые улучшения будут Завершите, используя PWD/ , Gutenberg/books/ , Лучшее регулярное выражение с использованием контекста вокруг курсора.

" What: Complete sentence
" Usage: :so % <CR> Get sentence[press C-x C-o]
" How:  Get sentence completions using perl from current  file

set completeopt+=menuone

set omnifunc=MoshCompleteSentence
function!    MoshCompleteSentence(findstart, base)
    " == First call: find-sentence-backwards, see :help omnifunc
    if a:findstart
        let s:line = getline('.')
        let s:wordStart = col('.') - 1
        " Check backward for a sentence_prefix
        while s:wordStart > 0 && s:line[s:wordStart - 1] =~ '[A-Za-z0-9 _,]'
            let s:wordStart -= 1
        endwhile
        return s:wordStart

    else
        " == Second call: grep for sentence_regex, output: list of sentences
        let a:sentence_regex = a:base
        " in regex trim spaces
        let a:sentence_regex = substitute( a:sentence_regex,'\v^\s*(.{-})\s*$','\1','')
        " in regex change punctuation as dot.
        let a:sentence_regex = substitute(a:sentence_regex,'\W','.','g')
        " grep using perl
        let s:cmd='perl -ne '' '
            \.'chomp;'
            \.'next if m/^[;#]/;'
            \.'if( /('.a:sentence_regex.'.{1,30})/io ){'
            \.'   print qq/$1;;/ '
            \.'}'
            \. ' '' '
            \.expand("%:p")
        " == To debug: redir echom to file
        " redir >> c:/tmp/vim.log
        echom s:cmd
        let   s:rawOutput = system(s:cmd)
        let   s:listing = split(s:rawOutput, ';;')
        " echom join(s:listing,',')
        " redir END
        return s:listing
    endif
endfunction
2
15.10.2019, 11:16
2 ответа

Чтобы решить актуальную проблему за один шаг:

$ grep -o '201[1-4].[0-9]\+' file1.txt file2.txt file3.txt \
| datamash --sort -t: -g1 count 2 mean 2 

file1.txt:8:2012.8125
file2.txt:6:2013.08
file3.txt:7:2013.6371428571
  • grepполучает значения из файлов,
  • datamashподсчитывает элементы и вычисляет средние значения по файлам.

Теперь у вас есть одна строка на файл:filename:n:average

Легче, да?

Чтобы получить среднее значение по всем файлам, удалите группировку:

grep -o '201[1-4].[0-9]\+' file1.txt file2.txt file3.txt \
| datamash --sort -t: mean 2

2013.1638095238

Если вам нужен красивый -печатный табличный вывод, попробуйте что-то вроде этого:

$ cat mktable.sh
#!/bin/bash
myfiles="$@"

trap "rm ${myfiles//txt/txt.tempfile}" EXIT SIGTERM SIGINT

declare -A count

for f in $myfiles ; do
  # write the tempfile AND get the linecount simultaneously
    count[$f]="$(grep -o '201[1-4].[0-9]\+' "$f" | tee ${f}.tempfile | wc -l)"
  sed -i "1i $f" ${f}.tempfile        # write header
  sed -i "2i ---------" ${f}.tempfile # write header
done

( paste ${myfiles//txt/txt.tempfile} ;
 for item in $myfiles ; do echo -n '--------- '; done; echo
 for item in $myfiles ; do echo -n "n=${count[$item]} " ; done ; echo ;
 for item in $myfiles ; do echo -n '--------- '; done; echo
 )\
  | column -nt

echo "Average: $(grep -o '201[1-4].[0-9]\+' $myfiles | datamash -s -t: mean 2)"

$./mktable.sh file*.txt
file1.txt  file2.txt  file3.txt
---------  ---------  ---------
2012.69    2013.17    2013.54
2013.44    2012.6     2013.9
2012.64    2013.12    2013.66
2013.11    2012.76    2013.44
2012.6     2013.75    2013.89
2012.41    2013.08    2013.62
2012.41               2013.41
2013.2                
---------  ---------  ---------  
n=8        n=6        n=7        
---------  ---------  ---------  
Average: 2013.1638095238
3
27.01.2020, 21:58

Я бы обработал все это с помощью AWK:

#!/usr/bin/gawk -f

BEGIN {
    RS = " +|\t+|\n"
    OFS = "\t"
}

$1 >= 2011 && $1 < 2015 {
    counts[FILENAME]++
    allcounts++
    allsum += $1
    values[FILENAME][length(values[FILENAME])] = $1
}

END {
    for (file in counts) {
        printf "%s%s", file, OFS
        if (counts[file] > maxlength) {
            maxlength = counts[file]
        }
    }
    printf "\n"
    for (i = 0; i < maxlength; i++) {
        for (file in counts) {
            if (i < counts[file]) {
                printf "%.2f", values[file][i]
            }
            printf "%s", OFS
        }
        printf "\n"
    }
    printf "\n"
    for (file in counts) {
        printf "n=%d%s", counts[file], OFS
    }
    printf "\n"
    printf "Average: %f\n", allsum / allcounts
}

Сохраните это в файл (, например 546830), сделайте его исполняемым(chmod 755 546830)и запустите следующим образом:

./546830 file1.txt file2.txt file3.txt

Вы можете выровнять столбцы, используяcolumn:

./546830 file1.txt file2.txt file3.txt | column -t

Используя примеры, приведенные в вашем вопросе, я получаю

file1.txt  file3.txt    file2.txt
2012.69    2013.54      2013.17
2013.44    2013.90      2012.60
2012.64    2013.66      2013.12
2013.11    2013.44      2012.76
2012.60    2013.89      2013.75
2012.41    2013.62      2013.08
2012.41    2013.41      
2013.20                 
n=8        n=7          n=6
Average:   2013.163810  

Порядок файлов на выходе не обязательно будет соответствовать их порядку на входе, но значения не будут перепутаны. Если порядок важен, я могу изменить сценарий, чтобы сохранить его.

Это работает следующим образом: каждый файл разбивается на записи по пробелам и символам новой строки, а затем сохраняется каждая запись, соответствующая критериям (между 2011 включенным и 2015 исключенным )в массиве values, проиндексированном по файлу. имя и количество. Значения также добавляются в накопитель allsum, а количество файлов для каждого файла -хранится в массиве counts, а совокупное количество — в накопителе allcounts.

1
27.01.2020, 21:58

Теги

Похожие вопросы