Calculating frequency of values within bins

Hi, I am working with files containing 2 columns in which i need to come up with the frequency/count of values in col. 2 falling within specifics binned values of col. 1. the contents of a sample file is shown below:

 
15 12.5
15 11.2
16 0.2
16 1.4
17 1.6
18 4.5
17 5.6
12 8.6
11 7.2
9  2.3      
my desired output will be something like this (3 column output).  
9-10 val. of col.2 falling within this bin freq
11-12 val. of col.2 falling within this bin freq
13-14 val. of col.2 falling within this bin freq
15-16 val. of col.2 falling within this bin freq
17-18 val. of col.2 falling within this bin freq

i want to visualize the resulting output into a figure like this. hope u can help me sort this out. many thanks.

Can you post the exact output with numbers that should be achieved for the sample data that you provided?

I am not going to draw your graph but regarding the calculation maybe this will help (i hope i did not missunderstood your requirements):

awk 'BEGIN{m=M=0}{A[$1]+=$2;++B[$1];m=($1<m)?$1:m;M=($1>M)?$1:M}END{for(i=m;i<M;i++) if (i in B) {print i"-"i+1": "B+0,"values have their $1 in "i " and the sum of their $2 is "A+0}}' yourfile
$ cat mytst
15 12.5
15 11.2
16 0.2
16 1.4
17 1.6
18 4.5
17 5.6
12 8.6
11 7.2
9  2.3
$ awk 'BEGIN{m=M=0}{A[$1]+=$2;++B[$1];m=($1<m)?$1:m;M=($1>M)?$1:M}END{for(i=m;i<=M;i++) if (i in B) {print i"-"i+1": "B+0,"values have their $1 in "i " and the sum of their $2 is "A+0}}' mytst
9-10: 1 values have their $1 in 9 and the sum of their $2 is 2.3
11-12: 1 values have their $1 in 11 and the sum of their $2 is 7.2
12-13: 1 values have their $1 in 12 and the sum of their $2 is 8.6
15-16: 2 values have their $1 in 15 and the sum of their $2 is 23.7
16-17: 2 values have their $1 in 16 and the sum of their $2 is 1.6
17-18: 2 values have their $1 in 17 and the sum of their $2 is 7.2
18-19: 1 values have their $1 in 18 and the sum of their $2 is 4.5

Hi guys, thanks for the replies. I hope i can explain the criteria better for my desired output, my apologies. Anyway, the basic idea will be to compute for the mean of values of column 2 falling on specific bin, where bin ranges are initially determined from the min and max values of column 1. Below is the sample data I am working.

Based on min (9.662971860) & max (19.04534982) values of column 1, I need to create an array containing my bin ranges say "arraybin". then, I need to go through the data in column 1, and identify which bin number does each value falls giving me an output "whichbin".

Now, the final step will be to calculate for the average of column 2 from the original data based on the arraybin assignment. the end output will be something like this one.

endoutput=
arraybin average of col. 2
9-10  9.662971860
11-12 12.37139173
13-14 13.73474782
15-16 16.10586498
17-18 17.28483688
19-20 19.04534982
whichbin=
col.1 values  arraybin assignment
12.6318352458 2 
12.0566193203 2
13.2302267715 3
12.0116097615 2
13.310066457  3
12.0118300038 2
12.0887778114 2
13.7107875841 3
12.9565490722 2
12.0617174502 2
12.1672836452 2
12.0956200447 2
12.3911778903 2
14.173625486  3
12.9012203275 2
11.2007593792 2
9.66297186014 1
12.5666761127 2
12.6919820568 2
13.0367574336 3
12.7637326677 2
14.9655179679 3
13.5666439876 3
15.9240500895 4
16.7596231894 4
13.8307211439 3
17.1159829995 5
13.7381931446 3
15.4617357782 4
13.9926310027 3
14.3019600635 3
16.571361985  4
13.386336958  3
14.6119437607 3
14.6271410249 3
16.4103756709 4
17.4536907641 5
13.8739825546 3
12.8456365048 2
12.4519526598 2
13.1417111191 3
13.3157434671 3
13.0941859655 3
19.0453498227 6
12.7900711291 2
13.17760558   3
13.4821577599 3
13.0229460206 3
13.2783780649 3
13.8176612104 3
16.2109653259 4
15.7580809633 4
15.7507268703 4
arraybin=( 9-10 11-12 13-14 15-16 17-18 19-20 )
12.6318352458 3.296900
12.0566193203 4.166667
13.2302267715 1.101667
12.0116097615 1.763333
13.310066457  3.523125
12.0118300038 2.439231
12.0887778114 2.250000
13.7107875841 1.176667
12.9565490722 3.250714
12.0617174502 2.563333
12.1672836452 3.172857
12.0956200447 3.104667
12.3911778903 8.070000
14.173625486  3.148333
12.9012203275 2.960000
11.2007593792 1.902727
9.66297186014 3.089286
12.5666761127 2.970000
12.6919820568 3.123333
13.0367574336 3.540769
12.7637326677 3.000000
14.9655179679 9.322000
13.5666439876 12.570000
15.9240500895 5.972941
16.7596231894 10.222000
13.8307211439 9.336250
17.1159829995 6.040667
13.7381931446 12.260000
15.4617357782 10.424762
13.9926310027 16.070000
14.3019600635 9.004348
16.571361985  11.002778
13.386336958  9.762857
14.6119437607 9.516522
14.6271410249 6.730909
16.4103756709 9.751429
17.4536907641 19.626522
13.8739825546 11.684444
12.8456365048 11.530000
12.4519526598 10.110476
13.1417111191 11.124583
13.3157434671 11.187059
13.0941859655 13.176667
19.0453498227 13.787143
12.7900711291 11.840588
13.17760558   11.367222
13.4821577599 8.538750
13.0229460206 11.180588
13.2783780649 9.555652
13.8176612104 14.691250
16.2109653259 21.295200
15.7580809633 20.223600
15.7507268703 19.763333

