We have a distribution of probability of a discrete variable (it may have only integer values)
```
x       P(x)
0       0.125
1       0.375
2       0.375
3       0.125
Total = 1.000   # The sum of the probabilities for all the possible values should be one (=1)
```
The mean, ```μ```,  of the values of x is:



For our example
```
μ = 0*0.125 + 1*0.375 + 2*0.375 + 3*0.125 = 1.5
```

The variance, ```σ²``` is:



For our example :
```
σ² = 0.75
```

The standard deviation, ```σ``` is:



Finally, for our example:
```
σ = 0.8660254037844386
```
Make the function ```stats_disc_distr()``` that receives a 2D array. Each internal array will have a pair of values: the first one, the value of the variable ```x``` and the second one its correspondent probability, ```P(x)```.

For the example given above:
```python
stats_disc_distr([[0, 0.125], [1, 0.375], [2, 0.375], [3, 0.125]]) == [1.5, 0.75, 0.8660254037844386]
```
The function should check also if it is a valid distribution.

If the sum of the probabilities is different than ```1```, the function should output an alert.
```python
stats_disc_distr([[0, 0.425], [1, 0.375], [2, 0.375], [3, 0.125]]) == "It's not a valid distribution"
```
If one of the values of ```x``` is not an integer, the function will give a specific alert:
```python
stats_disc_distr([[0.1, 0.425], [1.1, 0.375], [2, 0.375], [3, 0.125]]) == "All the variable values should be integers"
```

If the distribution has both problems will output another specific alert:
```python
stats_disc_distr([[0.1, 0.425], [1.1, 0.375], [2, 0.375], [3, 0.125]]) == "It's not a valid distribution and furthermore, one or more variable value are not integers"
```
But if a value is a float with its decimal part equals to 0 will proceed without inconveniences, (if the sum of probabilities is ```1```:
```python
stats_disc_distr([[0.0, 0.125], [1.0, 0.375], [2.0, 0.375], [3, 0.125]]) == [1.5, 0.75, 0.8660254037844386]
```

The 2Darray will not have any strings.

Enjoy it!!

Source: codewars | Difficulty: EASY
Tags: Mathematics

Probability

Starter code: def stats_disc_distr(distrib):
	

Solutions:
def stats_disc_distr(distrib):
	err = check_errors(distrib)
	if not err:
		mean = sum((x[0] * x[1] for x in distrib))
		var = sum(((x[0] - mean) ** 2 * x[1] for x in distrib))
		std_dev = var ** 0.5
	return [mean, var, std_dev] if not err else err

def check_errors(distrib):
	errors = 0
	if not isclose(sum((x[1] for x in distrib)), 1):
		errors += 1
	if not all((isinstance(x[0], int) for x in distrib)):
		errors += 2
	if errors > 0:
		return {1: "It's not a valid distribution", 2: 'All the variable values should be integers', 3: "It's not a valid distribution and furthermore, one or more variable value are not integers"}[errors]

def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
	return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)


def stats_disc_distr(distrib):
	dist = abs(sum((px for (x, px) in distrib)) - 1) < 1e-05
	all_int = all((isinstance(x, int) for (x, px) in distrib))
	if not dist:
		if not all_int:
			return "It's not a valid distribution and furthermore, one or more variable value are not integers"
		return "It's not a valid distribution"
	if not all_int:
		return 'All the variable values should be integers'
	u = sum((x * px for (x, px) in distrib))
	o2 = sum((abs((x - u) ** 2 * px) for (x, px) in distrib))
	o = o2 ** 0.5
	return [u, o2, o]


def stats_disc_distr(arr):
	a = round(sum((float(i[1]) for i in arr)), 2) != 1
	b = not all((int(i[0]) == i[0] for i in arr))
	if a and b:
		return "It's not a valid distribution and furthermore, one or more variable value are not integers"
	if a:
		return "It's not a valid distribution"
	if b:
		return 'All the variable values should be integers'
	_mean = sum((i[0] * i[1] for i in arr))
	_var = sum(((i[0] - _mean) ** 2 * i[1] for i in arr))
	_sdt = _var ** 0.5
	return [_mean, _var, _sdt]


from __future__ import division
import numpy as np

