One of the most important uses for machine intelligence in e-commerce applications is **adaptive pricing **– that is, dynamically changing the price of a product in an online store based on characteristics of the user, the product, and the store. It’s a technique that’s used extensively by big on-line retailers like Amazon, but it’s less common for smaller companies.

Partly this is because of the risk of getting prices wrong. If you offer an online user a price that’s too high, you’re going to fail to convert that user. If you offer one that’s too low, you unnecessarily cut into your margin.

Another reason is the difficulty of implementation. Traditional procedural code can be OK for the most trivial adaptive pricing, but if you have more than a couple of factors that affect price, the code can become complex and unmaintainable. It’s also hard to test its accuracy, and unhandled edge cases can cause devastating or embarrassing outcomes (free cars, billion-dollar paper-clips).

Machine learning algorithms, on the other hand, require a sizable corpus of data to show successes and failures. Unless you’re willing to offer some cohort of customers an array of random prices for a product in order to determine its optimal price, machine learning for pricing can present some challenges.

One technique that’s worked well for companies with a two-sided market, like Uber, is to have a market-based bid-and-ask system. Uber, for example, slowly raises the end user’s “bid” for a ride until some driver chooses to respond. This can be really useful, but if your two-sided market isn’t real-time (Etsy providers can only knit so fast, after all), then bid-and-ask won’t be very useful.

In this post, I go over a simple technique for adaptive pricing using fuzzy logic.

### Why fuzzy logic?

Fuzzy logic is a machine intelligence technique based on multivariate truth values. A fuzzy logic *agent* works by mapping exact or “crisp” values into data structures representing membership in a so-called “fuzzy set”. So a user who’s been to your site 2 times might not be exactly a *new* user, but they’re *kind of* a new user and *kind of* an experienced user. Fuzzy logic assigns a value to their membership in each set — say, they’re 75% new, and 40% experienced.

Fuzzy logic then allows you to define rules to reason about these sets — something like, “IF the user is new, THEN the discount will be high.” If the user is only partially a member of the set, the output is only partially a member of its set. You can define multiple rules, and it’s OK if they’re potentially conflicting.

A fuzzy agent then converts these fuzzy output membership measurements to a “crisp” single value which can be used for further processing in a procedural language.

If you have base fuzzy logic software, or you use an API like fuzzy.io, the steps for developing a new fuzzy logic agent are pretty simple:

- Define your output variables and their fuzzy sets.
- Define your input variables and their fuzzy sets.
- Define the rules that link your inputs to your outputs. Usually, this is a one-to-one match of one input fuzzy set to one output fuzzy set.

Fuzzy logic is a good fit for adaptive pricing for a number of reasons:

- Like procedural methods, it uses explicit rule definition by the programmer to direct its calculations.
- It doesn’t require much data to get started. In fact, it depends on your own experience with your customers.
- It has smoothly varying output as you vary an input. Procedural code tends to have discontinuities as you hit different thresholds (“if (userAge >= 2) { … }”).
- It handles contradictory inputs well. You can have one factor that suggests a high price, and another that suggests a low price, and a fuzzy logic agent will synthesize the two and come out with a reasonable middle ground.
- It handles new inputs well. You can get started on an adaptive pricing algorithm with only a few inputs, and then add new inputs as they come up.
- It handles missing data well. If you don’t know the number of times the user has been on the site for some reason, you can do a calculation with the other factors you
*do*know, and you’ll get a reasonable output. - It’s relatively easy to audit. Figuring out
*why*a discount was higher or lower than you intuitively expected can be done just by looking at the fuzzified versions of the inputs and outputs.

There are some restrictions to using fuzzy logic, too. The algorithm requires numerical inputs, so if you have input data like “user is in North Dakota”, you need to reframe it to something like “User is in a state with 0.1% market penetration”. Usually it’s relatively easy to do.

### Defining output variables

For adaptive pricing, there are a couple of different ways to define an output. One is to define the price that will be offered to the customer. That’s reasonable, but if you have multiple products available in your store, with widely varying prices, it will mean you need to have a different fuzzy agent for each product. That can be hard to develop and maintain.

Instead, I recommend modelling your adaptive pricing as an adaptive *discount.* Here, your output is a discount in percent values. Full price would be a discount of 0%, and a free product would be a discount of 100%. The advantage here is that you can use the same fuzzy agent for all your products. You also avoid having out-of-bounds pricing that shocks customers (compare Uber’s problems with unexpectedly high “surge pricing”). You can also set a maximum value of the discount to match your profit margin (assuming your margin is about the same on all your products!). You may be willing to sell a product below margin to activate a new customer, but if not, you can use the discount’s maximum value to prevent losing money on your adaptive pricing algorithm.

In this diagram, I’ve defined a discount output variable and its five corresponding fuzzy sets: “veryLow”, “low”, “moderate”, “high”, and “veryHigh”. This is a pretty common pattern in fuzzy engineering: input and output variables usually come with 3, 5, 7, or occasionally 9 outputs.

The diagram shows each fuzzy set, with the variable value in the x axis and the percentage of membership in the y axis. In this example, a discount of 20% is “moderate”, and a discount of 5% has a 50% membership in the “veryLow” set and a 50% membership in the “low” fuzzy set.

