hpi-epic / pricewars-consumer

Consumer Component of the Price Wars Platform
MIT License
0 stars 4 forks source link

Consumer

This repository contains the Consumer-component of the Price Wars simulation. The consumer represents the costumers arriving at the marketplace and buying products. How often and which products they buy is decided based on custom consumer-behaviors that can be configured and changed.

The consumer is realized using a Ruby-app implementing the MVC pattern. Please make sure tests are running before committing.

The meta repository containing general information can be found here

Application Overview

Repo
UI
Consumer
Producer
Marketplace
Merchant
Kafka RESTful API

Requirements

The consumer is written in Rails. Ensure to have the following components installed and set up on your computer:

Setup

After cloning the repo, install the necessary dependencies with bundle exec bundle install.

Afterwards you may start the webserver with rails s -b 0.0.0.0 where the ENV variable PRICEWARS_MARKETPLACE_URL should point to the marketplace server.

If all worked out, see the results at http://localhost:3000

Configuration

The marketplace url is configured in the environment variable PRICEWARS_MARKETPLACE_URL. If it is not set, a default url http://marketplace:8080 is used. The environment variable can be set with:

export PRICEWARS_MARKETPLACE_URL='http://your_hostname:8080'

Concept

The consumer is defined via behaviors which are implemented in lib/buyingbehavior.rb. All available behaviors are included and exposed with their default settings and description in app/controllers/behavior_controller.rb .

Consumer Behaviors

The consumer chooses a random buying behavior for each buying decision. The buying behaviors have weights that determine how frequently each behavior is chosen.

The implemented behaviors are:

buying the first item out of the marketplace offer list

buying a random item out of the marketplace offer list

buying the cheapest item out of the marketplace offer list

buying the n-cheapest item out of the marketplace offer list

buying the second cheapest item out of the marketplace offer list

buying the third cheapest item out of the marketplace offer list

buying the cheapest item out of the marketplace offer list filtered by prime

buying the most expensive item out of the marketplace offer list

buying the cheapest item with the best possible quality out of the marketplace offer list filtered by prime

buying the cheapest item with the best possible quality out of the marketplace offer list

buying items based on the provided logit coefficients from the marketplace offer list

Buys with highest probability the cheapest product, but also has a chance to buy more expensive products. The probabilities are calculated with a modified market power formula.

Scores each offer based on price and quality. A lower score is better. The consumer buys from the best offer if its score is below or equal to the consumer's willingness to buy. The importance of price and quality and the willingness varies for each consumer (visit).

Logistic regression behavior in detail

The logit behavior implements a logistic regression with feature scaling and calculates for each offer the buying probability based on the feature coefficients provided in the behavior settings. Based on this buying probability for each offer, the consumer will actually choose an offer to buy. In this way, potential consumer behavior can be learned on real world data and imitated in the simulation solution.

Logistic regression is a regression model where the dependent variable -- in our case the selling of an offer -- is categorical. This categorization outcome must be discrete and should be dichotomous in nature simply expressed by a boolean whether a purchase happened or not. To determine this, this behavior consumes features and their coefficients can be altered within runtime and will then be applied to the next calculation iteration taking place. The describing hashmap of features and their coefficients contains only available features which are already implemented otherwise they will be ignored.

The default settings for the logit behavior holds the following settings:

{
   "coefficients":{
      "intercept":-6.6177961,
      "price_rank":0.2083944,
      "amount_of_all_competitors":0.253481,
      "average_price_on_market":-0.0079326,
      "quality_rank":-0.1835972
   }
}

which were extracted from a real world use case provided by a big book retail company. For deeper insights in the concepts of logistic regression, the reader is kindly referred to DW Hosmer Jr et al. work.

Adding new features for logit behaviors

For adding a new feature for the logit behavior, one simply needs to extend the logic in lib\features.rb. In particular, one may implement a new method and include it in the switch case starting in L9.

Adding new behaviors

For adding a new buying behavior, one simply needs to add the buying logic as method in lib/buyingbehavior.rb starting with the prefix buy_ returning the item (only one!), which is supposed to be bought.

If wished, validate_max_price() can be used to validate whether the selected item comply the settings (e.g. max price).

If the new behavior has individual settings, they can be accessed via @behavior_settings.

A buying behavior chooses at most one offer from all available offers.

Keep in mind to add the new behavior with its description, default settings and method name in the app/controller/behavior_controller.rb in the way that it will be included and listed in the default setting return value.

Sample Configuration

Like described in the API documentation, a sample setting json for the consumer looks like the following:

HTTP GET http://localhost:3000/setting/

{
   "consumer_per_minute":100.0,
   "amount_of_consumers":1,
   "probability_of_buy":100,
   "min_buying_amount":1,
   "max_buying_amount":1,
   "min_wait":0.1,
   "max_wait":2,
   "behaviors":[
      {
         "name":"first",
         "description":"I am buying the first possible item",
         "settings":{

         },
         "settings_description":"Behavior settings not necessary",
         "amount":9
      },
      {
         "name":"random",
         "description":"I am buying random items",
         "settings":{

         },
         "settings_description":"Behavior settings not necessary",
         "amount":9
      },
      {
         "name":"cheap",
         "description":"I am buying the cheapest item",
         "settings":{

         },
         "settings_description":"Behavior settings not necessary",
         "amount":9
      },
      {
         "name":"expensive",
         "description":"I am buying the most expensive item",
         "settings":{

         },
         "settings_description":"Behavior settings not necessary",
         "amount":9
      },
      {
         "name":"cheap_and_prime",
         "description":"I am buying the cheapest item which supports prime shipping",
         "settings":{

         },
         "settings_description":"Behavior settings not necessary",
         "amount":9
      },
      {
         "name":"cheapest_best_quality",
         "description":"I am buying the cheapest best quality available.",
         "settings":{

         },
         "settings_description":"Behavior settings not necessary",
         "amount":9
      },
      {
         "name":"cheapest_best_quality_with_prime",
         "description":"I am buying the cheapest best quality available which supports prime.",
         "settings":{

         },
         "settings_description":"Behavior settings not necessary",
         "amount":9
      },
      {
         "name":"second_cheap",
         "description":"I am buying the second cheapest item",
         "settings":{

         },
         "settings_description":"Behavior settings not necessary",
         "amount":9
      },
      {
         "name":"third_cheap",
         "description":"I am buying the third cheapest item",
         "settings":{

         },
         "settings_description":"Behavior settings not necessary",
         "amount":9
      },
      {
         "name":"sigmoid_distribution_price",
         "description":"I am with sigmoid distribution on the price regarding the producer prices",
         "settings":{

         },
         "settings_description":"Behavior settings not necessary",
         "amount":9
      },
      {
         "name":"logit_coefficients",
         "description":"I am with logit coefficients",
         "settings":{
            "coefficients":{
               "intercept":-6.6177961,
               "price_rank":0.2083944,
               "amount_of_all_competitors":0.253481,
               "average_price_on_market":-0.0079326,
               "quality_rank":-0.1835972
            }
         },
         "settings_description":"Key Value map for Feature and their coeffient",
         "amount":9
      }
   ],
   "timeout_if_no_offers_available":2,
   "timeout_if_too_many_requests":30,
   "max_buying_price":80,
   "debug":true,
   "producer_url":"http://vm-mpws2016hp1-03.eaalab.hpi.uni-potsdam.de",
   "product_popularity":{
      "1":25.0,
      "2":25.0,
      "3":25.0,
      "4":25.0
   },
   "marketplace_url":"http://vm-mpws2016hp1-04.eaalab.hpi.uni-potsdam.de:8080/marketplace"
}

Source Code

Detailed information regarding method and function usage and behavior can be found within the public/doc/ directory of this repository.