0

Say I have the following class:

class Vehicle:

    def __init__(self, pevtype):
        self.pevtype = pevtype

How can I write a function which uses a probability distribution to determine whether the vehicle is an EV or a PHEV?

For example, the function setVehicle() would enable:

>>> v1.pevtype = 'EV'
>>> v2.pevtype = 'PHEV'
grimrol123
  • 21
  • 5

2 Answers2

2

You can use random.choices from the standard library.

import random
values = ['EV', 'PHEV']
for _ in range(10):
    result = random.choices(values, weights=(0.3, 0.7))
    print(result[0], end=' ')

Example output: PHEV EV PHEV PHEV PHEV PHEV PHEV PHEV EV EV


Additional info: You're not limited to just 2 options and you can get multiple results.

import random
values = ['A', 'B', 'C']
for _ in range(10):
    result = random.choices(values, weights=(1, 4, 10), k=2)
    print(result)

Example output:

['B', 'C']
['B', 'C']
['C', 'C']
['C', 'C']
['C', 'B']
['C', 'B']
['B', 'C']
['C', 'C']
['C', 'C']
['B', 'C']

This is a possible implementation including the code from the question. Here I assume that the pev types and their probability are fixed in the code, so I made them an attribute of the class Vehicle. This can be changed as needed. Note that the distributions are relative and don't have to add up to exactly 1.0.

import random

class Vehicle:
    pev_types = {'EV': 0.3, 'PHEV': 0.7, 'X': 0.2}

    def __init__(self):
        self.pev_type = self._get_random_pev_type()

    def __str__(self):
        return f'Vehicle (pev type:{self.pev_type})'

    def _get_random_pev_type(self):
        return random.choices(list(self.pev_types), weights=self.pev_types.values())[0]

print(', '.join(str(Vehicle()) for _ in range(10)))

Example output:

Vehicle (EV), Vehicle (EV), Vehicle (X), Vehicle (PHEV), Vehicle (PHEV), Vehicle (X), Vehicle (PHEV), Vehicle (PHEV), Vehicle (PHEV), Vehicle (PHEV)
Matthias
  • 12,873
  • 6
  • 42
  • 48
  • You can also store the choices and the weights together: `values = {'A': 1, 'B': 4, 'C': 10}` and `random.choices(values, weights=values.values(), k=2)`. Even in older Python versions, where `dict` order wasn't preserved, it is *consistent* between multiple iterations. – chepner May 05 '20 at 12:00
  • Thank you for adding this suggestion. I thought about adding that example but I feared it would look like a rip-off from the other answer. – Matthias May 05 '20 at 12:06
  • I think the most important part of this answer is that it's not using an external library. – chepner May 05 '20 at 12:12
  • You can rip it off if you like! At what point does it make sense to use `numpy` for something like this though? I would have thought that `numpy` is faster, but maybe not. – mapf May 05 '20 at 12:16
0

You could use numpy.random.choice. It takes a list of items that you want to chose from, and you can pass it the probability associated with each item as well. In the following example, I stored the information in a dict, where the keys are the items you want to chose from, and the values are the respective probabilities:

import numpy as np


class Vehicle:
    def __init__(self, pevtypes):
        self.pevtype = np.random.choice(
            list(pevtypes), p=list(pevtypes.values())
        )

car_types = {'EV': 0.3, 'PHEV': 0.7}

# for a single car
car = Vehicle(car_types)

print(car.pevtype)

# for 2 or more cars e.g. like this
cars = [Vehicle(car_types) for _ in range(3)]
mapf
  • 1,906
  • 1
  • 14
  • 40
  • Say you would do this for a different no of vehicles (100,200,300...) such that it would return vehicles (v1, v2,...,vn) with the attribute EV or PHEV. How would you do that? – grimrol123 May 05 '20 at 11:50
  • You just loop over the assignment. I edited the example. – mapf May 05 '20 at 11:54