Skip to content

Instantly share code, notes, and snippets.

@quag
Created June 6, 2021 16:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save quag/d0081f972faae5a1ccd6a2a37bc51d46 to your computer and use it in GitHub Desktop.
Save quag/d0081f972faae5a1ccd6a2a37bc51d46 to your computer and use it in GitHub Desktop.
"""
Sample output:
```
range: 19.7 → 30.9
mean: 25.06
19.6 (0.0%)
20.0 (0.1%)
20.4 █ (0.1%)
20.8 ███ (0.4%)
21.2 ████ (0.6%)
21.6 ████████ (1.2%)
22.0 █████████████ (2.0%)
22.4 ████████████████████ (2.9%)
22.8 ████████████████████████████ (4.1%)
23.2 ████████████████████████████████████████ (5.8%)
23.6 ████████████████████████████████████████████████ (7.0%)
24.0 ████████████████████████████████████████████████████████████ (8.7%)
24.4 ███████████████████████████████████████████████████████████████████ (9.8%)
24.8 ██████████████████████████████████████████████████████████████████████ (10.2%)
25.2 ████████████████████████████████████████████████████████████████ (9.4%)
25.6 █████████████████████████████████████████████████████████████ (8.9%)
26.0 ███████████████████████████████████████████████████████ (8.0%)
26.4 ████████████████████████████████████████████ (6.4%)
26.8 ████████████████████████████████████ (5.3%)
27.2 ███████████████████████ (3.4%)
27.6 █████████████████ (2.4%)
28.0 ██████████ (1.5%)
28.4 ██████ (0.9%)
28.8 ████ (0.6%)
29.2 ██ (0.3%)
29.6 █ (0.1%)
30.0 (0.0%)
30.4 (0.0%)
30.8 (0.0%)
Questions: 0.1/0.1, 0.1/0.3, 0.1/0.7, 0.1/0.9, 0.2/0.2, 0.2/0.5, 0.2/0.6, 0.2/0.8, 0.4/0.5, 0.1/0.3/1.0, 0.1/0.6/0.9, 0.2/0.3/0.5, 0.2/0.3/0.8, 0.3/0.4/0.5, 0.3/0.4/0.9, 0.3/0.5/0.9, 0.3/0.7/0.8, 0.3/0.8/1.0, 0.4/0.5/0.7, 0.4/0.7/0.8, 0.4/0.8/0.9, 0.5/0.7/0.8, 0.5/0.9/1.0, 0.6/0.6/1.0, 0.9/0.9/0.9, 0.2/0.2/0.9/0.9, 0.2/0.3/0.5/0.7, 0.2/0.4/0.7/0.7, 0.2/0.5/0.5/0.6, 0.2/0.5/0.7/0.7, 0.3/0.3/0.4/0.9, 0.3/0.4/0.9/1.0, 0.6/0.6/0.7/0.8, 0.6/0.6/0.7/1.0, 0.1/0.1/0.4/0.6/0.9, 0.1/0.2/0.3/0.6/1.0, 0.1/0.5/0.6/0.8/1.0, 0.1/0.6/0.7/0.8/0.9, 0.1/0.7/0.7/0.9/0.9, 0.2/0.2/0.4/0.7/0.9, 0.2/0.3/0.3/0.4/0.8, 0.2/0.5/0.9/1.0/1.0, 0.3/0.3/0.6/0.6/0.9, 0.3/0.5/0.5/0.6/0.8, 0.4/0.4/0.4/0.7/1.0, 0.5/0.6/0.7/0.9/1.0, 0.7/0.7/0.7/0.8/0.8
```
"""
import random
import math
import collections
QUESTIONS = [
(0.3, 0.5, 0.5, 0.6, 0.8),
(0.3, 0.4, 0.9, 1.0),
(0.4, 0.7, 0.8),
(0.6, 0.6, 0.7, 1.0),
(0.4, 0.8, 0.9),
(0.2, 0.5, 0.5, 0.6),
(0.5, 0.9, 1.0),
(0.2, 0.2, 0.9, 0.9),
(0.7, 0.7, 0.7, 0.8, 0.8),
(0.3, 0.3, 0.4, 0.9),
(0.3, 0.8, 1.0),
(0.2, 0.5, 0.9, 1.0, 1.0),
(0.6, 0.6, 0.7, 0.8),
(0.6, 0.6, 1.0),
(0.2, 0.3, 0.3, 0.4, 0.8),
(0.1, 0.3, 1.0),
(0.2, 0.8),
(0.9, 0.9, 0.9),
(0.3, 0.3, 0.6, 0.6, 0.9),
(0.5, 0.6, 0.7, 0.9, 1.0),
(0.2, 0.5, 0.7, 0.7),
(0.2, 0.3, 0.8),
(0.3, 0.4, 0.5),
(0.2, 0.2),
(0.1, 0.6, 0.9),
(0.1, 0.7),
(0.4, 0.5),
(0.1, 0.1),
(0.5, 0.7, 0.8),
(0.1, 0.9),
(0.2, 0.2, 0.4, 0.7, 0.9),
(0.1, 0.2, 0.3, 0.6, 1.0),
(0.3, 0.5, 0.9),
(0.3, 0.7, 0.8),
(0.3, 0.4, 0.9),
(0.1, 0.7, 0.7, 0.9, 0.9),
(0.2, 0.4, 0.7, 0.7),
(0.2, 0.5),
(0.2, 0.6),
(0.4, 0.4, 0.4, 0.7, 1.0),
(0.4, 0.5, 0.7),
(0.1, 0.3),
(0.2, 0.3, 0.5, 0.7),
(0.1, 0.6, 0.7, 0.8, 0.9),
(0.2, 0.3, 0.5),
(0.1, 0.1, 0.4, 0.6, 0.9),
(0.1, 0.5, 0.6, 0.8, 1.0),
]
def generateQuestions(rng):
questions = []
for i in range(rng.randint(20, 50)):
n = rng.randint(2, 5)
answerWeights = [round(mix(0.1, 1, rng.random()), 1) for j in range(n)]
question = tuple(sorted(answerWeights))
questions.append(question)
return questions
def sampleSurvey(questions: list[tuple[float]], rng) -> int:
total: int = 0
for answerWeights in questions:
weight = rng.choice(answerWeights)
score = fixedWidth(weight)
total += score
return total
def sampleSurveys(questions, n, rng) -> list[float]:
samples = []
for i in range(n):
sample = sampleSurvey(questions, rng)
samples.append(sample)
return samples
def printHistogram(samples, approxLines=20):
p0 = min(samples)
p100 = max(samples)
mean = round(sum(samples) / len(samples), 1)
print(
f"range: {coFixedWidth(p0)} → {coFixedWidth(p100)}\nmean: {coFixedWidth(mean)}\n"
)
bucketWidth = sigfig((p100 - p0) / approxLines, 1)
counts = collections.Counter(quantize(bucketWidth, x) for x in samples)
largest = counts.most_common(1)[0][1]
maxBarLength = 70
for bucket, count in sorted(counts.items()):
barLength = round(mix(0, maxBarLength, coMix(0, largest, count)))
print(
coFixedWidth(bucket),
"█" * barLength,
f" ({round(100 * count / len(samples), 1)}%)",
)
def fixedWidth(x: float) -> int:
return int(x * 1000)
def coFixedWidth(x: int) -> int:
return round(x / 1000, 2)
def mix(e0, e1, x):
return x * (e1 - e0) + e0
def coMix(e0, e1, y):
return (y - e0) / (e1 - e0)
def sigfig(x, sig=2):
return round(x, sig - int(math.floor(math.log10(abs(x)))) - 1)
def quantize(quantum, x):
return math.trunc(x / quantum) * quantum
def main():
rng = random.Random(0)
if False:
questions = generateQuestions(rng)
print(questions)
else:
questions = QUESTIONS
samples = sampleSurveys(questions, 10000, rng)
printHistogram(samples, 30)
print("\nQuestions: ", end="")
print(
", ".join(
sorted(
["/".join(str(y) for y in x) for x in questions],
key=lambda z: (len(z), z),
)
)
)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment