【问题标题】:Creating histograms in bash在 bash 中创建直方图
【发布时间】:2017-01-29 13:55:23
【问题描述】:

编辑

我读到这个问题应该是 (this one) 的副本。我不同意。在该问题中,目的是获得列中各个数字的频率。但是,如果我将该解决方案应用于我的问题,我仍然会遇到将特定范围内的数字频率分组到最终直方图中的初始问题。即,如果该解决方案告诉我0.45 的频率是20.441(对于我的输入数据),我仍然存在将这两个频率分组为@ 总数的问题987654328@ 用于范围 0.4-0.5

结束编辑

问题-

我有一长列数据,其值介于 0 和 1 之间。 这将是类型-

0.34
0.45
0.44
0.12
0.45
0.98
.
.
.

允许重复的一长列十进制值。

我正在尝试将其更改为直方图类型的输出,例如(对于上面显示的输入)-

0.0-0.1  0
0.1-0.2  1
0.2-0.3  0
0.3-0.4  1 
0.4-0.5  3
0.5-0.6  0
0.6-0.7  0
0.7-0.8  0
0.8-0.9  0
0.9-1.0  1

基本上,第一列包含每个范围的下限和上限,第二列包含该范围内的条目数。

我把它(糟糕地)写成——

for i in $(seq 0 0.1 0.9)
do 
    awk -v var=$i '{if ($1 > var && $1 < var+0.1 ) print $1}' input | wc -l; 
done

它基本上对它在每个范围内找到的条目进行wc -l

输出格式不是问题的一部分。如果我只是得到与不同 bin 相对应的频率,那就足够了。另请注意,bin 大小应该是我提出的解决方案中的变量。

我已经阅读了this 的答案并希望避免循环。我确信awk 中有一种更快的方法可以绕过for 循环。你能帮帮我吗?

【问题讨论】:

  • @triplee 查看我的编辑。
  • @NeilMcGuigan,您链接的问题以“正确分类数据”开头。我的问题与我将如何首先创建垃圾箱有关。
  • @VarunM 你能告诉我我的答案有什么问题吗...如果你需要我可以改进它...

标签: bash loops awk histogram


【解决方案1】:

你会在这个算法中找到的唯一循环是在文件的行周围。

这是一个关于如何实现您在 bash 中提出的问题的示例。 bash 可能不是最好的语言,因为它在数学上很慢。我使用 bc,如果您愿意,可以使用 awk。

算法的工作原理

想象你有很多箱子:每个箱子对应一个区间。每个 bin 的特征是宽度 (CHANNEL_DIM) 和位置。这些 bin 必须能够覆盖数据投射的整个间隔。执行number / bin_width 的值,您将获得垃圾箱的位置。因此,您只需在该垃圾箱中添加 +1。 Here 更详细的解释。

#!/bin/bash

# This is the input: you can use $1 and $2 to read input as cmd line argument
FILE='bash_hist_test.dat'
CHANNEL_NUMBER=9  # They are actually 10: 0 is already a channel

# check the max and the min to define the dimension of the channels:
MAX=`sort -n $FILE | tail -n 1`
MIN=`sort -rn $FILE | tail -n 1`

# Define the channel width 
CHANNEL_DIM_LONG=`echo "($MAX-$MIN)/($CHANNEL_NUMBER)" | bc -l` 
CHANNEL_DIM=`printf '%2.2f' $CHANNEL_DIM_LONG `
# Probably printf is not the best function in this context because
#+the result could be system dependent.

# Determine the channel for a given number
# Usage: find_channel <number_to_histogram> <width_of_histogram_channel>
function find_channel(){
  NUMBER=$1
  CHANNEL_DIM=$2

  # The channel is found dividing the value for the channel width and 
  #+rounding it.
  RESULT_LONG=`echo $NUMBER/$CHANNEL_DIM | bc -l`
  RESULT=`printf '%.0f' $RESULT_LONG`
  echo $RESULT
}