bunch of thanks as always.

Not sure to understand your requirements especially the way you calculate your average (or the given example is not accurate?)

$ awk 'BEGIN{m=M=0}{e=int($1);A[e]+=$2;++B[e];m=($1<m)?$1:m;M=($1>M)?$1:M}END{for(i=int(m);i<=int(M);i+=2) {while(!(i in B)){i++};print i"-"i+1": "B+B[i+1],"values of $1 fall in that bin and the average of their $2 is "(A+A[i+1])/(B+B[i+1])}}' mytst
9-10: 1 values of $1 fall in that bin and the average of their $2 is 3.08929
11-12: 18 values of $1 fall in that bin and the average of their $2 is 4.5286
13-14: 23 values of $1 fall in that bin and the average of their $2 is 9.11172
15-16: 8 values of $1 fall in that bin and the average of their $2 is 13.582
17-18: 2 values of $1 fall in that bin and the average of their $2 is 12.8336
19-20: 1 values of $1 fall in that bin and the average of their $2 is 13.7871

---------- Post updated at 11:42 AM ---------- Previous update was at 11:30 AM ----------

Or If you just don't care of $2 because not needed, then :

$ awk 'BEGIN{m=M=0}{e=int($1);A[e]+=$1;++B[e];m=($1<m)?$1:m;M=($1>M)?$1:M}END{for(i=int(m);i<=int(M);i+=2) {while(!(i in B)){i++};print i"-"i+1": "B+B[i+1],"values of $1 fall in that bin and the average of their $1 is "(A+A[i+1])/(B+B[i+1])}}' mytst
9-10: 1 values of $1 fall in that bin and the average of their $1 is 9.66297
11-12: 18 values of $1 fall in that bin and the average of their $1 is 12.3714
13-14: 23 values of $1 fall in that bin and the average of their $1 is 13.682
15-16: 8 values of $1 fall in that bin and the average of their $1 is 16.1059
17-18: 2 values of $1 fall in that bin and the average of their $1 is 17.2848
19-20: 1 values of $1 fall in that bin and the average of their $1 is 19.0453

yeah, the sample average i just posted on the end output is wrongly calculated. thanks for the reply, i'll try to run your code and will get back to you for feedback. many many thanks.

Just another try (if the range array is built from $1 values and if the average is calculated from the $2 value falling into those ranges):

$ awk '{
A[int($2)]+=$2
B[int($1)]++
N[int($2)]++
m=($1<m)?$1:m
M=(M<$1)?$1:M
}END{
for(i=m;i<=M;i+=2){
while(!(i in B)){i++}
z=N+N[i+1]
print i"-"i+1,":",z,"values of $2 fall in that bin and their average is",(z<=0?"not available":(A+A[i+1])/z)
}
}' yourfile
9-10 : 10 values of $2 fall in that bin and their average is 9.70063
11-12 : 10 values of $2 fall in that bin and their average is 11.5747
13-14 : 3 values of $2 fall in that bin and their average is 13.885
15-16 : 1 values of $2 fall in that bin and their average is 16.07
17-18 : 0 values of $2 fall in that bin and their average is not available
19-20 : 3 values of $2 fall in that bin and their average is 19.8712

hi, big thanks. do u mind, if u briefly walk me through the updated version of your code? I don't fully understood this part of the code.

m=($1<m)?$1:m
M=(M<$1)?$1:M 

thanks!

This part just setup the min (m) and max (M) values taken by $1

m=($1<m)?$1:m

means :

m=(is $1 lower than m)? if yes,takes $1 : otherwise takes m

1 Like

Hi ctsgnb,
Thanks for the replies and help. my apologies, havent get back to u sooner.

Be carefull : all the attempt i posted do different things.

In order to make sure it really fit with your expectations, do not pick them up until you are fully understanding what it does.

If you have any questions, feel free to shoot.

hi ctsgnb, bunch of thanks really. Ive found a code in matlab that does the calculation i wanted. i just dont know how to translate it in unix.

clear all 
load data 
x=data(:,1); 
y=data(:,2); 
 
topEdge=16; 
botEdge=-16; 
numBins=16; 
 
binEdges=linspace(botEdge, topEdge, numBins+1); 
 
[h, whichbin]=histc(x,binEdges); 
 
for i=1:numBins+1 
    flagBinMembers = (whichbin ==i); 
    binMembers = y(flagBinMembers); 
    binMean(i)= mean(binMembers); 
end 
 

I don't know Matlab, sorry ...

thanks for all your help. anyways, on your last posted code, is there a way to tweak it that instead of bin ranges, it would be linearly spaced bin values. for instance, it would be:

bin=(9,10,11,12,13,14,15,16,17,18,19,20)

so that it will give a mean of col.2 falling on this linearly spaced values of col.1?the output will then be:

9- mean of col2 values with col.1 values falling within this bin
10- mean of col2 values with col. 1 values falling within this bin
and so on...  

thanks again