# your code goes here
# your code goes here
import numpy as np
# consider you have an array like this
a= [1, 2, 3, 5, 10,11, 12, 13, 14, 15, 21,23, 25, 26, 27, 29, 30,31, 35, 51]
# here we have decided to group all these numbers into 5 bins
# i.e bins = 5
# the minimum number in the array is 1
# the maximum number in the array is 51
# the width of each bin is calculated as = ((max - min) / bins)
# width of each bin = (51-1)/5 = 10
# Since we got each bin with as 10, we can choose the bin edges like this
# 1 ...... 11 ....... 21 ........ 31 ....... 41 ....... 51
# |---10---|----10----|----10-----|----10----|----10----|
# so we have found out the bin edges now
# to find thte counts we calcuate how many number of points fall into each bin
# therefore the count of a bin = number of elements of a such that left_bin_egde<=ai<right_bin_edges
# i. number of elements belongs to the 1st bin 1<=x<11 => 5 [1,2,3,5,10]
# ii. number of elements belongs to the 2nd bin 11<=x<21 => 5 [11,12,13,14,15]
# iii. number of elements belongs to the 3rd bin 21<=x<31 => 7 [21,23,25,26,27,29,30]
# iii. number of elements belongs to the 3rd bin 21<=x<31 => 7 [21,23,25,26,27,29,30]
# iv. number of elements belongs to the 4th bin 31<=x<41 => 2 [31,35]
# v. number of elements belongs to the 5th bin 41<=x<=51 => 1 [51]
# note: from the documentation: https://d...content-available-to-author-only...y.org/doc/numpy/reference/generated/numpy.histogram.html
# All but the last (righthand-most) bin is half-open i.e [1,2,3,4], the bins are [1,2), [2,3), [3,4]
print('='*30, "explaining 'bin edges and counts",'='*30)
counts,bins = np.histogram(a, bins=5)
print("bin edges :",bins)
print("counts per each bin :",counts)
# density : bool, optional
# If False, the result will contain the number of samples in each bin.
# If True, the result is the value of the probability density function at the bin, normalized such that the integral over the range is 1.
# Note that the sum of the histogram values will not be equal to 1 unless bins of unity width are chosen;
# it is not a probability mass function.
# and from the source code
#if density:
# db = np.array(np.diff(bin_edges), float)
# return n/db/n.sum(), bin_edges
# here the n => number of elements for each bin
n = counts
# and db = difference between bin edges
db = np.array(np.diff(bins))
# n.sum() number of all the elemnts
print('='*30, "explaining 'density=True' parameter",'='*30)
print("manual calculated densities for each bin",counts/db/counts.sum())
counts, bins = np.histogram(a, bins=5, density=True)
print("bin edges :",bins)
print("counts per each bin using density=True:",counts)
print('='*30, "explaining counts/sum(counts)",'='*30)
# pleasen note that the documentation says when you have density=True,
# "that the sum of the histogram values will not be equal to 1"
# this is simple logic we used, to make the whole sum=1, we have devided each element by the number of whole elemnets
counts, bins = np.histogram(a, bins=5, density=True)
print("bin edges :",bins)
print("counts per each bin using density=True:",counts/sum(counts))
IyB5b3VyIGNvZGUgZ29lcyBoZXJlCiMgeW91ciBjb2RlIGdvZXMgaGVyZQppbXBvcnQgbnVtcHkgYXMgbnAKIyBjb25zaWRlciB5b3UgaGF2ZSBhbiBhcnJheSBsaWtlIHRoaXMKYT0gWzEsIDIsIDMsIDUsIDEwLDExLCAxMiwgMTMsIDE0LCAxNSwgMjEsMjMsIDI1LCAyNiwgMjcsIDI5LCAzMCwzMSwgMzUsIDUxXQojIGhlcmUgd2UgaGF2ZSBkZWNpZGVkIHRvIGdyb3VwIGFsbCB0aGVzZSBudW1iZXJzIGludG8gNSBiaW5zCiMgaS5lIGJpbnMgPSA1CiMgdGhlIG1pbmltdW0gbnVtYmVyIGluIHRoZSBhcnJheSBpcyAxCiMgdGhlIG1heGltdW0gbnVtYmVyIGluIHRoZSBhcnJheSBpcyA1MQojIHRoZSB3aWR0aCBvZiBlYWNoIGJpbiBpcyBjYWxjdWxhdGVkIGFzID0gKChtYXggLSBtaW4pIC8gYmlucykKIyB3aWR0aCBvZiBlYWNoIGJpbiA9ICg1MS0xKS81ID0gMTAKIyBTaW5jZSB3ZSBnb3QgZWFjaCBiaW4gd2l0aCBhcyAxMCwgd2UgY2FuIGNob29zZSB0aGUgYmluIGVkZ2VzIGxpa2UgdGhpcwojIDEgLi4uLi4uIDExIC4uLi4uLi4gMjEgLi4uLi4uLi4gMzEgLi4uLi4uLiA0MSAuLi4uLi4uIDUxCiMgfC0tLTEwLS0tfC0tLS0xMC0tLS18LS0tLTEwLS0tLS18LS0tLTEwLS0tLXwtLS0tMTAtLS0tfAojIHNvIHdlIGhhdmUgZm91bmQgb3V0IHRoZSBiaW4gZWRnZXMgbm93CiMgdG8gZmluZCB0aHRlIGNvdW50cyB3ZSBjYWxjdWF0ZSBob3cgbWFueSBudW1iZXIgb2YgcG9pbnRzIGZhbGwgaW50byBlYWNoIGJpbgojIHRoZXJlZm9yZSB0aGUgY291bnQgb2YgYSBiaW4gPSBudW1iZXIgb2YgZWxlbWVudHMgb2YgYSBzdWNoIHRoYXQgbGVmdF9iaW5fZWdkZTw9YWk8cmlnaHRfYmluX2VkZ2VzCiMgaS4gbnVtYmVyIG9mIGVsZW1lbnRzIGJlbG9uZ3MgdG8gdGhlIDFzdCBiaW4gMTw9eDwxMSA9PiA1IFsxLDIsMyw1LDEwXQojIGlpLiBudW1iZXIgb2YgZWxlbWVudHMgYmVsb25ncyB0byB0aGUgMm5kIGJpbiAxMTw9eDwyMSA9PiA1IFsxMSwxMiwxMywxNCwxNV0KIyBpaWkuIG51bWJlciBvZiBlbGVtZW50cyBiZWxvbmdzIHRvIHRoZSAzcmQgYmluIDIxPD14PDMxID0+IDcgWzIxLDIzLDI1LDI2LDI3LDI5LDMwXQojIGlpaS4gbnVtYmVyIG9mIGVsZW1lbnRzIGJlbG9uZ3MgdG8gdGhlIDNyZCBiaW4gMjE8PXg8MzEgPT4gNyBbMjEsMjMsMjUsMjYsMjcsMjksMzBdCiMgaXYuIG51bWJlciBvZiBlbGVtZW50cyBiZWxvbmdzIHRvIHRoZSA0dGggYmluIDMxPD14PDQxID0+IDIgWzMxLDM1XQojIHYuIG51bWJlciBvZiBlbGVtZW50cyBiZWxvbmdzIHRvIHRoZSA1dGggYmluIDQxPD14PD01MSA9PiAxIFs1MV0KCiMgbm90ZTogZnJvbSB0aGUgZG9jdW1lbnRhdGlvbjogaHR0cHM6Ly9kLi4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi55Lm9yZy9kb2MvbnVtcHkvcmVmZXJlbmNlL2dlbmVyYXRlZC9udW1weS5oaXN0b2dyYW0uaHRtbAojIEFsbCBidXQgdGhlIGxhc3QgKHJpZ2h0aGFuZC1tb3N0KSBiaW4gaXMgaGFsZi1vcGVuIGkuZSBbMSwyLDMsNF0sIHRoZSBiaW5zIGFyZSBbMSwyKSwgWzIsMyksIFszLDRdCnByaW50KCc9JyozMCwgImV4cGxhaW5pbmcgJ2JpbiBlZGdlcyBhbmQgY291bnRzIiwnPScqMzApCmNvdW50cyxiaW5zID0gbnAuaGlzdG9ncmFtKGEsIGJpbnM9NSkKCnByaW50KCJiaW4gZWRnZXMgOiIsYmlucykKcHJpbnQoImNvdW50cyBwZXIgZWFjaCBiaW4gOiIsY291bnRzKQoKIyBkZW5zaXR5IDogYm9vbCwgb3B0aW9uYWwKIyBJZiBGYWxzZSwgdGhlIHJlc3VsdCB3aWxsIGNvbnRhaW4gdGhlIG51bWJlciBvZiBzYW1wbGVzIGluIGVhY2ggYmluLiAKIyBJZiBUcnVlLCB0aGUgcmVzdWx0IGlzIHRoZSB2YWx1ZSBvZiB0aGUgcHJvYmFiaWxpdHkgZGVuc2l0eSBmdW5jdGlvbiBhdCB0aGUgYmluLCBub3JtYWxpemVkIHN1Y2ggdGhhdCB0aGUgaW50ZWdyYWwgb3ZlciB0aGUgcmFuZ2UgaXMgMS4gCiMgTm90ZSB0aGF0IHRoZSBzdW0gb2YgdGhlIGhpc3RvZ3JhbSB2YWx1ZXMgd2lsbCBub3QgYmUgZXF1YWwgdG8gMSB1bmxlc3MgYmlucyBvZiB1bml0eSB3aWR0aCBhcmUgY2hvc2VuOwojIGl0IGlzIG5vdCBhIHByb2JhYmlsaXR5IG1hc3MgZnVuY3Rpb24uCgojIGFuZCBmcm9tIHRoZSBzb3VyY2UgY29kZQojaWYgZGVuc2l0eToKIyAgICAgICAgZGIgPSBucC5hcnJheShucC5kaWZmKGJpbl9lZGdlcyksIGZsb2F0KQojICAgICAgICByZXR1cm4gbi9kYi9uLnN1bSgpLCBiaW5fZWRnZXMKCiMgaGVyZSB0aGUgbiA9PiBudW1iZXIgb2YgZWxlbWVudHMgZm9yIGVhY2ggYmluCm4gPSBjb3VudHMKIyBhbmQgZGIgPSBkaWZmZXJlbmNlIGJldHdlZW4gYmluIGVkZ2VzCmRiID0gbnAuYXJyYXkobnAuZGlmZihiaW5zKSkKIyBuLnN1bSgpIG51bWJlciBvZiBhbGwgdGhlIGVsZW1udHMgCgoKcHJpbnQoJz0nKjMwLCAiZXhwbGFpbmluZyAnZGVuc2l0eT1UcnVlJyBwYXJhbWV0ZXIiLCc9JyozMCkKcHJpbnQoIm1hbnVhbCBjYWxjdWxhdGVkIGRlbnNpdGllcyBmb3IgZWFjaCBiaW4iLGNvdW50cy9kYi9jb3VudHMuc3VtKCkpCgpjb3VudHMsIGJpbnMgPSBucC5oaXN0b2dyYW0oYSwgYmlucz01LCBkZW5zaXR5PVRydWUpCgpwcmludCgiYmluIGVkZ2VzIDoiLGJpbnMpCnByaW50KCJjb3VudHMgcGVyIGVhY2ggYmluIHVzaW5nIGRlbnNpdHk9VHJ1ZToiLGNvdW50cykKCnByaW50KCc9JyozMCwgImV4cGxhaW5pbmcgY291bnRzL3N1bShjb3VudHMpIiwnPScqMzApCiMgcGxlYXNlbiBub3RlIHRoYXQgdGhlIGRvY3VtZW50YXRpb24gc2F5cyB3aGVuIHlvdSBoYXZlIGRlbnNpdHk9VHJ1ZSwgCiMgInRoYXQgdGhlIHN1bSBvZiB0aGUgaGlzdG9ncmFtIHZhbHVlcyB3aWxsIG5vdCBiZSBlcXVhbCB0byAxIgoKIyB0aGlzIGlzIHNpbXBsZSBsb2dpYyB3ZSB1c2VkLCB0byBtYWtlIHRoZSB3aG9sZSBzdW09MSwgd2UgaGF2ZSBkZXZpZGVkIGVhY2ggZWxlbWVudCBieSB0aGUgbnVtYmVyIG9mIHdob2xlIGVsZW1uZXRzCgpjb3VudHMsIGJpbnMgPSBucC5oaXN0b2dyYW0oYSwgYmlucz01LCBkZW5zaXR5PVRydWUpCgpwcmludCgiYmluIGVkZ2VzIDoiLGJpbnMpCnByaW50KCJjb3VudHMgcGVyIGVhY2ggYmluIHVzaW5nIGRlbnNpdHk9VHJ1ZToiLGNvdW50cy9zdW0oY291bnRzKSk=