def stats_disc_distr(distrib):
	print(distrib)
	values = [i[0] for i in distrib]
	probs = [i[1] for i in distrib]
	if any((type(i) != int for i in values)) and float(sum(probs)) != 1.0:
		return "It's not a valid distribution and furthermore, one or more variable value are not integers"
	elif sum(probs) > 1.0 + 1e-05 or sum(probs) < 1.0 - 1e-05:
		print(sum(probs))
		return "It's not a valid distribution"
	elif any((type(i) != int for i in values)):
		return 'All the variable values should be integers'
	mean = np.mean(values)
	var = sum([(values[i] - mean) ** 2 * probs[i] for i in range(len(values))])
	std_dev = var ** 0.5
	return [mean, var, std_dev]


def stats_disc_distr(distrib):
	(values, probs) = zip(*distrib)
	probs_is_not_one = abs(sum(probs) - 1) > 1e-08
	values_are_not_ints = any((value % 1 for value in values))
	if probs_is_not_one and values_are_not_ints:
		return "It's not a valid distribution and furthermore, one or more variable value are not integers"
	elif values_are_not_ints:
		return 'All the variable values should be integers'
	elif probs_is_not_one:
		return "It's not a valid distribution"
	mean = sum((value * prob for (value, prob) in distrib))
	var = sum(((value - mean) ** 2 * prob for (value, prob) in distrib))
	std_dev = var ** 0.5
	return [mean, var, std_dev]


def stats_disc_distr(distrib):
	is_valid_distribution = lambda d: abs(sum((px for (x, px) in d)) - 1) < 1e-08
	are_events_integers = lambda d: all((isinstance(x, (int, float)) and float(x).is_integer() for (x, px) in d))
	(events, probabilities) = (are_events_integers(distrib), is_valid_distribution(distrib))
	if not events and (not probabilities):
		return "It's not a valid distribution and furthermore, one or more variable value are not integers"
	elif not probabilities:
		return "It's not a valid distribution"
	elif not events:
		return 'All the variable values should be integers'
	mean = sum((x * px for (x, px) in distrib))
	var = sum(((x - mean) ** 2 * px for (x, px) in distrib))
	std_dev = var ** 0.5
	return [mean, var, std_dev]


from math import sqrt

def stats_disc_distr(distrib):
	if round(sum((count[1] for count in distrib)), 3) != 1:
		if not all((isinstance(count[0], int) for count in distrib)):
			return "It's not a valid distribution and furthermore, one or more variable value are not integers"
		else:
			return "It's not a valid distribution"
	if not all((isinstance(count[0], int) for count in distrib)):
		return 'All the variable values should be integers'
	expected = sum((event * prob for (event, prob) in distrib))
	variance = sum(((event - expected) ** 2 * prob for (event, prob) in distrib))
	standard = sqrt(variance)
	return [expected, variance, standard]


stats_disc_distr = lambda d: (lambda m: "It's not a valid distribution and furthermore, one or more variable value are not integers" if round(sum((k for (i, k) in d)), 8) != 1 and any((type(i) != int for (i, k) in d)) else "It's not a valid distribution" if round(sum((k for (i, k) in d)), 8) != 1 else 'All the variable values should be integers' if any((type(i) != int for (i, k) in d)) else [m, sum((k * (i - m) ** 2 for (i, k) in d)), sum((k * (i - m) ** 2 for (i, k) in d)) ** 0.5])(sum((i * k for (i, k) in d)))


def stats_disc_distr(distrib):
	print(sum((p for (x, p) in distrib)))
	if abs(sum((p for (x, p) in distrib)) - 1) > 0.0001:
		if not all((x % 1 == 0 for (x, p) in distrib)):
			return "It's not a valid distribution and furthermore, one or more variable value are not integers"
		return "It's not a valid distribution"
	if not all((x % 1 == 0 for (x, p) in distrib)):
		return 'All the variable values should be integers'
	mean = sum((x * p for (x, p) in distrib))
	var = sum(((x - mean) ** 2 * p for (x, p) in distrib))
	std_dev = var ** 0.5
	return [mean, var, std_dev]


import math

def stats_disc_distr(disv):
	m = 0
	v = 0
	p = 0
	ni = False
	for dis in disv:
		if type(dis[0]) != int:
			ni = True
		p = p + dis[1]
		m = m + dis[0] * dis[1]
	if ni == False:
		for dis in disv:
			v += (dis[0] - m) * (dis[0] - m) * dis[1]
	if ni:
		return "It's not a valid distribution and furthermore, one or more variable value are not integers" if math.fabs(p - 1) > 1e-10 else 'All the variable values should be integers'
	if math.fabs(p - 1) > 1e-10:
		return "It's not a valid distribution"
	return [m, v, v ** 0.5]