I chose 45% as the maximum discount, and then mapped out the other fuzzy sets from there. All of these numbers are based on more or less intuitive reasoning on my part. In a real-world situation, you can do customer surveys or talk to people in your company to get their ideas of what a “moderate” discount is. There are also mechanisms for varying these parameters based on experience (see below).

One thing to note is that at each output value, the membership in all the fuzzy sets adds up to about 100%. This isn’t strictly required, but it tends to give smoother-varying outputs.

It’s worth noting that this model is going to give a non-zero discount for almost any input values. You may want to set your base prices slightly higher to accommodate this.

### Choosing inputs

There are a lot of different input variables you can use for an adaptive pricing algorithm. I’ve chosen a few here to give some ideas.

One important input is product popularity. How well is the current product selling? If it’s not selling very well, it makes sense to offer steeper discounts. If it’s selling very well, little or no discount makes sense. To model popularity, I’ve used the number of sales per week of the product. (I use sales per week to smooth over discrepancies between weekend and weekday Web traffic.) The above fuzzy sets show typical values for a medium-sized e-commerce site; it’s relatively easy to expand or contract them. As your e-commerce site grows, varying these input parameters makes a lot of sense.

It’s probably also worth noting that calculating the current number of sales per week of a product at runtime is too compute-intensive. This kind of input data should really be pre-calculated, probably on a weekly basis.

Another thing to note is that the number of fuzzy sets in this input is 5 — exactly the same number of fuzzy sets in the *discount* output variable. This is a good rule-of-thumb, since it makes mapping input variables to output variables in your rules much easier.

A similar input would be product category popularity. There may be value in incenting users to purchase products in underperforming categories, even if the product itself is doing well.

Again, popularity is measured in sales per week. The shape of the category popularity fuzzy sets is roughly the same as the product popularity, but the numbers are somewhat higher — representing a typical ecommerce site with a few products per category, with a few high performers and mostly average performers.

Another input would be store-wide performance. How have numbers been lately? If they’ve been low, it might make sense to juice the numbers with some bigger discounts.

Here, I’ve chosen another 5 fuzzy sets, denominated by annual revenue in US dollars. Obviously, what’s “ok” for a mid-sized ecommerce site is “terrible” for Apple or Amazon, so these numbers need to be tuned for the company running the site. Especially in periods of high growth, what’s “good” in February may be “bad” by April.

For other site-wide inputs, adapting the price by time of day also makes sense. Depending on their market, most ecommerce sites drop off sales dramatically at nights and on weekends. Giving users an incentive here can boost those numbers.

Note that providing the input on this item will require a) figuring out what hour of the week (like 3-4PM on Tuesday) it is and b) looking up the sales for this hour of the week in a database. If sales per hour varies more than 1-2 orders of magnitude, it may make sense to use a logarithmic scale here.

Finally, what about varying the discount based on aspects of the user? One important user metric is *recency — *how long the user has been signed up. You may want to get new users activated, so providing a discount makes sense.

Here, we’re measuring user recency in terms of hours since first acquisition (usually either arriving on a landing page or sign up). The concentration is on very recent users (less than 5 days). Anything larger will get a veryLongTerm membership (and thus, a veryLow discount).

User sales are linked to, but not proportional to, user recency. Long-time users can fail to activate for a long time. In this case, I’ve broken down the user sales into “unactivated”, “activated”, “frequent”, “veryFrequent” and “whale”. Note that number of sales per user is an integer, so a lot of these values are impossible. But it’s still worthwhile to map the input onto a smoothly-continuous set.

There are a number of other user characteristics you can key prices to. One that’s especially helpful is market penetration. This is a measure of your company’s penetration of a given geographical market, measured in numbers per million. It requires, again, two important lookups: first, identifying the user’s geographical location, either based on information they provided you, or on their IP address, or on data from the browser. That will give a latitude/longitude pair, which in turn has to be mapped into a “market” as you define it — a city, county, US state or Canadian province, or country. You’ll then need some information on your previous sales to that market.

Here, I’ve only defined three fuzzy sets — “low”, “medium”, and “high”. Most of the heavy lifting on market penetration happens well before the fuzzy agent gets the input.

### Rules

The last step in fuzzy agent design is defining rules to link inputs to outputs. Because we’ve mostly used inputs with the same number of fuzzy sets as the output, it’s relatively easy to define our rules.

For some inputs, like productPopularity, we map the output sets inversely to the input sets. So, if productPopularity is low, the discount is high, and if productPopularity is veryHigh, the discount is veryLow.

For others, like userSales, there’s more of a bow shape. Users who have not activated often get high discounts, and top customers also get high discounts. The ones in the middle get low or moderate discounts.

### Next steps

If you’re interested in trying out this example, it’s possible to sign up at fuzzy.io and set up a new fuzzy agent with a Web API.

The next steps, after designing a fuzzy agent, are integrating it into the store. This can happen either through a plugin, or with custom code. Fuzzy.io has a number of Open Source libraries for connecting to the service, for example.

Another important step is varying the fuzzy set boundaries and inputs based on performance. This process, called *fuzzy learning*, requires a feedback mechanism, showing the performance of each discount value. Performance, here, would be profit on the sale, if any. This feedback can be used to tune the inputs.