mirror of
https://github.com/velocitatem/PHANTOM.git
synced 2026-05-31 08:33:36 +00:00
chore: properly developing
This commit is contained in:
48
engine/lib/behavior.py
Normal file
48
engine/lib/behavior.py
Normal file
@@ -0,0 +1,48 @@
|
||||
from sim.rl.behavior_loader.models import BehaviorModel, AgentBehaviorModel, aggregate_event_transitions
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from .demand import generate_demand
|
||||
|
||||
base_dir = "/home/velocitatem/Documents/Projects/PHANTOM/experiments"
|
||||
human_dir, agent_dir = f"{base_dir}/collected_data/", f"{base_dir}/agents/collected_data/"
|
||||
|
||||
|
||||
def adjust_behavior_to_condition(condition, transition_matrix):
|
||||
# transition matrix just maps probability of eventA to eventB
|
||||
# we enhance this that eventA-productI to eventB-productJ... based on the condition of interest
|
||||
# this is to simulate the impact of demand onto the behavior
|
||||
# NxN -> (N*(P + 1))x(N*(P + 1)) where P is number of products
|
||||
new_transitions = transition_matrix.copy()
|
||||
for col in new_transitions.columns:
|
||||
for product in range(len(condition)):
|
||||
# adjust the transition probability based on the demand condition
|
||||
newname = f"{col}_product{product}"
|
||||
new_transitions[newname] = new_transitions[col] * (condition[product] / np.sum(condition))
|
||||
for row in transition_matrix.index:
|
||||
for product in range(len(condition)):
|
||||
newname = f"{row}_product{product}"
|
||||
new_transitions.loc[newname] = new_transitions.loc[row] * (condition[product] / np.sum(condition))
|
||||
|
||||
return new_transitions.fillna(0.0)
|
||||
|
||||
def sample_behavior(condition, human=True, max_len=40):
|
||||
model = BehaviorModel(human_dir) if human else AgentBehaviorModel(agent_dir)
|
||||
mdp = model.build_MDP()
|
||||
raw_events = aggregate_event_transitions(mdp) # this gets us transtition between events (blind to products or prices)
|
||||
# staet: {state: p} is raw_events we needc a matrix a pivot table
|
||||
events_pivot = pd.DataFrame(raw_events).fillna(0.0)
|
||||
# now adjust the transition matrix based on the condition to get a more informed transition matrix
|
||||
adjusted_transitions = adjust_behavior_to_condition(condition, events_pivot)
|
||||
|
||||
trajectory = [np.random.choice(adjusted_transitions.index)]
|
||||
while len(trajectory) < max_len or 'checkout' in trajectory[-1]:
|
||||
probs = adjusted_transitions.loc[trajectory[-1]].values
|
||||
sample = np.random.choice(adjusted_transitions.columns, p=probs/np.sum(probs) if np.sum(probs) > 0 else None)
|
||||
trajectory.append(sample)
|
||||
return trajectory
|
||||
|
||||
if __name__ == "__main__":
|
||||
t=sample_behavior(generate_demand(np.array([10,20,30])), human=True)
|
||||
print(t)
|
||||
t=sample_behavior(generate_demand(np.array([10,20,30])), human=False)
|
||||
print(t)
|
||||
40
engine/lib/demand.py
Normal file
40
engine/lib/demand.py
Normal file
@@ -0,0 +1,40 @@
|
||||
import numpy as np
|
||||
|
||||
def generate_demand(prices):
|
||||
# assumption 1: each product has an intrinsic valuation drawn from a normal distribution centered at 50
|
||||
product_valuations = np.random.normal(loc=50.0, scale=10.0, size=len(prices))
|
||||
# assumption 2: demand decreases as price increases, following a simple linear model
|
||||
demand = np.maximum(0, product_valuations - prices) # demand cannot be negative
|
||||
demand = demand / np.sum(demand) * 100 # normalize to total demand of 1000 units so demand output is within [0, 100]
|
||||
return demand
|
||||
|
||||
def estimate_demand(trajectories):
|
||||
demand_estimate = {}
|
||||
for traj in trajectories:
|
||||
for event in traj:
|
||||
if 'view_product' in event:
|
||||
product_id = int(event.split('_')[-1].replace('product', ''))
|
||||
demand_estimate[product_id] = demand_estimate.get(product_id, 0) + 1
|
||||
total_views = sum(demand_estimate.values())
|
||||
for product_id in demand_estimate:
|
||||
demand_estimate[product_id] = (demand_estimate[product_id] / total_views) * 100 # normalize to percentage
|
||||
return demand_estimate
|
||||
|
||||
# Example usage
|
||||
if __name__ == "__main__":
|
||||
np.random.seed(42)
|
||||
prices = np.array([20.0, 35.0, 50.0, 65.0])
|
||||
demand = generate_demand(prices)
|
||||
print("Generated Demand:", demand)
|
||||
from .behavior import sample_behavior
|
||||
N, alphat =200, 0.1
|
||||
trajectories = []
|
||||
for _ in range(int(N*(1 - alphat))):
|
||||
trajectories.append(sample_behavior(demand, human=True))
|
||||
for _ in range(int(N*alphat)):
|
||||
trajectories.append(sample_behavior(demand, human=False))
|
||||
demand_estimate = estimate_demand(trajectories)
|
||||
print("Estimated Demand from Behavior:", demand_estimate)
|
||||
delta = {k: demand_estimate.get(k, 0) - demand[i] for i, k in enumerate(range(len(prices)))}
|
||||
delta = np.mean([np.abs(v) for v in delta.values()])
|
||||
print("Demand Delta:", delta)
|
||||
0
engine/main.py
Normal file
0
engine/main.py
Normal file
@@ -226,6 +226,7 @@ if __name__ == "__main__":
|
||||
|
||||
agent_model = AgentBehaviorModel(agent_dir)
|
||||
agent_mdp = agent_model.build_MDP()
|
||||
print(agent_mdp)
|
||||
print(f"AGENT... Built MDP: {agent_mdp['num_states']} states, "
|
||||
f"{sum(len(t) for t in agent_mdp['transitions'].values())} transitions")
|
||||
if not agent_mdp['states']:
|
||||
@@ -234,6 +235,9 @@ if __name__ == "__main__":
|
||||
|
||||
human_evt = aggregate_event_transitions(human_mdp)
|
||||
agent_evt = aggregate_event_transitions(agent_mdp)
|
||||
print(agent_evt)
|
||||
|
||||
|
||||
common = set(human_evt.keys()) & set(agent_evt.keys())
|
||||
|
||||
if not common:
|
||||
|
||||
Reference in New Issue
Block a user