# Read the file and do the computuation
while IFS='' read -r line || [[ -n "$line" ]]; do

  CHANNEL=`find_channel $line $CHANNEL_DIM`

  [[ -z HIST[$CHANNEL] ]] && HIST[$CHANNEL]=0
  let HIST[$CHANNEL]+=1
done < $FILE

counter=0
for i in ${HIST[*]}; do
  CHANNEL_START=`echo "$CHANNEL_DIM * $counter - .04" | bc -l`
  CHANNEL_END=`echo " $CHANNEL_DIM * $counter + .05" | bc`
  printf '%+2.1f : %2.1f => %i\n' $CHANNEL_START $CHANNEL_END $i
  let counter+=1
done

希望这会有所帮助。如果您有其他问题,请发表评论。

【讨论】:

  • 感谢您的好评脚本。我不明白你的变量 $NUMBER$CHANNEL_DIM 代表什么。
  • @VarunM 我试着解释一下……但了解它的工作原理的最好方法是测试它并检查输出广告的不同点。
  • 您的脚本适用于示例案例(短输入),但对于我的实际输入(大约有 50 万个条目)花费了 way 太长的时间。你是对的,也许 bash 不是最好的语言。不过谢谢你的回答! +1,因为它适用于我在问题中的示例。
  • @VarunM awk 中的新脚本。据我所知,获得更快的唯一方法是使用 c ... ;)
【解决方案2】:

对于这个特定的问题,我会删除最后一个数字,然后计算排序数据的出现次数:

cut -b1-3 | sort | uniq -c

在指定的输入集上给出:

  2 0.1
  1 0.3
  3 0.4
  1 0.9

输出格式可以通过这个awk命令来完成:

| awk 'BEGIN{r=0.0}
       {while($2>r){printf "%1.1f-%1.1f %3d\n",r,r+0.1,0;r=r+.1}
       printf "%1.1f-%1.1f %3d\n",$2,$2+0.1,$1}
       END{while(r<0.9){printf "%1.1f-%1.1f %3d\n",r,r+0.1,0;r=r+.1}}'

【讨论】:

  • 哈哈,创意得分,但这不是一个很好的答案。使用这种定义垃圾箱的逻辑,我不得不以 0.1 的间隔进行。如果我想以 0.05 个间隔(有 20 个 bin 而不是 10 个)执行它,那么将无法更改。
  • 这就是为什么我以针对这个特定问题开始我的回答。问题中的 bin 大小不可变。
  • 是的,你是对的。感谢这个非常聪明的答案。但在一般情况下不会真正有帮助。
  • 不适用于浮点数,但对于许多其他用例来说是一个非常有用的答案,谢谢!
【解决方案3】:

按照我之前回答的相同算法,我在 awk 中编写了一个非常快的脚本(看图片)。

脚本如下:

#!/usr/bin/awk -f

BEGIN{
    bin_width=0.1;
    
}
{
    bin=int(($1-0.0001)/bin_width);
    if( bin in hist){
        hist[bin]+=1
    }else{
        hist[bin]=1
    }
}
END{
    for (h in hist)
        printf " * > %2.2f  ->  %i \n", h*bin_width, hist[h]
}
   

bin_width 是每个通道的宽度。要使用该脚本,只需将其复制到一个文件中,使其可执行(使用chmod +x &lt;namefile&gt;)并使用./&lt;namefile&gt; &lt;name_of_data_file&gt; 运行它。

【讨论】:

  • 这太棒了!非常感谢您的帮助。
  • 您需要在脚本的开头添加一个适当的 shebang (#!) 才能像您的示例一样执行
猜你喜欢
  • 2022-01-21
  • 2021-02-19
  • 1970-01-01
  • 1970-01-01
  • 2012-02-17
  • 1970-01-01
  • 1970-01-01
  • 2017-07-27
相关资源
最近更新 更多