Machine Learning Over in Game Ec
Machine Learning Over in Game Ec
Paul Benn
Copyright notice
This report is made available exclusively to Gerry Be-ilan of Simon Fraser University
under a Creative Commons Attribution, Non-Commercial 4.0 International licence (CC
BY-NC-ND 4.0). In summary, the reader:
• MAY distribute this report in any way they wish as long as credit is given to the
original author and this licence is preserved.
i
Success consists of going from failure to failure without loss of enthusiasm.
- Winston Churchill
ii
Abstract
Most role-playing videogames have a market where players can buy and sell upgrades or
equipment, sometimes to each other. These markets can be a simple shop provided by
the game developer or a rich ecosystem with all the nooks and crannies one would expect
of the real world. This report introduces the notion of monetary gain from videogame
economies as a real and profitable possibility, and outlines how similar, user-driven
economies such as the housing market can be analysed in much the same way. The
focus is on a specific game, Path of Exile, chosen for its constantly changing environment
and immense complexity, with more than 172 quadrillion possible combinations for each
data point, and the additional challenge presented by the heavily nested structure of the
data. Machine learning and several dimensionality reduction and feature engineering
techniques are applied to thousands of market snapshots to build a system capable of
accurately predicting the price range of more than 70% of all of these possible combina-
tions, beating every similar system in the public domain by an order of magnitude. The
information gained by running this prediction algorithm on a current snapshot of the
market can easily be used to spot hundreds of under-priced items, each with the potential
to be bought and sold for a higher price. This work serves merely as a proof of concept of
what is possible in this vast, and as yet unexplored, territory.
iii
Acknowledgements
This project has been a hard but exciting journey through uncharted territory, and it
would not have been possible without all of the below.
Firstly, thank you, Grinding Gear Games, developers of Path of Exile and its wonderfully
complex environment, without which my curiosity for this topic would not have been
piqued.
Thank you to the helpful community over at the official message boards for Path
of Exile tool developers, which pointed out many potholes in my original designs. I’d
especially like to draw attention to that one user who stated this was a problem too
absurdly complex and risky to tackle as a final project, for setting me on this path with
ever more determination.
The largest debt of gratitude is owed to all those who helped validate my outputs and
provided that much-needed boost of credibility, taking time out of their regular schedules
even with thousands of followers to keep happy just to help me out. Without you, it would
have been much harder to prove the functionality of my software.
Also, thank you to my personal tutor, Dr. Gkoutzis, and to the members of the Machine
Learning Group at Imperial College. Some of you provided invaluable pointers and
assistance, and you are most of the reason the further work sections are so full.
I must not forget to mention my amazing family, girlfriend and close friends, who have
patiently listened to me complain for months and supported me all the way through.
Finally, a massive thank you to both my supervisors, William Knottenbelt from the
Department of Computing and David Birch from the Data Science Institute. I never
thought a project as unusual as this would be accepted into the research arena, and you
both proved me wrong. Thank you Will for the excellent advice on focusing my project on
what really mattered, and thank you David for the great tips on honing this very report
and my presentation.
iv
Contents
Abstract iii
Acknowledgements iv
1 Introduction 1
1.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Contributions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3 Pipeline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2 Background 6
2.1 In-game Economies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.2 Path of Exile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.2.1 Leagues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2.2 Currency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2.3 Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.2.4 Modifiers (affixes) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.2.5 The problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.3 Previous attempts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.3.1 poe.trade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.3.2 ExileTools indexer (no longer available) . . . . . . . . . . . . . . . . . 13
2.3.3 Other market indexers . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.3.4 poe.ninja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.3.5 Stashi (no longer available) . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.3.6 PoETradeChat (no longer available) . . . . . . . . . . . . . . . . . . . . 14
2.3.7 PoEPrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.4 Data Mining . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.5 Machine Learning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.5.1 Preprocessing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.5.2 Regression algorithms and classifiers . . . . . . . . . . . . . . . . . . . 19
2.6 JSON processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.7 Databases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.7.1 SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.7.2 MongoDB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.7.3 Apache Cassandra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.7.4 Column databases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.7.5 ElasticSearch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3 Preprocessing 30
3.1 API Endpoint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.1.1 JSON format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.1.2 Explicit modifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.2 JSON Parsing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.2.1 Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.2.2 Raw JSON to ElasticSearch JSON . . . . . . . . . . . . . . . . . . . . . 40
3.3 ElasticSearch JSON to CSV . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3.3.1 Primitives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3.3.2 Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
3.3.3 Explicit modifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
3.3.4 Clustering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
4 Learning 47
4.1 WEKA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
4.2 CSV to ARFF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
4.3 Training the classifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
4.4 Result applicability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
5 Validation 53
5.1 Community figure survey . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
5.2 Clipboard input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
6 Further Work 59
7 Conclusions 63
References 64
Introduction
1.1 Overview
It becomes clearer every day that gaming is here to stay. A multi-billion-dollar industry
with over 2000 game development companies registered in the UK alone [98], it’s no
wonder that almost 67% of households own a device used for gaming [5]. Even though
this brave new world offers endless possibilities, this report is concerned with one broad
subset of all videogame titles: those with a monetary element that plays a leading role in
the experience.
The real market, the one concerned with trading stocks and shares, is a harsh and
unforgiving environment that requires passion and minutious planning to succeed [53].
While the lucky 6% of professional traders that ‘made it’ occupy themselves with finding
the few profitable exchanges in a vast global market, others have turned to the emerging
world of gaming markets and slowly, manually, traded their way to a level of wealth only
envisaged in dreams by the casual player [48], making use of primarily or even exclusively
virtual goods.
The trading concept is far from the gaming spotlight for several reasons, chief among
them that much of humanity would much prefer to relax and lose themselves in a fantasy
world, than to scrutinize it and delve into an economy that may sound alien and unrelatable
at first. Furthermore, even when economy-focused videogames were just starting out the
total value of virtual goods was already well above what the average skeptic would expect
[87], which almost immediately led some game development companies to shut down any
efforts to convert their particular brand of intangible currency to cold hard cash. In fact,
it’s not uncommon to see revenue authorities taking this a step further and laying down or
planning tax legislation on entirely virtual profits [99]. All this being said, the properties
and stunning variety of in-game economies described in section 2.1 showcase just how
many valuable insights can be gained from studying them - often insights applicable to a
wide range of other areas.
This work outlines a series of procedures applicable to virtual markets of varying
complexity which can be used to predict the price of most items even with no access
to a solid transaction record or an objective price reference. The especially confusing,
heavily obscured and deeply nested data provided by the virtual economy of the game
Path of Exile [36] has been chosen as a base data set, as success ensures learning and
1
1.2. CONTRIBUTIONS CHAPTER 1. INTRODUCTION
regression over economies of lesser or equal convolution is possible. The game itself is
briefly documented in section 2.2, and the difficulty and hence interest of the pricing
problem is explained in section 3.1.2.
Success is, in fact, the issue at hand - indeed the techniques described in the body of
the work form the bases of the first known fruitful general pricing software for the game
Path of Exile, a task considered by many to be so absurdly complex that it borders on
the impossible. Most of the work is applicable to a wide range of virtual economies and,
combined with years of existing knowledge in age-old disciplines such as stock market
and portfolio trading, could make virtual economy analysis become a viable, if unofficial,
career choice.
1.2 Contributions
In-game economies are invariably written about in academia as targets for taxation
and not as a topic ripe for analysis in and of themselves. However, as videogames
inexorably move to conquer other forms of entertainment such as television, this field
will do nothing but grow as more markets become available for study and exploitation by
the keen eye. Focusing on its value as an area of research, it’s not hard to see abundant
parallels between the virtual and the real: the housing market, second-hand sale apps
and online retail all operate in much the same way as game markets. In almost all cases,
environments like these are bursting with items of all shapes and sizes, lack a publicly
accessible transaction history and an objective price reference, operate across dozens of
currencies and evolve extremely fast.
Coming up with a general algorithmic pricing solution for any economy is an important
step towards abolishing market manipulation and ill-intended traders, or making their
effect negligible. It follows that dangerously unhealthy practices such as ‘gold farming’
[42] would also see a reduction. Cleaning data is one of the largest hurdles in any machine
learning effort, and IGEs see some of the highest corruption, staleness or intentional
mispricing rates of any type of market. The underlying issue runs deep, with most virtual
markets being unregulated and rife with misinformation, so the focus of the work is on
dealing with this problem in as generic a way as possible.
The data interchange format used by Path of Exile’s application programming interface
is JavaScript Object Notation [54] or JSON - one of the two most popular formats in the
world together with XML (eXtensible Markup Language). This fortunately translates
to a respectable amount of existing work relating to machine learning over JSON, and
also guarantees any techniques developed to analyse JSON-formatted trade data are
applicable to a vast number of scenarios.
However, machine learning algorithms such as classifiers and regression techniques
almost always use ‘flattened’ data, that is, data reduced to a one-dimensional array of
numerical or categorical variables, often in exactly the same format. When trying to learn
over complex, nested data structures which allow for six or seven types1 such as JSON,
loss of information is almost inevitable, which in time generates a sub-par training set
1
Apart from objects, arrays, strings, booleans and the null value and depending on the definition, one
may consider a single ‘number’ type or two ‘integer’ and ‘double’ types.
2
CHAPTER 1. INTRODUCTION 1.3. PIPELINE
Figure 1.1: Survey question 1: ‘Do you find Figure 1.2: Survey question 2: ‘If an accu-
pricing items time-consuming or hard most rate pricer existed for Path of Exile, would
of the time?’ you be likely to use it?’
Note ‘rare items’ is a context-specific term which will become clearer further on.
An apparently narrow contribution like this might not sound very exciting on its own,
but as mentioned in section 1.1 and expanded upon in section 2.2 and 4.4, this work
serves as proof that almost any community-based dataset, no matter how complex, from
the property market to the Amazon Marketplace can be broken apart in machine learning
contexts. Useful, profitable trades can be identified in an instant across the whole market,
even if they exchange items which have never been seen before.
1.3 Pipeline
3
1.3. PIPELINE CHAPTER 1. INTRODUCTION
is reached. The numbered process below summarises the path data takes through the
system before eventually reaching validation and being worthy of inclusion in the training
set. It is worth noting all the concepts in this paragraph are explained in layman’s terms
in the body of this report.
1. A block of changes to items currently on sale by the game’s currently online players
is received in JSON format from the game’s API endpoint [39] once every few
seconds and temporarily stored in memory. Items arrive heavily obscured and
with an unreliable unique identifier, leading to additional steps. The API and
polling methods used are detailed in section 3.1, and the raw item format is further
explained in appendix A, as it is one of the main reasons the data is so intractable.
2. Items are parsed and strictly filtered to ‘weed out’ impossibly high or low prices,
blacklisted sellers, irrelevant types and missing or malformed values. The full list of
filters, together with the reason they were included and how they were designed,
can be found in section 3.2.1. It is essential that the number of mispriced items
which reach the training data be absolutely minimal.
3. The last few preprocessing steps ensure the remaining items are flattened until a
sole level of nesting (an array of primitives2 , specifically) remains on exactly one of
the item’s many dimensions. This particular array is proven by principal component
analysis to have, by a wide margin, the largest impact on value.
4. Now ready, items are packaged and indexed into an ElasticSearch [23] document
store. There are many positives to using NoSQL when working with JSON, and
the decision process that led to abandoning SQL can be found in section 2.7. Also,
distributed ElasticSearch and its underlying Apache Lucene engine provide top-
notch query and search performance, necessary to keep up with the astonishingly
high market update rate of up to several tens of thousands of items per second.
5. Items are retrieved and clustered into one 52 groups (see section 3.3 for more
information). This operation is performed separately, in parallel and at an arbitrary
time after database storage so as to further speed up initial data parsing, as an
entire chunk must be fully indexed in a very short time before the next one arrives.
6. The remaining level of nesting (the principal component responsible for the highest
variance) is eliminated using a combination of feature hashing and n-hot encoding,
generating over 500 extra dimensions for each item. This is still many orders of
magnitude better than those necessary if operating on the raw data, and a more
than manageable size when compared to most learning problems.
8. 52 very large CSV files are updated with the new validated records, thus splitting
the main pricing problem into many sub-problems. A very fast streaming parser
2
JSON primitives are not equivalent to the usual programming language primitive - note, for example,
that a string is an object in Java but a primitive in JSON.
4
CHAPTER 1. INTRODUCTION 1.3. PIPELINE
then translates the new CSV on the fly to the ARFF format [20], understood by the
WEKA [21] machine learning library.
9. This means classifiers have 52 training sets in total, and within the WEKA ecosystem
(of questionable efficiency) this is especially useful, as even very large datasets are
entirely loaded into main memory before training can proceed. Unfortunately the
use of updateable, big-data ready online learning classifiers is quite limited in WEKA,
so possible solutions to this bottleneck are discussed in section 4.1.
10. Seven different regressive classifiers can be trained and stored for every single
ARFF file whenever the user desires, resulting in over 300 serialised, ready-to-use
models. Only some of these are in use for the final prediction system - details in
section 4.3.
11. When a new item is passed as an input to the system, a neural network or linear
regression model (depending on availability) is asked to predict a price and a
confidence level, which is then printed to a basic front-end.
5
Chapter 2
Background
From the barter systems of old to ever-changing stock markets, economy has been a
basic and lasting element of society for a very long time. However, never in the history of
humanity has this much data been collected, and the job of the stock trader is not only
being made easier but quickly becoming obsolete [66]. Now is when machine learning
shines: with training sets becoming millions of items larger by the day, predictive software
is set to be on the rise for the foreseeable future.
The introduction of virtual economies is an exciting time for aspiring traders. Now,
even with a small investment, being the first to figure out the intricacies of a market
means massive returns. Alas, it is hard to find people who have taken an interest in the
topic; videogames’ original purpose was entertainment, and the public has not forgotten
this basic fact. Thankfully, much can be gained from the analysis of markets as complex as
the one described here and, as described in the introduction, part of the intent behind this
work was to inspire others to do the same. This is a double-edged sword: when bringing
new content to the table one must consider an almost complete lack of background
research as the norm. Of course, this chapter still contains information and sources for
many of the techniques used and provides context for all of them.
A brief overview of what in-game economies actually look like and some explanatory
examples is presented below in section 2.1. As the focus of this work, the one present in
Path of Exile has its own section under the heading 2.2. The bulk of this chapter, however,
rests with all previous attempts at pricers for the Path of Exile economy and why they
have all either failed or have achieved only mediocre results (section 2.3), as well as a
detailed description of regression techniques for price prediction in similar contexts (2.5).
Virtual economies are those defined as dealing in intangible currency or services within a
virtual world. In-game economies are a relatively new concept, yet they are already one
of the most important subsets of virtual economies, and definitely the fastest-growing.
Initially, they represented the next step in the evolution of gaming: a novel way to interact
with other players, yet only a pale reflection of money management in the real world.
While the first ones were small and underpopulated, it soon became clear that entire
6
CHAPTER 2. BACKGROUND 2.1. IN-GAME ECONOMIES
• Firstly, let us take a look at an economy similar to that of League of Legends. While
the videogame has one of the most impressive followings in the world, its only
virtual economy element is a store where players can buy individual upgrades for
themselves. Players cannot sell their possessions or exchange currency, making
the market completely immutable. Prices are fixed except for the occasional sale.
All of the above makes for close to null player economic interaction and thus no
interesting insights (or monetary value, for that matter) to be gained.
• The next step up is an economy where players can buy goods or services off each
other or directly from an online shop. Such is the case with the Steam platform,
where some prices are set by game developers and others are governed by offer
and demand laws, which apply in much the same way as in real life. In markets like
this, item repetition is commonplace and there will often be thousands or millions of
previous identical examples to provide some kind of historical record if one wants
to price a new item. As dictated by regular market laws, uncommon items will
be worth more than common items, with the extremely rare being worth tens of
thousands of dollars [52]. It is almost trivial to write simple code capable of spotting
deals in this environment, and studying it further is unlikely to yield new techniques.
In addition, from a purely practical angle, the age-old trader trouble appears soon
enough: profits are inversely proportional to the number of people trying to increase
their wealth [69].
• The third example we will use deals with immensely more complex economies such
as the one analysed in this report. Several currencies to be considered at any
one time, mutable goods with billions of possible combinations, heavily fluctuating
trends and the possibility of malicious intent (scams, price-reducing botnets) make
these markets a valuable target. As an intended side effect of complexity, player
interaction is at its best: a constant flow of currency and items ensures a healthy,
fluid economy where prices are determined based on subjective, not objective, value.
Unfortunately, an obvious consequence that follows from that last point is that
simple algorithmic analysis is ineffective and sometimes impossible, and any tool
without a machine learning component is unlikely to succeed in pricing new items.
Note this is by no means an exhaustive list of IGE categories, just a set of illustrative
examples - in fact the reality is quite the opposite, with a wide spectrum of economy types
popular across the board.
All of this begs the question of currency and item generation. The basic concept of
goods is not so different to the real world. In much the same way as the reader might
have a house with objects in it, players have an inventory, and this inventory has items
7
2.2. PATH OF EXILE CHAPTER 2. BACKGROUND
in it. Items can be bound to a certain value or said value can fluctuate wildly - they can
even be worthless to other players and only there to enable the progression of one’s game
experience. While in the real world one would generate currency to buy a cup of coffee
by providing a service such as work, one cannot generate the cup of coffee itself from
thin air in the same way. Since, however profitable it may be, we are talking about an
entirely fictional economy, within a virtual world the cup of coffee and indeed every item
on sale is generated from thin air. One may come across items as rewards for completing
milestones within the game or by earning loot by slaying players or monsters, for example.
The latter is especially common in action role-playing games such as Path of Exile.
In fact, IGEs have a few more differences with respect to real world economies that
should not be ignored during their analysis. Trades do not have to occur on a nanosecond
level as, if the process is not automated, sellers will often reject offers and wait for
someone willing to pay a little more. Even if speed is desirable, it is often the case that
information and intelligence are much more valuable. In most games, security is also a
problem: scams and other criminal practices such as artificial price inflation using botnets
are sometimes even explicitly allowed by the game developers. Part of the complexity of
writing pricing software stems from the large proportion of the market which is pure noise,
useless information to be filtered out. If this filtering is not carried out in a satisfactory
manner, any potential profitable bargains will be lost in the stream of data or, conversely,
scams will be mistaken for opportunities.
Before we go further, let us carefully detail what economy this work deals with and the
long list of troublesome features making successful trading with no previous knowledge
nigh impossible.
1
Internationally widespread demographic label used to denote people from New Zealand.
2
The microtransaction business model is often used as a revenue stream in free-to-play games and is
based on offering cosmetic or, in rare cases, gameplay and usability improvements for small amounts of
real money.
8
CHAPTER 2. BACKGROUND 2.2. PATH OF EXILE
Although PvP (Player versus Player) is possible within the game, the PvE (Player
versus Environment) aspect of Path of Exile is its main attraction. Players compete to
build the best characters possible in a procedurally generated set of environments, using
currency obtained from looting enemies and trading with other players to improve their
equipment over time. A character can often be worked on for years before reaching its
peak, and even then absurd levels of virtual currency can be invested before achieving
perfection. A character has a total of ten slots such as helmet or belt, and each can
be filled with one, interchangeable item, making for an even larger number of possible
combinations on one character.
The variety of the possible loot is so broad that without trading, players would never
be able to improve characters on their own beyond a certain point, as the desired item
might be so elusive that years of continuous play would yield nothing close. It is easy to
see that without the introduction of a robust economic ecosystem the game would entirely
lose its charm, and the game was indeed launched with the early form of the tortuous
market we see today. This system is further described below.
2.2.1 Leagues
Firstly, the game’s economies are naturally split along the game’s content: when players
enter the virtual world, they choose one of four main ‘leagues’ or environments of varying
difficulty and features, each of these with its own market. Players have limited, sometimes
one-way movement between all four of these leagues, and as they move so do their items,
already making item tracking a costly problem. The scope of this work deals entirely with
one of these leagues and ignores the interactions between them, and indeed this is one of
many necessary simplifications to come up with a working pricer in the time allotted to
this project. However, the software has been built in such a way that only one string in
the entire code-base would need to be changed to switch the analysis to the new league
or include it in the picture by running two pipelines in parallel.
2.2.2 Currency
In Path of Exile, currencies are not just currencies. To continue the example in section
2.1, to buy a cup of coffee in the real world one would need a token, generally agreed
upon by society to have intrinsic value, such as a dollar, a euro or a pound. If one thinks
about these tokens objectively with no knowledge of human society they are all, at the
most basic level, stamped chunks of common metal and cannot be used for anything
whatsoever except if value is manually associated to them. While in some IGEs this model
is followed to the letter and currencies are virtual tokens, Path of Exile is much more
interesting: currencies can be consumed entirely to produce a change in one of your
items (see appendix B). The cup of coffee could change to a cup of tea, or it could change
to the colour red, or it could grow an extra handle, or all of the above, but the concept
itself would still be the same (a cup). The cup is what is known as an item ‘base’ in Path
of Exile and many other trading-based games. The term will be referenced many times in
these pages.
9
2.2. PATH OF EXILE CHAPTER 2. BACKGROUND
2.2.3 Items
The really interesting aspect of PoE’s economy is the ungainly variety of items possible.
In fact, when taking the subset of the market used in this work as an example, over 172
quadrillion (order of magnitude 1017 ) items are possible. How to arrive at this number is
explained further in the body of this report, section 3.1.2.
There are over 800 different possible base item types, often referred to as ‘bases’. An
item’s base serves as merely one of the dozens of possible top-level classifications, but it
turns out clustering algorithms align almost exactly with this split in particular, as we
shall see in section 3.3.4.
Items within the game are optionally assigned a value by the player. There is no
objective reference to price items, contrary to the second type of economy described
above, as the chances of encountering the same combination of properties on an item
twice is negligible and thus historical records are nonexistent. Not all items owned by a
certain player will be on sale, some of the ones that are will be completely mispriced and
others will not have a price at all, instead waiting for someone interested to offer. Items
have dozens of properties that determine their subjective value to a player, described
briefly in appendix A, but the one with the most impact on value is a list of properties such
as ‘cold resistance’ or ‘increased physical damage’ that impact the item’s characteristics
to benefit the player using them. The full list of dimensions present on each of these items
is covered together with the API endpoint in section 3.1.
The list of properties or ‘modifiers’ referenced above can be shown by PCA to be the
most important feature on any item. Modifiers can add offensive stats, defensive stats
and everything in between to any item, including purely cosmetic properties that change
nothing about the item except its in-game appearance. The synergy between mods on
an item in relation to the item’s base is often what determines the majority of the item’s
value, to correct pricing. Each mod has its own range of values, and even that range is
split into smaller chunks referred to as ‘tiers’.
Item modifiers or ‘mods’ for short are a common concept in role-playing games, and
one of the clearest examples of the depth achievable in different IGEs. Mod generation,
transformation and taxonomy and the tier system are covered in detail in section 3.1.2.
Now, let us combine all of the above. With what we’ve seen so far, it would be negligible
not to suggest k -nearest-neighbour regression - surely, with the help of clever clustering,
a model for a certain item may be produced by learning from sales of similar items.
Unfortunately there are, as of the time of writing, 47 currencies in the game, 24 of which
are commonly used for everyday trading. All of these are capable of modifying an item,
minutely or otherwise, essentially transforming one item into another of the same base,
sometimes altering the all-important list of mods. This makes any attempt to come up
with a formula for the similarity coefficient very inefficient, as it would be dependent
10
CHAPTER 2. BACKGROUND 2.3. PREVIOUS ATTEMPTS
The pricing problem for Path of Exile has been attempted many times before unsuccess-
fully. As of the time of writing, the work in this report is one of only a handful of tools
in the public domain capable of pricing items better than a completely random system
would - in fact, as discussed in the validation chapter 5, the software can accurately place
72% of the total item universe within a reasonable range (where ‘reasonable’ is defined
as within a small range around the price a competent human would produce).
Data is generated by Path of Exile every few seconds as a very large JSON object
11
2.3. PREVIOUS ATTEMPTS CHAPTER 2. BACKGROUND
that represents the current state of the market. This ‘chunk’, as it will be referenced
countless times in the following pages of this report, contains a long list of inventories,
each associated with one player and containing a list of items, sometimes several hundred
items in length. The data comes from an API endpoint described further at the beginning
of chapter 3 and is commonly known among the community as the ‘public stash tab API’,
the ‘river’, the ‘stream’ or simply ‘the API’. The comparison to a flowing body of water is
obviously due to the continuous release of new data chunks representing the changes in
the current market state.
Ten tools designed specifically for analysing Path of Exile3 are described in this section
in no particular order, all of which have contributed towards this work in their own way
and some of which are now defunct. Even though all of these arguably deserve their own
chapter, they are in the background pages of this report because many of the problems
encountered early on in this work were solved making use of these previous efforts, and
for them I am eternally grateful.
It is worth mentioning that there have been several previous attempts at learning
from other, much simpler IGEs such as that of RuneScape, including a notable (and
successful) neural-network-based attempt by students at Northwestern University in
the United States [101]. However, as the last paragraph of the previous section states,
the objective that concerns us is to make at least some headway into the much more
interesting, unexplored territory of the Path of Exile economy and thus that is what we
will be focusing on.
2.3.1 poe.trade
poe.trade [103], the king of all PoE-related websites, is a very fast market indexer
originally written by Ilya Zhuravlev. It features a spider crawler to trawl game forum
threads for items on sale, and consumes the API stream as fast as it is generated, parsing
items into its database and displaying them in a user-friendly format until they are sold
or removed by the user who listed them. Its internationalisation, parallel processing,
caching and usability make it the best-in-class indexer for the game.
The website is quite flexible and allows for searches using over 50 parameters, but the
function we are interested in is its import button. With a few clicks, users can price their
items easily by searching the entire database for items with the same mods (and possibly
different values). However, the algorithms used are way too simple to guarantee a price -
in fact, in over 90% of cases for items with the maximum amount of mods the system fails
to find any matches at all, as adding properties makes the item more unique and thus very
unlikely to exist before. When items do match within a reasonable margin, often they will
not have a price associated to them and thus be of no help whatsoever to the user, and
the very same problem of misinformation occurs when the match is incorrectly priced by
whoever owns it. Additionally, imported search fields have to be manually and sometimes
extensively added, removed or edited to make sure the matches are indeed similar.
In short, the tool is not really designed as a price checker, but it is far from being
devoid of value. Zhuravlev’s indexer is one of the few tools consuming sufficient data
3
Although, as happens with the vast majority of software produced and techniques used, they can be
applied with minor changes to any community market.
12
CHAPTER 2. BACKGROUND 2.3. PREVIOUS ATTEMPTS
ExileTools was a host of several tools running on the Path of Exile community APIs. One of
these, the market indexer [81], was the most advanced search engine ever created for the
Path of Exile market. Running on an ElasticSearch [23] and Apache Kafka [27] back-end,
it translated items into a search-friendly format and provided a neat, polished interface
with even more search parameters than poe.trade (2.3.1). ElasticSearch ended up being
the document storage choice for this work precisely because of ExileTools’s efficiency.
A few other similar indexers such as PoEApp [24] and ExileTrade [81] have been created
for this economy, each with their own set of features that set them apart from the rest.
While they have not caused an impact in this project, it should be noted that all of the
tools described have done a great job of parsing the market into a user-friendly format.
Unfortunately, none of them have made a real effort to tackle the pricing problem and
are mentioned to illustrate the point that most developers do not delve into it due to the
time-consuming nature of the task.
2.3.4 poe.ninja
A beautiful interface coupled with informative and, more importantly, robust statistics
running on a Meteor [50] backend make poe.ninja [61] the go-to site for checking the
currency exchange rates of Path of Exile. Recall there are several dozen currencies as
mentioned in 2.2.2, each with its own intrinsic subjective value, so this is no easy task.
The tool provides price checks for items that have little to no variation and for
which historical records are easy to find, for example, those where principal-component
properties such as the modifier list do not change at all. Note these static items are
intentionally and completely excluded from this work, as they provide little to no challenge.
Nevertheless, if the report’s companion software is to be released to the public, it should
have these capabilities, and poe.ninja is an excellent example of data science done right.
A simple substitute for a full-fledged currency exchange can be built from the ground
up by simply looking at the most popular (‘best deal’) currency-to-currency listings in
the last 24 hours. The effect on accuracy of using such a seemingly naive system is
13
2.3. PREVIOUS ATTEMPTS CHAPTER 2. BACKGROUND
negligible, but the future work chapter includes details on how to make statistically
sounder calculations. Indeed, poe.ninja itself provides a currency exchange API that
would avoid reinventing the wheel.
The first real price check attempt on this list, stashi.org [94] used fuzzy logic and trend
analysis to try and predict how valuable items were based solely on their current use by
the Path of Exile playerbase.
First, Stashi analysed the player ladders4 and built a statistical picture of the popular,
viable playstyles in the game at that moment. Then, items associated with those playstyles,
or ‘builds’, as they are commonly referenced, were stored and given a fuzzy affinity score.
Any item subsequently entered into the system was priced according to overlaps with
existing playstyles. Although the idea is sound, it seems as if the software would have
been put to much better use as an addition to a more robust system, capable of objectively
identifying valuables in a very large item space even without access to trends.
Eventually, the author moved on to another videogame and development ground to
a halt, but fuzzy logic continues to be one of the most original approaches to solving
the rare pricing problem and as such it should definitely be mentioned in any further
research.
By far the most bizarre and original background work encountered writing of this software
is PoETradeChat. Skipping the pricing problem entirely, its author decided to make money
off the economy another way, which is almost hard to believe. Three thousand instances
of the game ran on close to as many computers in a Chinese server farm paid for in
Bitcoin, 24 hours a day, 7 days a week, running optical character recognition software on
all of Path of Exile’s trade channels. Whenever an item in a predefined set was spoken
about or linked in any of the chats, the system would detect it and gauge the level of
activity surrounding it. If it was deemed enough, a human operator would receive a push
notification on a chosen medium, for example, in SMS form. The human could then use a
direct link to contact the seller in game, and the continuous gains that resulted net the
developers of the program some of the most impressive wealth ever seen in the game.
Obviously similar programs are not an option for a project of this scope, but unusual
solutions are definitely worth studying. During the months spent investigating previous
attempts, I spoke to dozens of developers and many more players about pricing, as no
insights are as valuable as those of people who have already spent years on the topic,
especially those with out-of-the-box approaches like this.
4
A ladder is a form of competitive ranking where players try to climb to the top ‘rung’ (position 1) by
accumulating some kind of score such as experience or play time.
14
CHAPTER 2. BACKGROUND 2.4. DATA MINING
2.3.7 PoEPrices
At the time of writing, poeprices.info [75] is the only publicly operational site which can
lay claim to the pricing trophy. The same import function visible in poe.trade (2.3.1) is
visible here, only it displays a price no matter what, even if there are very few matching
items.
The backend is extremely complex, based on several serial synergy calculations. First,
local synergy measures are calculated between all mods of an item to identify what
combinations affect the price of that particular type5 of item the most. For each following
step, types are progressively added in batches to the set space being analysed by the
synergy calculator until remaining mods are found to impact the price of all types of
items in roughly the same way or the end of the mods list is reached. The objective is to
create a system that boosts high synergy while penalising mods with close to zero effect
or detrimental effect on the price, and it works to a reasonable degree.
However, performance is not guaranteed for all types: items with high local synergy
requirements are valued much better than items where the opposite is true, as there
are several problems with exponentially boosting some mods while negating others
completely. The developers behind the site have tried to get around this by designing
gentler exponential or polynomial regression models to fit the data, scaling the parameters
gradually to find the best possible solution but have found it quite challenging. They
have also applied decision trees to the problem and seem to have slightly better results,
but there is always the creeping problem of massive feature space and computational
intractability lurking in the background.
Also, when items are priced on their site, a large range is returned, which is not
very helpful if one is looking to quickly price many items at once. That is, if an item’s
real worth is 120 units of currency, the system might inform the user his or her item
is worth anywhere between 35 and 600 units (based on a real example). This is not an
isolated problem and ten distinct items of varying worths were tested before coming
to the conclusion that, even though this is one of the best attempts yet, it is not good
enough. The user is looking for an instant, reliable number, or even a small range to use
as guidelines.
All things considered, poeprices.info is an impressive effort and definitely solid ground
to build upon in future - exposing their update-able model may even make it possible to
let the community itself provide training data, vastly accelerating learning capabilities.
This project has involved a monumental amount of data mining. Mod information, trends,
currency exchange rates, base item type information and a myriad of other data had to
be mined from scratch for many of the components of the software to be able to function,
resulting in over one and a half million lines of JSON which are just used for reference.
All this was made possible by the extensive Python library known as PyPoE [76].
Written in 2015, the library provides a stable API to Path of Exile’s obfuscated game files,
5
Types are described further in the body of this report.
15
2.5. MACHINE LEARNING CHAPTER 2. BACKGROUND
both with a QT graphical user interface and a very complete command line interface. The
library is capable of extracting the spawn weights6 of every mod in the game from the
many gigabytes of packaged or .dat files.
PyPoE is well documented and the established option for any kind of data mining in the
PoE ecosystem. At least three authors, independently of this work, have used the library
to populate their databases, and indeed the data I have used has been triple-checked
against two of their resulting sites and the original data.
The RePoE data repository [80] also contains data extracted with PyPoE but in JSON
format, much friendlier to Java than those produced by writing a Python wrapper. In fact,
some of the large JSON files used for parsing or dimensionality reduction purposes are
original copies from this repository.
The bulk of the background research conducted for this project was investigating how
to apply regression techniques to heavily nested data such as those presented by Path
of Exile’s market. In practice, this narrow outlook spread into many different areas of
learning, including classifiers, clustering algorithms, natural language processing and
most of all preprocessing, an often undervalued element of the machine learning pipeline
whose importance simply cannot be overstated for this project.
JSON data chunks coming from Path of Exile’s API have a practical maximum of 14
levels of nesting, although after thousands of market snapshots the average is closer
to 9. These levels have to be completely eliminated in order to create CSV files for
training classifiers or regression algorithms. In addition, the noisier the training set,
the harder it is to discover useful insights and, when talking about any IGE, noise levels
approach or surpass those of legitimate data. Unfortunately, this pipeline still has to
be fast enough to handle real-time market updates, which is a challenge in and of its
own. Dimensionality reduction, feature engineering or feature hashing tactics used or
referenced in this project are further explained below.
This section also deals with previous approaches to supervised regressive learning
or price prediction conducted by many different teams around the world at different
times, and how they were applied to the data at hand. Every algorithm thrown at the PoE
economy produced erroneous or hardly better than random results, with the exception of
univariate linear regression on a heavily modified version of data and neural networks. In
section 4.3 back-propagation multilayer perceptrons are discussed as the best choice for
this project - however, hardware limitations made it impossible to include them.
2.5.1 Preprocessing
Kotsiantis et al. [59] present an excellent summary of why clean data is so important and
how to preprocess raw instance sets thoroughly and effectively for supervised learning
6
In this context, the spawn weight of a mod is the chance of that mod appearing on an item. Spawn
weights change per item even if considering the same mod, as we shall see.
16
CHAPTER 2. BACKGROUND 2.5. MACHINE LEARNING
purposes. The software at the centre of this work follows several of the steps described
in their paper and adds some others such as dependency elimination.
Input filtering
Instance selection is the first and most helpful step towards a clean training set. Jankowski
and Grochowski [55] describe several techniques to do this algorithmically, including
for K-nearest-neighbour models used later on, but near-optimal selection in our case
consists merely of applying several filters in series to every chunk parsed by the system.
These filters were selected to reduce the problem as much as possible before any feature
engineering occurs, and as we shall see later on the benefits of doing so right at the
beginning are numerous. By eliminating easy-to-price goods and filtering items from
all leagues except one (see 2.2.1) we condense the considered set to what most people
consider the crux of the problem: items with a variable number of mods and enormous
dimensionality, but within only one market with limited fluctuations, albeit slightly fuzzy
ones.
Note that several authors, including Brighton et al. [12] have pointed out that K-
nearest-neighbour classification can be extremely slow over large datasets. Unfortunately,
as they describe, not only are they slow, but they can produce very large serialized models
and use up a vast amount of memory when loaded. While a lazy instance-based approach
is tested in this work, significant efficiency improvements in all aspects can be achieved
by applying an instance selection algorithm specific to KNN to vastly reduce the training
set without affecting performance. One such algorithm is the one proposed by Yunsheng
et al. [91], which removes outliers after measuring their impact on the final regression.
In a more general sense, the task of outlier detection becomes harder roughly pro-
portional to the dimensionality of the data [82]. As we shall see, it is counter-productive
and dangerously collision-prone to reduce the dimensionality of this particular dataset to
less than around 600 dimensions, making outlier detection computationally inefficient at
the very least. Trimming [97] and median absolute deviations (MADs) [63] are used in
this work to circumvent the problem somewhat. However, the system is far from perfect -
Rousseeuw and Croux [85] already did an excellent job of summarising the disadvantages
of using the MAD proving many improvements are possible. The only reason it is used in
this context is because it is relatively fast to calculate, both for ElasticSearch’s underlying
motor and for the companion software.
Missing values
Roughly half of all features in the input data are optional. There are many ways to deal
with missing values [62], and the method chosen for this work could not be simpler.
Whenever a feature is missing, it is substituted with false if boolean and 0 if numeric.
Missing string values are substituted for the empty string. In a production environment,
when choosing a more robust method for these substitutions, there are some options
which it is better to stay well away from, specifically most common value and mean value,
as synergy-based learning models would no longer be able to price items accurately.
17
2.5. MACHINE LEARNING CHAPTER 2. BACKGROUND
Normalisation
Features in PoE market data are all bounded, except for the price of the item. Since the
price is the dependent variable this poses no problem, but every other feature should
be normalised whenever possible, as the different scales confuse almost any regression
algorithm.
The common min-max normalisation technique is used to bring all variables down to a
real scale between 0 and 1. The normalised value of a variable x is obtained using the
following formula:
x − xmin
xnorm =
xmax − xmin
In the further work section of this report improvements to the normalisation process
are discussed briefly. Also note that while min-max is available in this case, many JSON
files in other contexts would require estimating the bounds or using z -score normalisation
[60].
Feature selection
With no previous knowledge of the data, several algorithms can be employed to remove
redundant and irrelevant features from the data. The most well-known option for this
task is Principal Component Analysis or PCA [72, 56], which estimates the impact of each
feature on the dependent variable. The transformation from the set of all features to
the subset of guaranteed linearly uncorrelated features yields the so-called ‘principal
components’ in descending order of variance - in other words, the feature that accounts for
the largest variation in the dependent variable is chosen as the first principal component,
and features with very small impact are considered last.
PCA is a very strong technique, its effectiveness repeatedly proven in many different
contexts [9]. It is based on linear assumptions and orthogonal transformations, and thus
does not work on Path of Exile’s initial non-linear data. However, once dimensionality
reduction has been applied, PCA uncovers some interesting results in the formatted data
which, with some assumptions, allow for ignoring features in the raw data (see 3.2.2).
Feature engineering
18
CHAPTER 2. BACKGROUND 2.5. MACHINE LEARNING
As the reader is free to check, a simple Google Scholar search for ‘JSON machine
learning’ yields zero useful results. Machine learning requires flat data to work with:
order-compliant comma or tab separated values with absolutely no depth or relation.
JSON by definition is nested, unordered data, and with an average 9 levels of nesting
flattening the Path of Exile market to a regression-friendly format is no easy feat.
If the issue is transformed to one of natural language processing, several new com-
plications arise. The bag-of-words model [44], for example, cannot deal with JSON, as
processing the entire document as one large text feature into many numeric features
causes unacceptable information loss. Actually, even if this was somehow doable we
run into a secondary issue which is much harder to solve: while brackets and other
punctuation can be filtered out with some effort, the fluid object model present in all
JSON documents prevents the filtering of field names. For example, if an array of JSON
sub-objects is being analysed, each object could have a different number of fields and the
overall document will still be valid, and since fields of a different name may be added
at any time we cannot just filter out all names in a predefined list. On top of this, con-
sider also the example where a field named ‘house’ contains the string ‘house’ and both
instances of the word are filtered in error, thus tainting the data. An obvious deduction
from all of the above is that we must treat each top-level element of any JSON document
we wish to analyse as its own feature and flatten it independently, and this is precisely
what is done in this work.
In JSON primitive types are extremely limited [25], and indeed in PoE’s data we find
just strings7 , booleans, integers and arrays thereof. The hard problem of machine learning
over JSON can thus generally be broken down into many small feature transformation or
feature engineering tasks. Below are some of the learning algorithms researched for this
project. All of them have their own use and context, but only some are relevant and even
less ended up producing a remotely accurate model.
• Boolean features are well suited to classification and regression trees (CARTs),
that try and predict a class value going through a (generally) pruned subset of all
possible boolean combinations of an instance. Ensemble methods such as boosting
[83, 34] are very useful to improve the performance of a decision tree regressor -
indeed Freund’s AdaBoost [32] was considered as an initial classifier booster before
dropping it in favour of algorithms capable of handling numeric types better.
There are other boolean learners out there, but the sheer ranges of explanatory
variables also rule out many other tree-based algorithms such as C4.5 [77, 78] and
reduced-error-pruning trees, which have to calculate the attribute with the highest
normalised information gain at each level so as to find the optimal hyperplane. We
shall see below that K* classifiers have the exact same problem.
Of course, there are certain workarounds to problems like this, such as randomly
generating decision trees and then comparing their output to improve prediction
performance [11]. This is known as a random forest model, and although the
algorithm does in fact price items correctly much more often than a completely
7
Of course, the strings become other primitives or arrays thereof once parsed.
19
2.5. MACHINE LEARNING CHAPTER 2. BACKGROUND
random model, other regression methods are far more accurate, and random forests
were dropped early on when they showed no signs of promise.
Even if some form of binary decision trees had been chosen, it has already been
proven that constructing the optimal model is an NP-complete problem [47], making
them unsuitable for very large feature spaces such as the one generated by PoE
data.
• Integers and doubles8 , or in other words numeric features, are present in all re-
gression problems. A regression algorithm is given a set of ‘explanatory’ variables
and tries to predict the outcome of a ‘dependent’ and usually scalar variable, based
on many previous examples. To clarify, in this case the dependent variable we are
trying to predict is the price of an item in the PoE market, and the explanatory set is
everything else.
There are many different types of regression, but not all of them can be applied in
this context: logistic regression, for example, can only handle nominal dependent
variables [14] and our price is numeric. Forms of stepwise regression such as
multivariate adaptive regression splines (MARS) [33] could be applied, as they
are one of the few techniques that can successfully predict dependent variable
values in a non-linear environment while keeping the complexity of a model below
alternatives like random forests or neural networks. However, the data is so nuanced
the technique is doomed to fail without extensive feature weighting, which cannot
be accomplished across hundreds of dimensions in the allocated time. Feature
weighting is mentioned under the further work section. Obviously simple linear
regression [57] is out of the question, as we are not dealing with just one explanatory
variable.
We are still left with quite a few options: univariate linear regression [68] instantly
comes to mind and is widely accepted as the default prediction algorithm for most
datasets, but requires normalisation to reach full potential. Thankfully variables
in PoE data have known bounds as described in section 2.5.1 and simple min-max
normalisation can be used. Linear regression is the chosen method for this project,
and is described in the body of this report.
Ordinary least squares multiple regression [95], often abbreviated to OLS, is the
other standard option, based on minimising the sum of squared errors in the depen-
dent variable. Unfortunately, this technique is extremely sensitive to outliers, of
which there are still many even after the preprocessing steps have executed. It was
researched because even though the number of final features is in the thousands,
the training set is orders of magnitude larger in all but a few cases (recall any kind
of linear regression will fail if there are more dimensions than training instances). A
possible fix to the outlier problem is to use the median of squared errors instead
[86], but the patch is not enough to produce valuable results (see figure 2.1). The
partial version of least squares [40] is also applicable, but was not covered in this
project because it is overly sensitive to the relative scaling of explanatory variables
8
Even though only integers are present in the raw data, doubles are generated by the preprocessing
pipeline and thus included here.
20
CHAPTER 2. BACKGROUND 2.5. MACHINE LEARNING
and implementations have been known to cause false positives or overlook real
correlations.
Both examples above have the same main weaknesses. Firstly, the linearity of the
models caps the accuracy they can reach on PoE’s dataset, which is only approxi-
mately linear. This also ends up being the case for the solution used, but the heavy
preprocessing is enough to negate most issues if the hypothetical item similarity
graph is dense enough near the instance we are trying to price. Secondly, on
complex data in general the difficulty of coming up with a successful linear model
increases proportional to the dimensions of the model - it’s much easier to fit a
hyperplane in 10 dimensions than it is in 1000.
There are some lesser known techniques such as locally estimated scatter plot
smoothing (LOESS) and its close relative locally weighted scatter plot smoothing
(LOWESS) [17], but they take a very long time to train on large datasets as they
combine classical algorithms such as the ones above into a k -nearest-neighbour-
based meta-model, a computationally intensive procedure. Additionally, they are
only successful when operating on fairly large training sets, effectively providing
lesser results for a greater investment and rendering the algorithms far inferior to
its counterparts.
Meanwhile, if we go to the other end of the spectrum there are always interest-
ing instance-based options like k -nearest-neighbour classifiers [2]. When used in
regression mode, the output value is the weighted average of the values of the k
most similar instances in the training set. Initially, this seemed like an extremely
attractive option, given the importance of synergy in the PoE market ecosystem and
the relative success of previous attempts using synergy-based methods. However,
the performance of such classifiers is sensitive to the local structure of the data;
that is, if there is a massive number of instances the distance coefficient must be
calculated for each one. Also, being a lazy classifier, k -NN does not actually learn
anything from the training data when built and rather uses it in real-time to predict
the dependent variable of a new instance. These two problems, combined with non-
clustered data, lead to classification times which are far from ideal. Furthermore,
the technique does not generalise well and is known to be especially sensitive to
noisy data [71], so even though its output is not completely random it is far from
sufficient to be considered for this project. It is worth noting that the K* variant of
k -NN classification [16] was tested on the dataset and the library implementation
was initially broken - however, once fixed it can be deduced that it would produce
even worse results due to the same principle that negates C4.5 on boolean variables,
an entropic distance measure, heavily weighed down by variable ranges.
Support vector machines are discriminative classifiers that build their models by
finding provably optimal hyperplanes between instances. Although they offer the
best performance when dealing with just a few nominal classes, SVMs can also be
used for regression [90, 89] - this is often termed sequential minimal optimisation
regression or SMO. An SMO regressor was trained on PoE’s data with default
parameters, but was quickly abandoned due to training times resembling those of
neural nets (see next paragraph).
Finally, the current protagonist on numeric regression is the growing field of neural
21
2.5. MACHINE LEARNING CHAPTER 2. BACKGROUND
networks, and indeed in the body of this report they are discussed as the best
option for the task at hand. The machine learning library used in the companion
software provides some NN functionality in the form of feed-forward multilayer
perceptrons, but they are 10 to 2000 times slower to train than less accurate models
even with moderate learning parameters and would take more than 70 days of
uninterrupted, very high RAM and high CPU availability to finish, which vastly
exceeds the resources allocated for this project. Note random sampling can be
used to reduce the training set size, but the immense number of possible item
combinations makes changes in accuracy more visible when using neural networks
rather than other classifiers. The further work chapter 6 discusses neural networks
in conjunction with the PoE data specifically.
• Boolean and numeric features are relatively easy to learn from. Strings as a part of
JSON data are tough to deal with, as very few techniques are capable of dealing with
them efficiently, opting instead to transform them to infinitely expanding cardinality
nominals9 .
Many natural language processing models were tried as part of this project, starting
with the popular bag-of-words model [58] already touched upon above (maximum
entropy methods such as multinomial logistic regression [19] are again out of
bounds, as the output variable is not nominal and cannot be transformed to be
so). A bag-of-words representation turns a string of text into a much simpler,
more abstract numerical representation based on word multiplicity, completely
disregarding grammar and word-to-word synergy. While this is a very effective way
of learning from large text samples such as email or website content databases,
strings in the raw JSON data as produced by the PoE API are quite short, and indeed
most are one or two sentences at most. Since spatial information is ignored in
regular bag-of-words learning, the length of samples is far from sufficient to provide
any kind of useful output. The addition of the n-gram model [13], also attempted in
the initial stages of the project, only marginally improves performance.
There is some existing research focusing on the much younger fields of information
extraction and information retrieval [31] as opposed to regular NLP, which started
out in the 1970s. In fact, some promising solutions have shown up to analyse webs of
data as large as the Internet [93], but this is precisely the problem: new approaches
are still mostly intended for large datasets of text-only data. Some older methods
such as the excellent set of Naive Bayes classifiers [67] have been revived for the
same purpose. It has been proven that Bayesian classification still works to a high
degree of accuracy when the dependency of variables is uniform across classes or
the dependencies cancel out [102], but after extensive testing it can be concluded
without a shadow of a doubt that the technique simply cannot deal with variable type
data where synergy is so important and strings are so short, such as the properties
of an IGE item.
At first incremental hashing [6, 15] was seriously considered - the technique is
able to hash entire string arrays directly into one variable, which seemed like
precisely what was needed for getting rid of that pesky last level of nesting. The
9
A nominal feature in a machine learning context is one whose value belongs to a finite set of categories.
22
CHAPTER 2. BACKGROUND 2.5. MACHINE LEARNING
idea was to produce several incrementally generated hashes to represent all subsets
of explicit modifiers on the item, then compare hashes across the entire dataset to
spot synergies. It was implemented in the software and tested, and unfortunately
dropped immediately after producing dismal results due to excessive information
loss.
After investigating further, it seemed that the only viable course of action was
somehow reducing the tens of thousands of possible strings in the JSON data to
nominal variables. Usually, this would require knowing or procedurally generating
every string possible and storing a translation database or dictionary for all of them,
making the system inefficient overall.
This is when feature hashing [100], popularised as the ‘hashing trick’ becomes
extremely useful. By hashing features into a fixed range and then using one-hot
sparse vectors to represent said range as final features in training instances, one can
successfully turn all possible strings analysed into a faithful numeric representation,
even those which have never been encountered before. One-hot encoding is a con-
cept taken from word embedding, an entirely separate area of NLP applicable here,
which normally maps nominal values to numerical vectors with all elements zeroed
except one. It was originally designed and described in a computer architecture
context [43]. The original version of the algorithm transforms a single variable that
can take n distinct values to n binary variables, each indicating whether the nth
value is the variable’s value (1) or not (0).
If there are n distinct classes, one-hot encoding produces n features. So why use
this over a simple integer identity mapping? Assume, without loss of generality, that
just three real-world example classes Cat, Dog and F ish exist, for clarity, and each
is mapped to an integer from 0 to 2:
Cat = 0
Dog = 1
F ish = 2
Any linear classification algorithm will make a decision based on the simple con-
straint w∗x+b > 0. In effect, this means class Dog will become the average of classes
Cat and F ish, which makes no semantic sense and will result in null performance.
Another naive approach to encoding nominals considered initially was simple binary.
With n classes, one-hot creates n features, and binary obviously reduces this to
log2 (n) features. Unfortunately, this would make all numeric variables in the final
encoded vector dependent, making the format unsuitable for machine learning. To
illustrate this consider the following example with 4 nominal classes A, B , C and D .
A = [0, 0]
B = [0, 1]
C = [1, 0]
23
2.5. MACHINE LEARNING CHAPTER 2. BACKGROUND
D = [1, 1]
There are many classifiers and regressors for all three different features, but very
few capable of picking up all three. Neural networks are an example of the latter, and
definitely a force to be reckoned with in this field. However, their training requirements
were completely out of reach for the duration of this project, especially since a dedicated
sampling technique would have to be devised to ensure any form of reduced training set
preserves the characteristics and accuracy of the original.
The final pricing system is based on linear regression over 17 of the original features
of the item. Four of these are one-hot encoded, resulting in a total of 663 dimensions,
quite an improvement considering the number of possible combinations (see 3.1.2).
10
In other words, a small change in the input produces a large change in the output.
24
CHAPTER 2. BACKGROUND 2.5. MACHINE LEARNING
Figure 2.1: Classifier benchmark: RMSE for seven attempts at pricing the same set of
items
25
2.5. MACHINE LEARNING CHAPTER 2. BACKGROUND
The units on the Y-axis are currency units of medium-low denomination, so with some
work and training time the neural networks used could predict the price of any item
to within the equivalent of a few cents. Note the sample set for this graph is merely
representative, and IB-k in particular performs much better than shown on other item
types. As mentioned above, the subset was carefully restricted to allow the neural
networks to work their magic.
There is an entire machine learning branch concerned with the study of hierarchical data,
and it would be a sin not to include it in this report. Statistical Relational Learning or
SRL [41] is concerned with modeling the relationship between instances using advanced
forms of knowledge representation such as first-order logic.
SRL requires some heavy feature engineering of its own to perform adequately [84]
and unfortunately does not quite fit the bill to deal with PoE data. It is designed and
implemented to deal natively with uncertainty, and the dataset considered in this work is
completely deterministic. In summary, even though it is a field growing in giant steps in
time with the big data boom, it was not included in any way in the final results, as the
time investment was deemed unworthy of the probable yield.
26
CHAPTER 2. BACKGROUND 2.6. JSON PROCESSING
The popular Jackson (‘JSON for Java’) library [96] was used in the initial stages of this
project. The POJO11 data-binding and tree APIs were found insufficient and too slow, so
too many hours were invested in writing the perfect token streaming parser just to find
that Jackson cannot deal with heavily nested data like the PoE market. Closer analysis
reveals that the default JSON handling library at org.json is capable of accessing fields
much faster, as Jackson must read every single token in the file before being able to
produce and use a cache mapping. It should be noted Jackson is still the faster option
when dealing with simple JSON. A performance comparison is shown below:
Figure 2.2: Performance comparison between the two JSON parsers tested for this project.
There are other JSON libraries designed for Java (notably Google’s excellent GSON),
but as of the time of writing org.json is more than sufficient to keep up with market
update speeds.
2.7 Databases
There is a wide range of storage options available for any kind of problem, but JSON data
in particular leans towards a NoSQL solution due to its nature and structure. However,
other infrastructures were researched and in some cases tried anyway, as read-write
speeds are a definite issue when dealing with market data and machine learning.
11
Plain Old Java Object
27
2.7. DATABASES CHAPTER 2. BACKGROUND
2.7.1 SQL
By far the most popular databases in the world are based on the Server Query Language.
The relational schema, organisation and amazing query flexibility of SQL is envied by
NoSQL options, and I made the mistake of trying very hard to fit the original, deep JSON
data into a MySQL database. This turned out to be a very time-consuming and wasteful
investment, as designing and running very inefficient queries with up to 11 joins was
necessary to return any form of useful data. The schema design alone was a nightmare,
and that was taking at least some inspiration from existing solutions [92]. Transformation
to the third normal form was also non-trivial - indeed the logical schema had almost
half the tables of the physical schema due to intermediate mappings. Normalisation was
definitely not the way to go.
Additionally, queries are cached in SQL and B-plus tree indexes make it very easy to
search tables by row index. This is also precisely the reason SQL was finally abandoned:
it simply has no fast way of dealing with queries involving non-indexed columns.
2.7.2 MongoDB
Moving on from MySQL, MongoDB might sound familiar to the reader as the single most
popular NoSQL solution - indeed, internal Mongo storage is based on Binary JSON [51].
This made the option quite attractive as the raw data was in JSON, but Mongo fails on the
same principle as SQL. It reads and writes documents completely in bulk - that is, the
entire chunk (or, for the sake of argument, a smaller document representing an item) is
saved to permanent storage with no indexing whatsoever and native binary-optimised
query methods are used to search it. This would be fine in the case of preprocessed data,
but caused a switch to Apache Cassandra at the time.
Cassandra was briefly considered as the main project database because it is provably
faster [79] than any other NoSQL solution, but was dropped in the setup stage due to
replication and fault tolerance overheads preventing its execution on a laptop environment.
It is one of the largest NoSQL providers out there and the extra features are useful to
sites like Reddit, but completely unnecessary in a research context.
An important step on the way to the final solution, column-oriented database management
systems [1] index columns instead of rows. Field retrieval becomes exponentially faster
at the cost of relational information queries becoming slower.
Assume one relational database and one column database hold the exact same ten
thousand instances. If each instance has attributes A, B and C , table 2.1 exemplifies
query efficiency for each.
28
CHAPTER 2. BACKGROUND 2.7. DATABASES
SQL and other relational systems must fetch the entire row by index, then look up a
non-indexed field. They perform well when entire rows are required at once, as only one
disk read is required per row. Columnar databases index by column, therefore the first
query is as fast as can be, but two different disk reads are required to cross-check both
conditions as happens in the second example query.
From the above, it is easy to see that column databases are especially useful in contexts
where every query is likely to be different. More importantly, they can store just the
distinct values of a column with a pointer to all rows containing that value, which greatly
increases storage and query efficiency.
2.7.5 ElasticSearch
ElasticSearch is the document store used in this project. Based on the lightning fast
Apache Lucene [28] search project, ElasticSearch is a cleverly designed mix of inverted
indexing, k -D trees [8] and analytic-friendly internal storage designed to provide near-
instant query response times even for millions of documents.
It is by far the superior option in this section, and the choice to use it was locked in be-
cause the engine produces ultra-fast, reliable location statistics and several other metrics
which are used to calibrate the final training sets, a definite quality-of-life improvement
over manually writing scripts to do it on other systems.
It should be noted all data was re-indexed (downloaded, removed, transformed and
re-inserted) a total of six times as performance and semantic adjustments were made,
and the final provided database contains only clean, preprocessed documents ready to
extract training data. Each document in the store represents one item.
29
Chapter 3
Preprocessing
The preprocessing chapter describes the initial stages of data retrieval and transformation.
JSON is polled regularly from an API endpoint, filtered, transformed to much simpler
ElasticSearch-friendly records, then flattened to CSV and passed to the machine learning
pipeline.
Path of Exile has opened several developer APIs to the public in the last few years. Among
them are the Player Ladder API, which records player experience rankings and items
and can be parsed to find trends and meta1 information, the elusive Player Online API,
available only to trusted developers and used to record a player’s online status and,
perhaps of most relevance to our project, the public stash tab API.
The public stash tab API, henceforth referred to just as ‘the API’, is the main entry
point for any third-party developer who wishes to use the PoE economy in some way. It is
uncommon to find a popular game with a market without a market API. This particular
one is part of the backend behind all market indexers such as poe.trade (2.3.1). A stash
is a player’s inventory, and a tab is just like a browser tab: a separate space within the
inventory to ease organisation tasks when the number of items owned by one player
becomes unmanageable without them. In other words, one tab represents a collection
of items and one stash represents a collection of tabs. The API backend is constantly
running, parsing all stash tabs marked as public (visible to the outside world and not just
the player) into JSON format. However, it is not that simple: the API does not save all
items in all tabs, creating a historical record: instead, it records only all tab-wise changes.
For example, if stash tab S1 used to have just one item A and the item has been removed
or sold, the API will mark it as empty and the first JSON chunk available will reflect the
change by displaying an empty tab. If tab S2 had items A, B and C and one item D is
added by its owner, the entire tab is added to the data stream with the new item.
When a sufficient number of changes occurs (there appears to be no exact number,
1
Meta is an extremely common concept in IGEs and virtual worlds which refers to anything popular, be it
items or builds. The meta of a game changes when developers modify existing content or add new features
to the game.
30
CHAPTER 3. PREPROCESSING 3.1. API ENDPOINT
the most probable explanation is that the number is based on the server load average at
that moment), all data recollected until that point is clustered together in one JSON file
and sent on its way with a unique identifier, becoming available as what we may loosely
call the next market snapshot. This JSON file is almost always more than 100,000 lines
long, often reaching triple that amount. The API started producing these chunks of data
in October of 2016 and has been updating ever since. Several million items from this
stream, a tiny percentage of the total available, form the raw data for this project and
reach the later stages of the software.
As a final note before moving on, the reader should be aware the API is far from
perfect - in fact, the vast majority of the community is disappointed in the format, often
commenting on its obscurity and complexity. It is slow to parse and even slower to process,
and one of the difficulties that had to be overcome during the design stage was consuming
the stream updates as fast as they are generated, which is every few seconds. To this
day it is not known why this is, but a definite possibility is that the API was intentionally
coded like this by the game developers, with the intention of delaying the inevitable onset
of economic analysis.
It is necessary to have at least a basic knowledge of the format followed by PoE’s data
stream if one is to understand the following sections. What follows is a moderately
abstract overview of the top-level fields present in the data, that is, the ones directly
available to any JSON parser without diving deeper into the object. Some example API
chunks can be found in the final project archive.
When starting from the document root, there are just two fields in the chunk:
• stashes: The main array of stash tabs, which represents more than 99.9% of the
bulk of the document. To reiterate, each element in the array represents one tab and
not one stash, which often results in information repetition when the same player
owns several tabs in the same chunk of the river, as the tab’s owner is stored on a
per-tab basis. See below for the full list of fields for each stash tab.
• id: Hexadecimal identification string representing the internal ID of the stash tab,
for all intents and purposes ignored in this work.
31
3.1. API ENDPOINT CHAPTER 3. PREPROCESSING
• stashType: The first of many strings that could just as easily be converted to a
much more efficient format such as boolean or numeric, that indicates whether the
stash tab is of type PremiumStash (paid for with real cash as a microtransaction,
see footnote on page 7) or of type NormalStash (the default stash tab type). Note
premium tabs are extremely common, as they are a relatively small investment
which provides large quality-of-life improvements, and indeed they represent more
than 95% of all tabs parsed by the API.
• stash: The first of many other strings that could be renamed to a much more
descriptive name, this string is either empty for normal stashes or represents the
name assigned to the tab by its owner. This is an important field, as the name can
be parsed to obtain the price of all items in the tab if they do not have a price set.
• accountName: The account name of the tab’s owner, stored by my software just to
identify blacklisted sellers.
• lastCharacterName: The name of the last character played by the tab’s owner
(ignored in this work, useful to contact players in-game to make trades happen).
• items: The main item array, the most important element of the tab. The collection
of items is to all intents and purposes unordered, as are the tabs themselves. There
are some fields which remain constant across all item types and some which appear
only on certain categories of items. All possible fields are described below.
For each item, a total of 43 fields are possible. Some of these fields are deeply (and
most of the time unnecessarily) nested and this report is not intended to make the reader
an expert on the nuances of the raw data, so all root-level fields are summarised in table
3.1 on the next page. If feeling adventurous, appendix A describes all fields in much more
detail.
As the field with most impact on the price of an item, explicit modifiers or just ‘mods’
deserve their own subsection. They are the basic premise which make Path of Exile items
so incredibly varied.
Mods usually have a large range of values they can take - for example, ‘+6% to Cold
Resistance’ is not the same as ‘+48% to Cold Resistance’. This range is further split into
much smaller subsets known as ‘tiers’. Tiers decrease gradually as the value of the mod
increases and are approximately uniformly distributed over the entire range. This means
a Tier 1 mod will be much more powerful than a Tier 10 mod, because its value or set of
values is within the Tier 1 range, which is much higher on the overall scale. When a mod
is generated on an item, one of the values in the mod’s range is chosen at random. This
value can be changed further only within its tier - that is, if the current value is 7 and
its tier ranges from 5 to 8, then the mod will never roll2 higher than 8 or lower than 5
2
A common analogy to the roll of an n-sided dice referring to the randomness of the value produced by a
random or pseudo-random number generator.
32
CHAPTER 3. PREPROCESSING 3.1. API ENDPOINT
Table 3.1: All possible fields for one raw JSON item.
33
3.1. API ENDPOINT CHAPTER 3. PREPROCESSING
without very significant currency investment to remove and re-add it, which is far from
being cost-effective. See table 3.2 for an example.
Table 3.2: Tier table for the common defensive suffix ‘+# to Cold Resistance’. Note that
in this case, the # is replaced upon mod generation with exactly one value from 6 to 48.
On items with only one or two mods, they usually appear as a visible addition to the
base item type string. If the type is "Ring", adding one mod means the name of the item
changes to, for example, "Ring of the Maelstrom", and adding another would yield, for
example "Robust Ring of the Maelstrom". Any more mods and the dependency between
the name of the item and the item’s mods will disappear. Even so, this format has given
rise to the denomination ‘affixes’ for mods within the game, and indeed for any single
base item there is a large pool of ‘prefixes’ and an even larger pool of ‘suffixes’ the
game randomly chooses from when generating the item for the first time. There can be
a maximum of six affixes for every item base type considered in this work, including a
maximum of three prefixes and three suffixes in total. There can be no less than 2 affixes.
That is, if prefixes were represented by the letters A-M and suffixes by the letters N-Z,
some examples of items could be:
I0 (valid) = {A, B, C}
I1 (valid) = {N, O, P }
I2 (valid) = {A, B, C, N }
I3 (valid) = {A, N, O, P }
I4 (valid) = {A, B, C, N, O, P }
I5 (valid) = {M, L, K, Z, Y, X}
I6 (invalid) = {A, B, C, D, N, O, P }
I7 (invalid) = {A, B, C, N, O, P, Q}
I8 (invalid) = {A, B, C, D}
I9 (invalid) = {N, O, P, Q}
I10 (invalid) = {D}
Items 6 and 7 are invalid because they violate the maximum affixes constraint, items
34
CHAPTER 3. PREPROCESSING 3.1. API ENDPOINT
8 and 9 are invalid because they violate the maximum prefixes and suffixes constraints
respectively and item 10 is invalid because it violates the minimum affixes constraint.
Proof of complexity
The below is proof that there are at least as many combinations for an item in Path of
Exile as there are stars in one million galaxies like our own. This will hopefully push home
the point of non-existent historical record.
The binomial coefficient, or number of ways to choose k elements from a set of n
elements:
N n!
=
K k!(n − k)!
Let P be the set of all possible prefixes for an item, and S be the set of all possible
suffixes. We know there can be a maximum of Pmax = Smax = 3 affixes of each type on any
item considered in this work.
The number of possible prefix combinations on an item is:
PX
max
|P |!
i=1
i!(|P | − i)!
SX
max
|S|!
i=1
i!(|S| − i)!
The number of total affix combinations on an item, valid or invalid, is simply the
multiplication of the two results above:
PX
max SX
max
|P |! |S|!
∗
i=1
i!(|P | − i)! i=1 i!(|S| − i)!
The final step is to remove all combinations which results in 0 or 1 affixes to get the
formula for the final number of possible combinations for any item I, denoted here as CI :
PX SX
!
max max
|P |! |S|!
CI = ∗ − (1 + |P | + |S|)
i=1
i!(|P | − i)! i=1 i!(|S| − i)!
Note if one were to implement the above formula in a production environment there
are much faster, more computationally viable alternatives which do not use so many
factorials, and the form shown here is done so for the sake of compactness.
To find the total possible number of items in the game, we need the set of all distinct
base items (those with no explicit modifiers) B . Let Bi denote the i th element in this set.
The formula for all possible combinations of explicit modifiers in Path of Exile Ctotal is:
35
3.2. JSON PARSING CHAPTER 3. PREPROCESSING
|B|
X
Ctotal = CBi
i=0
As of the time of writing, set B contains a grand total of |B| = 874 bases. 722 of
these bases are considered in this work, as the other 152 are considered easy to price
by most of the community. This results in over 172,766,763,654,978,801 (≈ 1017 ) total
combinations. Considering the Milky Way contains around 1011 stars, assigning one item
to every star you would need one million galaxies like ours to finish.
This is by no means the end of the story - the above calculations do not include:
• The 152 remaining bases, obviously, each with millions or billions of combinations.
• The 884 possible additional distinct enchantment modifiers on glove, boot and
helmet item types.
• The thousands of possible socket and link combinations (with only two sockets
already 20 are possible, and items can have a maximum of six). For more info on
sockets and links see appendix A.
Adding these parameters brings the real number of combinations well beyond the
range of the IPv6 address space, an unimaginably huge number.
The software uses the org.json library to parse raw data. Alternatives such as Jackson
are covered in the background section. This library deals with missing values in a very
elegant way, and is also significantly faster than Jackson when dealing with highly nested
JSON.
Raw data arrives from the API endpoint in chunks, as detailed in 3.1. The main
program execution loop takes care of setting the pointer to the next page of data using
the JSON’s root next_change_id, then sends the chunk off to further processing. The
chunk is processed tab by tab in a top-to-bottom fashion - all valid items encountered are
tagged with the tab owner and sent to the indexing pipeline described further down.
3.2.1 Filters
The raw data is extensively filtered to remove any items not of interest to this project.
Even though around 90% of everything on the market is removed, the final document
database for this project contains a total of nearly 2 million items.
36
CHAPTER 3. PREPROCESSING 3.2. JSON PARSING
League filter
Non-standard leagues, also known as ‘temporary’ leagues, have their own economy and
usually last three months only, after which all items are moved to standard leagues. It
would be counter-productive to try and analyse all four main leagues in PoE at the same
time, and the software has been written to ensure that it is possible to apply the same
procedure to items in other leagues by tweaking the minimum amount of code possible.
Furthermore, leagues are divided into the softcore and hardcore markets. When your
character dies in a hardcore league, be it temporary or standard, it and its items are all
moved to the standard softcore league. The market revolves around this mechanic in
hardcore leagues and does not obey normal trends. All of this distills into one key fact:
only items from the standard softcore league are ever touched by the algorithm.
Rarity filter
The frameType attribute of the raw JSON data, described as the top-level item category
in table 3.1, is often known as ‘rarity’ in an in-game context, and that is the word we will
be using here. As of the time of writing, there are ten possible rarities in Path of Exile:
Normal, Magic, Rare, Unique, Gem, Currency, Divination Card, Quest Item, Prophecy and
Relic.
All items except rares are easy to price - however, as is visible on the pie chart above
rares make up a sizeable chunk (almost 37%)of the market. For proof that rares are hard
to price for most of the community, see section 1.2.
37
3.2. JSON PARSING CHAPTER 3. PREPROCESSING
Base filter
Price filter
First of all, any item without a price is useless as training data and is completely ignored
by the algorithm. The ones that remain follow the restrictions below.
Any item with a maximum price over 15000 units (roughly $150) is filtered out. There
are items worth this and much more on the market, but there are many reasons to cap
the maximum price in this way.
The majority of rare items on the market are priced from 0 - 1000 units. The reader
must remember this is a totally subjective price and is not set according to any guidelines.
Trades happen quickly and constantly, and accumulating wealth as a human player means
processing a never-ending stream of information to identify under-priced items, grab
them and ‘flip’ them for profit. To flip an item of course refers to the act of buying it
cheaper than average and reselling it at a more expensive price. When items are priced
above 15000 units, there are two options. Either the item really is that good and there
are people willing to pay the exorbitant price, or someone too lazy to correctly price their
item set it extremely high so that no one would buy it until they had time to get to it. The
latter is much more common. If humans see any such item, they would be able to identify
it instantly as an outlier and filter it out, but for a computer it is very hard to tell these
two apart.
Thus, anything above the cap is not considered. The predictive algorithm will still
occasionally place an item above the cap if it thinks it is valuable enough - it has no such
boundary.
At the other end of the spectrum, there is also a recurring problem with botnets trying
to lower prices artificially, and this must be considered if there is ever a next iteration to
the work described in this report. For now, all prices below 1 unit are ignored.
In addition to the trimming detailed in previous paragraphs, the median absolute
deviation of the entire dataset is periodically obtained from the data set. For a univariate
data set X1 ...Xn , the formula for the MAD is simple:
38
CHAPTER 3. PREPROCESSING 3.2. JSON PARSING
M AD = median(|Xi − median(X)|)
And in fact, we can use the MAD as a robust estimator for the standard deviation
by using a constant scale factor k , which since the price distribution is assumed to be
normal is defined to be the reciprocal of the quantile function for the standard normal
distribution, i.e.:
1
k= ≈ 1.4826
Φ−1 ∗ 3/4
Note the 3/4 argument is taken so that the median absolute deviation covers exactly
50% of the normal cumulative distribution function.
Since we are dealing with big data, trimming the price is a more than sufficient
measure to obtain good results, as the breakdown point of all prediction algorithms used
is quite a bit higher than the percentage of wrongly priced items which reach the training
set. However, the option has been implemented to ignore anything outside 3k median
absolute deviations for each item base when filtering.
Price parsing
The price is obtained from the note field of the object or, if not present, from the tab-wide
price set by the stash field. As the only user input, it must be treated very carefully and
validated with the following regular expression so as to avoid exceptions being thrown at
some stage of the pipeline:
\~(b\/o|price|c\/o)\s*\d+[\.,]*\d*\s*\w+
Once checked, the string is split into three chunks along the separators. Note if the
separators are missing the string is malformatted but still parsable, hence the optional
parameter * after all \s. The first chunk represents one of the three options Buy-Out (the
price you should pay if you want the item instantly, with no negotiation), Current Offer
(the current highest offer on the item, indicates the seller is looking to buy higher) or
Price (simple price on the item, with no nuances either way). The second chunk is the
amount of currency, and the third is the currency itself. To put a simple example, the price
string ‘~price 213 c’ indicates the item is on sale for 213 units of the currency type
‘Chaos Orb’ (see appendix B for details). The amount is easy to parse, but the currency
identifier, known as ‘tag’, must be checked against an existing dictionary compiled for
this work which maps each tag to the currency they reference. If the tag does not match
any of the 136 options defined, it is almost certain that either the currency is extremely
obscure and almost never used to price items or the tag is plain wrong. In both cases the
item is discarded. If the tag does match, the exchange rate database (also data-mined
from scratch) is consulted to convert all currencies to a standard unit.
39
3.2. JSON PARSING CHAPTER 3. PREPROCESSING
The bulk of preprocessing is not the filters - it’s the preparation and transformation of the
raw data from an obscure and obstructive format with an average of nine levels of nesting
to a neat, 1-deep JSON document which ElasticSearch can process quickly. Almost all
features are converted to numerical types to avoid processing later via a combination of
feature selection and engineering.
Running variants of principal component analysis over the entire dataset reveals that
changes in the explicit modifier array and changes in item socket links produced the
biggest variance. This can be checked quickly with simple examples; for example, the
following figure is representative of the change in price increasing the quality of the item
versus increasing the total number of linked sockets on the item. Variable ranges are
different, but it’s clearly visible that socket links have a much greater impact. Note we
are using the 75th percentile of price to exclude most problematic outliers.
Figure 3.2: Changes in price caused by modifying the value of quality versus the total
number of sockets linked.
The first eight principal components for PoE data (modifying PCA to accommo-
date the complex nature of these dimensions) are as follows: explicitMods, sockets,
craftedMods, enchantMods, frameType, typeLine, ilvl and league, in descending order.
In fact, table 3.1 is roughly ordered by impact on item prices.
Knowing this, lets take a look at a raw data item and see how exactly it is processed
within the software.
40
CHAPTER 3. PREPROCESSING 3.2. JSON PARSING
Raw JSON:
1 {
2 "identified": true,
3 "corrupted": false,
4 "duplicated": false,
5 "ilvl": 59,
6 "frameType": 2,
7 "league": "Standard",
8 "typeLine": "Decimation Bow",
9 "properties": [{"name": "Quality","values": [["+7%",1]]}],
10 "sockets": [{"group": 0,"attr": "D"}, {"group": 0,"attr": "D"}],
11 "implicitMods": [ "40% increased Critical Strike Chance" ],
12 "explicitMods": [
13 "Adds 36 to 66 Fire Damage",
14 "Adds 3 to 111 Lightning Damage",
15 "0.28% of Physical Attack Damage Leeched as Mana",
16 "+4 Mana gained on Kill",
17 "+112 to Accuracy Rating"
18 ],
19 }
As mentioned, this is by no means the full JSON object - full examples of API chunks
and items can be found in the final project archive. As can be seen from table 3.1, there
are many fields which have been artificially removed or are missing in the original. Other
fields such as the properties one have been vastly cut down for the sake of argument.
Some domain knowledge is required for the following paragraph, as it deals with
identifying and removing known dependencies in the data. There is no way to prove the
dependencies are there without using complex algorithms like association rule mining,
which is outside the scope of this project, but they can be informally checked online on
the Path of Exile Wiki [37].
Fields maxStackSize, descrText, secDescrText, flavourText, support, colour,
artFilename, prophecyText, w and h have a functional dependency to property typeLine.
For that matter, everything in the properties and requirements arrays except the quality
property can also be deduced from the combination of typeLine, explicitMods and
implicitMods. Fields identified, talismanTier and implicitMods can also be deduced
from the same typeLine field most of the time, but the methods are not consistent enough
to use in production. All fields in the first list are ignored by the algorithm.
PCA reveals many other fields that are not dependent but have zero or negligible
impact on the item price, as is the case with the socketedItems array. This is especially
helpful to the JSON parsers, as all children of these elements can be skipped with no
negative consequences.
It is crucial to store documents in the most compact possible manner, both to speed up
Lucene indexing and to make sure the CSV generation stage has to download only exactly
what it needs to proceed from the database. Everything in the processed JSON below has
some impact on the price, but the main element is the only remaining level of nesting, the
41
3.2. JSON PARSING CHAPTER 3. PREPROCESSING
explicit modifier array. This level will be flattened to 512 new dimensions when passing
the document to the CSV pipeline.
A carefully crafted 32-bit hash function is responsible for assigning an extra reserved
_id field to every ElasticSearch document to make sure if the exact same item is encoun-
tered again it will not be re-added. There is a higher chance of a hash collision happening
than of encountering a second item generated with the same properties entirely by chance
(although hash collisions are relatively common in the 32-bit space after the one million
item mark due to the birthday paradox).
Processed JSON:
1 {
2 "owner": "<owner>",
3 "price": 3,
4 "identified": 1,
5 "corrupted": 0,
6 "mirrored": 0,
7 "itemLevel": 59,
8 "base": "Decimation Bow"
9 "type": "Bow",
10 "quality": 7,
11 "socketsTotal": 2,
12 "socketsRed": 0,
13 "socketsGreen": 2,
14 "socketsBlue": 0,
15 "socketsWhite": 0,
16 "socketsLinked": 2,
17 "implicit": "+40% increased Critical Strike Chance",
18 "enchantment": "",
19 "explicitsTotal": 5,
20 "explicitMods": [
21 "Adds 36 to 66 Fire Damage",
22 "Adds 3 to 111 Lightning Damage",
23 "0.28% of Physical Attack Damage Leeched as Mana",
24 "+4 Mana gained on Kill",
25 "+112 to Accuracy Rating"
26 ]
27 }
42
CHAPTER 3. PREPROCESSING 3.3. ELASTICSEARCH JSON TO CSV
possible colours and what is the largest group of sockets, that is, the maximum number
of sequential links between them. Each sub-object in the array represents one socket,
with the attr field being a colour code and the group field indicating what chain of links
the socket belongs to.
The full properties array is examined until the one named Quality is found. This
property is extracted and stored numerically in ES as simply quality. The rest are, as
mentioned above, base-dependent.
Using regular expressions to remove internationalisation strings and superfluous
prefixes and several data-mined dictionaries, the item’s typeLine is converted to two
new fields base and type, the former more specific than the latter. This type will later
be used to identify the correct model to price the item. If the reader is not familiar with
ElasticSearch, this type is also used to set the reserved field _type for each item. This
allows for much faster queries when training only one classifier for just one type of item
is desired.
The implicit ES field represents the contents of the raw implicitMods array - hence
the exclusion of talismans in the data.
The enchantment field is left blank, as no enchantMods root element has been found
on the raw item.
Finally, the explicitMods array is left as is, as processing it at this stage would slow
down indexing to the point of not being able to keep up with market update speed. Instead,
the mods are counted and their total explicitsTotal is saved.
After storing enough items in the document database and accumulating a very large
training set, the only stage left is to transform everything in the database to a format
friendly to machine learning - in other words, a completely flat format like CSV [88].
This stage is by far the hardest, and many of the previous attempts including some
of those described in section 2.3 have been stumped at this point. Starting off lightly,
the feature hashing process used to convert bases, implicit mods and enchantments to
192 dimensions is described. Recall in section 2.5.2, I mentioned the choice of hashing
function had to be perfect. The hashing function in question (MurmurHash) is described
at the same time as explicit modifier parsing is in 3.3.3 together with why it was chosen.
3.3.1 Primitives
All ElasticSearch numerical fields are normalised using min-max normalisation (see
2.5.1). Their ranges are very different, with some having a maximum of 100 and others
a maximum of 6, so normalisation ensures the algorithm does not erroneously weight
higher values differently.
A total of 12 normalised numeric fields are written at the beginning of every CSV line.
43
3.3. ELASTICSEARCH JSON TO CSV CHAPTER 3. PREPROCESSING
3.3.2 Strings
Strings cannot be converted using the bag-of-words model due to their length, but a
simple one-hot encoding would result in thousands of dimensions so it is not valid either.
Thus, middle ground is found by using the hashing trick to reduce all strings to 64 binary
dimensions each. See the background section for more information on the hashing trick.
All strings are hashed to an integer in the range 0 to 63 and a one-hot vector is produced
with all values zeroed except the one whose index is equivalent to the generated integer.
The procedure generates uniformly distributed values and produces a large change in the
output given a small change in the input, just as required.
There a total of three strings to hash, not including explicit mods: base, enchantment
and implicit. The three resulting one-hot vectors are stringified and written to the CSV
sequentially after the initial 12 features.
MurmurHash, specifically Apache Mahout’s 64-bit version [30], is the hashing function
chosen to reduce the explicit modifier array to a flat representation. It is not the same hash
function as the one used to produce ElasticSearch IDs. It is a weaker, non-cryptographic
procedure designed for efficiency and speed, that works by looping through multiplication
and rotation procedures. It was chosen because it can operate on seeds (or ‘probes’) and
strings just as fast as it can with only the string, and because it follows the two properties
described in 3.3.2.
By far the largest data-mining task for this project was undertaken with the objective
of flattening this array. Two web crawlers were designed and implemented using the
excellent JSoup library [45] to parse the entire contents of the two websites PoEAffix
and PoEDB (2.4). The information gained was then compared to the output of the PyPoE
library and stored in a file, which can be found in the final project archive. The file is
used to translate any modifier encountered to its corresponding tier, for any item base
possible. Consider the impact of this: by just looking at table 3.2 we can see a 6-48 range
is immediately reduced to a 1-10 range with no danger to the value of the item, as the
modifier can still be rolled within the same range. This is a four-fold improvement and
subsequent dimensionality reduction, and there are many examples where the reduction
is much more drastic, up to 11-fold reductions. Let’s take the example above again:
1 "explicitMods": [
2 "Adds 36 to 66 Fire Damage",
3 "Adds 3 to 111 Lightning Damage",
4 "0.28% of Physical Attack Damage Leeched as Mana",
5 "+4 Mana gained on Kill",
6 "+112 to Accuracy Rating"
7 ]
First pop and store all variables from the string, leaving a placeholder instead:
1 "explicitMods": [
44
CHAPTER 3. PREPROCESSING 3.3. ELASTICSEARCH JSON TO CSV
This leaves us with the pure mod strings whose hashes, taking into account average
modifier ranges, are around 100 times more likely to collide. Using tables similar to 3.2,
we can use the values we just retrieved to find the tier for each mod:
MurmurHash’s 64-bit procedure is then used to flatten the array, hashing each canon-
ical modifier name, using the mod’s tier as a seed and taking the integer remainder of
division by the desired number of dimensions to produce a reliable bounded hash of each
mod. Then, instead of using a one-hot vector, an n-hot vector with n = explicitsTotal is
populated with all these hashes. After much experimentation using several powers of 2 as
the number of dimensions (as bitwise shift operations can be used to further improve per-
formance) it was found that 512 provided the perfect balance between functionality and
load time, dependent on total storage. Note anything beyond roughly 1100 dimensions
produces a sharp decline in productivity, as the vector is too sparse for linear regression
to produce useful results. Curiously, the total number of canonical names encountered by
the system around the time of writing also approaches this limit.
45
3.3. ELASTICSEARCH JSON TO CSV CHAPTER 3. PREPROCESSING
3.3.4 Clustering
46
Chapter 4
Learning
After preprocessing is dealt with, the path to a successful prediction system can only
continue by training multiple algorithms to see which one works best, then building an
input system and a simple UI to make the software usable. This chapter deals with the
first of those tasks in its entirety.
4.1 WEKA
Java, specifically version 8 is the language being used for this project. The choice was
made because of my own familiarity with the language and because version 8 provides
streaming functionality not present in previous versions.
Initially, self-coded versions of non-linear regression were considered as possible
solutions to the pricing problem. This guaranteed at least a modicum of code quality and
efficiency (and more importantly, a deep understanding of the implementation) but my
lack of statistical analysis and machine learning experience made choosing a library a
much safer option. There are several available for Java - indeed the omnipresent Apache
Foundation has its own Scala version with a Java API [29], from which the MurmurHash
function was taken.
WEKA is a Java machine learning library originally coded in 2002 by the University of
Waikato’s Department of Computer Science - its qualified name is the ‘Waikato Environ-
ment for Knowledge Analysis’. It is the accepted option when it comes to Java machine
learning, and implements a total of 83 classification algorithms. WEKA supports both
dense and sparse data and is one of the easiest ways to produce quick results when tack-
ling a new machine learning problem. This is all impressive, but the library is outdated
and has been far superseded by competitors in the field.
My experience with machine learning was non-existent before this project started - in
fact the work was chosen on purpose to round off the extensive Imperial College degree
with the only main field I was yet to dabble in. This led to my supervisor recommending
WEKA and me blindly starting to use it without a second thought, then realising too late
that there are much better options out there, albeit with some wrapper writing required.
Almost all of WEKA’s algorithms are incapable of online learning1 , so data must be
1
Online machine learning refers to environments where data becomes available in a sequential manner,
47
4.2. CSV TO ARFF CHAPTER 4. LEARNING
loaded in one chunk, hence the usefulness of splitting it into 50 CSV files. Unfortunately,
loading even a relatively small 100 MB file results in 3 GB of memory usage, so files above
150000 instances must be culled using random sampling until they are well below that
mark. Then, by assigning a heap space six times higher than normal and a stack space
ten times higher than normal, effectively restricting the use of the work machine until the
process finishes, WEKA can finally load everything it needs to train a classifier.
However, then we reach the next problem - not all of WEKA’s classifiers work. The
code is ugly indeed, but not being able to use the K* algorithm when k -NN does work
approaches the level of moderately ridiculous, since they both use the same underlying
code. The library had to be patched manually and rebuilt from source, only to find that
the latest version was missing the least median squares regressor. Eventually, the LMS
algorithm was decompiled from an old version of the library and included in the newer
version manually, after which it had to be rebuilt again.
Options to tweak learning parameters from the Java API are few and far between
(parameters are designed to be tweaked from the command line or the graphical user
interface, which was not touched during the project as it was found to be even slower
than the regular API), and documentation is either non-existent or not particularly helpful
for some areas of the code. Due to all of the above, if the project lives on it will do so
without this library.
WEKA is incapable of automatically typing features. The ARFF format [20] is WEKA’s
version of CSV: a long-winded header with feature names and type specifiers such as
@numeric occupies the first 700 lines or so, then a @data clause indicates that all lines
beyond that point represent one instance each.
WEKA’s native CSV loaders are riddled with unnecessary exceptions and memory
problems, and cannot even make use of Java’s buffered streams, so the CSV to ARFF
translation was entirely rewritten. It’s not possible to show a performance comparison
of any kind, since WEKA’s input-output modules do not even terminate on large inputs.
With a large enough buffer and using my own code, the line-by-line full translation of
all 2 million items takes around ten minutes to complete. This is still many times faster
than the original CSV download from the Elastic document database, since the network
bottleneck is difficult to overcome.
Once all the CSV is parsed and translated to ARFF, the data can be finally used to begin
the long classifier training process. The full pipeline from raw data to a clean training is
incredibly long, but definitely worth it to improve regression accuracy drastically.
After many failed attempts due to memory limitations, the following six classifiers (listed
by WEKA name) were trained on all the data:
such as the PoE endpoint producing new data pages every few seconds.
48
CHAPTER 4. LEARNING 4.3. TRAINING THE CLASSIFIERS
Figure 4.1: Accuracy comparison (%). Note neural networks and SMOReg were trained
on partial data only.
49
4.4. RESULT APPLICABILITY CHAPTER 4. LEARNING
So far, we have obtained complex raw JSON market data for the Path of Exile economy, we
have completely transformed it to a flat format and we have successfully trained, among
others, 52 linear regression models, capable of correctly predicting item prices more than
70% of the time.
Recall the limit set3 of Path of Exile items is immense. Items on sale have too many
variables to be encountered twice, so there is no applicable historical record. This, in
addition to all prices being set by humans, makes it very hard to predict their objective
value.
If this sounds like a familiar problem, that’s because it is. To take a relatively common
example, property management agencies have a tough time pricing new acquisitions, and
2
The function still throws a superclass Exception instead of a context-specific one - this should give the
reader an idea of code quality.
3
Set of all possible states after infinite time has passed.
50
CHAPTER 4. LEARNING 4.4. RESULT APPLICABILITY
most have only recently switched to learning approaches after traditional methods are
found to be inconsistent. A previous student from this very institution [70] found that
the spatial structure of housing market data can be exploited to subdivide and simplify
the regression task - with the caveat that Gaussian Processes are employed over linear
regression, this is almost the exact same conclusion I came to when dealing with IGE
data. Furthermore, a quick test of the Zoopla property API [74] reveals the same order of
magnitude amount of top-level variables are used to describe a house as are to describe
an in-game item in Path of Exile.
Thinking conceptually about the situation, it’s easy to see that if a larger, world-
wide property database existed the variance of the data is literally limited by human
architectural imagination. If one wants to fairly price a violin-shaped, furnished flat with
carpeted floors near a nuclear power plant one will be hard-pressed to find an example
to use as some form of reference. Any logical system to deal with this will follow a
closest-match procedure. The problem soon overextends into the field of knowledge
representation: there are few ways to express the abstract attractive (or lack thereof) of
living in a violin-shaped flat. Although this is clearly an extreme case used for the sake
of argument, the data becomes obscured and nested as dimensions are added to deal
with conditions not totally unlike the above, causing the learning task and the subsequent
objective pricing task to become harder and harder.
In general, a precise description of what markets (real or virtual) this software or
derived variations can be applied to is required:
• Items on sale have so many possible combinations that historical records are either
nonexistent or too sparse to be reliable.
• All sellers value their own items according to their own whim and no objective price
reference exists - in other words, prices are subjective across the entire market.
• Noise represents no more than 25% of the data [35], as feature engineering and
dimensionality reduction can very easily lead to reducing the breakdown point of
the system, more so if using the hashing trick.
• Normal supply and demand laws apply; there is no system that automatically or
otherwise balances shortage or surplus by injecting or removing items from the
environment.
If there are no transaction records, as is the case with Path of Exile, the system can
be trained on items which were (at some point in time) on sale instead. Although the
breakdown point is lowered somewhat by the complexity of the problems dealt with, if
enough data is present the software is capable of accurately pricing new items, negating
the influence of failing to check whether the items actually sold for the price they were
listed. It’s worth pointing out that this still holds even in constantly changing markets
where malicious intent is explicitly allowed, such as the one studied.
The extensive background research on feature hashing made it clear the technique
is well equipped to deal with all forms of hierachical data where the value of a parent
property is a function of its children values, even obscured JSON with millions of different
strings. Any JSON array encountered in a machine learning context, however complex
51
4.4. RESULT APPLICABILITY CHAPTER 4. LEARNING
and nested, can be eventually flattened to an n-hot vector by repeatedly applying the
principle in combination with context-specific reductions. Variable length arrays can be
translated to a set of fixed dimensions, infinitely varying strings can be reduced to finite
sets of nominals, and if they follow a normal distribution even entire JSON sub-objects
can be hashed into numeric values with little to no consequence on the final accuracy of
the classifier.
This makes for a very interesting conclusion to this section: housing markets, second-
hand sale mobile applications, the Amazon marketplace, all in-game economies simpler
than that of Path of Exile and indeed any economy that follows the rules set out above can
be analysed with minor tweaks by similar software. In essence, after training classifiers
on their data, price prediction may become possible where it previously wasn’t. Next
is what any trader dreams of: the ability to identify every under-priced item on the
market instantly. From there, further user-by-user data crunching would enable the
implementation of extra components like suggestion systems (see chapter 6 for more).
52
Chapter 5
Validation
An interesting article from Scientific American [3] proves the first dedicated virtual-world
economists started to appear in 2008. It has already been established that IGE analysis is
a field that will do nothing but grow over time, as traders from real world environments
realise the massive potential for profit found in the as-yet untapped markets. As economies
grow, in-game corporations and accompanying socioeconomic developments will start
to flourish, as has already been demonstrated with games like EVE, Entropia or Second
Life. Reports not entirely unlike this one are yet to be researched and written for many
simpler economies such as the Steam Community market, and I for one am confident we
will see more and more of them pop up over the next few years.
This chapter deals with how this particular software and any like it can be validated
effectively, and the survey methods employed to guarantee integrity and neutrality.
The contribution section (1.2) proves that there is a definite need for pricing software in
Path of Exile. If the survey had been run on the EVE Online or Entropia playerbases, it is
almost certain that the same conclusion would have been reached.
Once pricing software does exist, what is not so easy to prove is that it actually works
to a reasonable degree, that is, it accurately predicts the prices of completely new items
never encountered before. There is no objective reference for pricing in Path of Exile,
and indeed there is nothing remotely similar to that in most in-game economies and real
world community markets. In fact, there isn’t even a transaction record, and this makes
it very hard indeed to objectively prove that a price prediction program is effective, as
results cannot be compared to a publicly available ledger.
A supervisor for this project recommended that, given the novelty of the field, it would
be acceptable to provide validation by asking domain experts to judge the program’s
effectiveness. This section provides the results of the survey that ensued from that
comment.
Domain experts are an abstract concept in the world of virtual economies. How to go
about identifying the experienced player or trader? Looking at wealth is a terrible option,
as it would take days to come up with a representative estimate (many traders keep
53
5.1. COMMUNITY FIGURE SURVEY CHAPTER 5. VALIDATION
their value in goods and not currency). Eventually, it became obvious that if I decided to
contact the same top 1% that I had spoken to in the initial stages of the design process
there would be no way to prove that even they knew what they were talking about. So,
instead, I contacted the only players whose output would be believable even if supervisors
knew nothing about the game: content creators. Those who use the game as a platform to
earn their living, streaming it to massive audiences or posting videos to YouTube, figures
respected among the community and followed by tens of thousands of people.
A total of 13 community figures were contacted for validation purposes. They are all
known to have played the game for years, and have a combined following of 460,000
verified users as of the time of writing. Even accounting for over 30% overlap between
their communities, the amount of people that follow these 13 creators could barely fit
into 16 O2 Arenas. They all get dozens or hundreds of people asking them for price
checks every day due to their experience; if anyone should be trusted with pricing items,
it’s them. Out of these 13 creators, only 9 responded - fair enough, given the massive
scripting, recording and editing workload they are subjected to every day. All 9 replied
that the project seemed interesting and wanted to help - however, three of them stated
they were not good price checkers and decided not to contribute, volunteering their aid
in any other areas. This was a strong indication that pricing in PoE is even harder than
originally anticipated.
The remaining six were all asked to fill in a 25-question form [7]. Each question had
two parts: a high definition screenshot of one in-game item providing all information
necessary to price it and a text area for them to input how much they thought the item
was worth in any currency they saw fit. The items were selected to provide the highest
variation possible between them and thus have a representative sample of the population.
A key reason for the achieved accuracy threshold is the fact that over 95% of all items
ever priced using this method in the future will be worth less than a few cents, as valuable
combinations are extremely rare. Since the objective was to test the maximum possible
range of inputs, items fell into a large price range, from zero currency units to tens of
thousands of units. The output for the same set of 25 items was calculated before the
form was sent out using the method described in section 5.2, and no person was aware of
the price set by the program to avoid unconscious bias. Business contact emails for all
six people kind enough to fill in the survey can be found in the final project archive, and
although they may not respond immediately they can all confirm the results below are
legitimate.
54
CHAPTER 5. VALIDATION 5.1. COMMUNITY FIGURE SURVEY
Figure 5.1: Validation results: program output plotted against community estimates.
The X axis represents prices as specified in the form, the Y axis represents prices as
produced by my software. Most experts answered in the form of a short range, with some
notable exceptions when they were unsure of a more specific value of the item. Note
where there was only one price specified by the expert for an item it is considered both the
beginning and end of the range for that item for that person. Each numbered cross on the
graph represents one item, of course - the red dotted line represents correlation between
the software’s prediction and the prices from the form. The start of each horizontal solid
bar is the median of the set of lower bounds for each item aggregated over all experts,
and the end of each horizontal solid bar is the median of the set of higher bounds for
each item aggregated over all experts. The vertical solid bars are ranges predicted by the
software. Where there was an even number of lower or upper bounds the average of the
two middle values was taken.
There is clearly good correlation between the two prices, with 13 out of 25 (52%) of
the ratios of program price to player estimate falling within the range 1/1.5 to 1.3. Of the
remaining 12, 5 lie in the lower left corner of the plot (in other words, they are very low
value items with very small absolute price differences), so in practice there is reasonable
55
5.2. CLIPBOARD INPUT CHAPTER 5. VALIDATION
agreement between program and players for 18 out of 25 items, i.e. 72%. The remaining
7 points are a mixture of underestimates and overestimates by the program. Of these 7
items, 3 are very expensive (note item 1 is not even visible on the graph), and it is almost
certainly the case that the program fails to accurately price them because of the artificial
15000 unit price cap imposed to improve learning, which limits training data available for
very high-end items.
Path of Exile allows players to copy item data from within the game to an external text
environment with the typical copy shortcut Ctrl + C. This is how items were passed to
the software and prices were generated for the items above, and indeed it is also how
poe.trade and other sites import items for search or pricing purposes. Unfortunately, the
item data is in a far-from-ideal format, seemingly intentionally designed to obstruct the
pricing process as much as possible. Let’s take an example:
Rarity: Rare
Apocalypse Shroud
Vaal Regalia
--------
Quality: +20% (augmented)
Energy Shield: 778 (augmented)
--------
Requirements:
Level: 68
Int: 194 (unmet)
--------
Sockets: B-B-B-B-B-B
--------
Item Level: 85
--------
56% increased Energy Shield
+145 to maximum Energy Shield
+48% to Fire Resistance
+48% to Cold Resistance
+48% to Lightning Resistance
17% increased Stun and Block Recovery
67% increased Energy Shield
This is a verbatim copy and paste from the game into the LATEX editor - the format
really is that simple. Splitting the data into chunks delimited by the 8-dash lines gives us
a modicum of control, but the number of chunks is not fixed and there is no definite way
to know which is which while parsing. Some tricks have been employed to identify them,
but there are some choices such as between implicit and explicit mods which are still not
completely deterministic.
56
CHAPTER 5. VALIDATION 5.2. CLIPBOARD INPUT
• The first chunk is always the rarity, name and base of the item - however, if the item
has no defined name (as is common with items which are not rare) the second line
just disappears and becomes the base. For this example, the item is of type rare
so the software can in fact price it, the name is ignored and the base is set to Vaal
Regalia.
• The quality modifier must be parsed from the following chunk, which is roughly
equivalent to the JSON properties array mentioned in the raw data section 3.1.1.
Several regular expressions are used to isolate the number, which is 20 in this case.
The second line in this chunk is either nonexistent or represents one of the implicit
properties on the item. Thankfully the rest are base-dependent.
• The next block is the item’s requirements and whether the player who copied the
item meets them. They can be safely ignored for pricing purposes, and are also
base-dependent.
• If the item has sockets, they are in the following chunk. If not, the chunk disappears
to make way for the one below. Each dash represents one link - in this case, all
six sockets are linked, making the item quite valuable. In addition, all sockets are
colour-coded, with the letter B representing the colour Blue.
• The item level of the item can be found in the chunk immediately before the first
chunk containing modifiers (in this case it is 85).
The reader may have noticed from the raw JSON fields or examples that there is no
significant difference in the format of modifiers regardless of their type. For each chunk,
the following regular expression is used to check each string to see if it matches the
format expected of a mod:
(?!.*:.*)(?!.*augmented.*).*[+-]?\d+(\.\d+)?\%?.+
Then, the number of strings that look like they might be a mod is counted. Taking n to
be the total number of lines in the chunk, if the count of lines that match the expression
above is larger than max(1, 3/4 ∗n) the chunk is taken to be the explicit mods, and otherwise
a further regular expression is applied to differentiate between implicit and enchantment.
57
5.2. CLIPBOARD INPUT CHAPTER 5. VALIDATION
Eventually, a JSON object similar to the clean ElasticSearch data described in 3.2 can
be generated. If the data for a particular field is missing, the field is set to a reasonable
default, but in general all fields can somehow be parsed from the clipboard string.
The type field of the JSON object is stored to identify which of the 52 serialised linear
regression models should be loaded into memory. Meanwhile, the JSON itself is converted
to CSV and then to ARFF using the same procedure as is used for items coming from
the database. This ARFF is then written (together with its 700 line header) to a file
on the hard drive, then immediately retrieved as a WEKA instance. There is no way to
simplify this process and no shortcut in this library. The instance is then classified by the
linear regressor and a short ten-unit leeway range is added on either side of the resulting
prediction.
The result can be displayed either in the Java console or in a small and basic JavaFX
[18] user interface. The UI allows for pricing several items of different type sequentially,
reloading the classifier in the background. It is not designed to look pretty, it is designed to
function, which is why it does not have its own section in this report. If a web application
spin off of this project is eventually coded, it will use beautiful chart libraries, but given
the proof-of-concept nature of the software the current UI must suffice.
58
Chapter 6
Further Work
I had never touched machine learning before this project. The pricing problem for Path
of Exile is not an ideal way to get into the field, and I am confident if I had some more
knowledge about the topic before starting I would not have tripped up so many times. The
software is far from perfect, pricing only 72% of items reasonably, and is also quite slow.
It can be so much more, and with any luck it will eventually be shaped into something that
can impress the average videogame player and stock market trader alike. This chapter
deals with future improvements to the entire system, from core to minutiae.
As mentioned in the introductory paragraph of this chapter, the Java code which runs the
entire system is slower than it should be.
Static methods are abundant in the code already, but there are many more which
remain as object instance methods. A number of benefits results from making helper
methods static, as the compiler can then tell the Java virtual machine to use the same
copy of the method every time it is called.
File input and output operations are abundant in the code, as a total of 520 data files
are actively used in the final code (only a small fraction of which are included in the
final project archive). They are slow, as they are bottlenecked by drive seek, read and
write speed, and performance can definitely be improved by using either Java streams or
directly pre-fetching and caching resources.
There are a number of design patterns which are underused in the project, particularly
the factory and singleton ones. In addition to this quite a few of the hundreds of total
classes can be rewritten to inherit from each other or should implement an interface.
Finally, after all of the above has been fixed one of the most performance-critical
improvements is parallelisation. Not only can format parsing and conversion be sped
up massively (for example, assigning one core to translate JSON to CSV and another to
translate CSV to ARFF), but Java’s concurrency package would also allow for database
downloads, API parsing and many more components to be sped up significantly.
59
CHAPTER 6. FURTHER WORK
Currently only one of the nine categories in Path of Exile is supported (see 3.2.1). All
items in the remaining categories have a low number of possible combinations and are
very easy to price accurately based on supply and demand only.
Eventually, the program will support all possible items within the game with no
exceptions, and it will be able to identify when any of them has an incorrect price, be
it too high or too low. This was never intended for the final project as presented to the
College.
ElasticSearch format
Soon the academic Azure credit which pays for the machine where ElasticSearch is hosted
will run out and the server will have to be transferred to a cheaper service.
This provides the perfect opportunity to re-index the data for a seventh time, adding
some properties which do not impact the price but do affect quality of life when working
with the data. For example, there is currently no way to search by requirement because
the indexer was made as fast as possible and to require as few disk writes as possible.
Even so, the project will still use ElasticSearch as its underlying document storage
system, as the Lucene engine is capable of beating the best speeds achieved by the
caching service at poe.trade, the leading market indexer for Path of Exile at the moment.
Currency exchange rates are currently calculated by parsing trade websites and finding
the lowest possible amount of one currency anyone is willing to trade for one unit of
another. Though this is a very effective heuristic and saves a lot of processing, the ideal
solution would be to track all currency and find the minimum in my own data.
In addition, the current currency exchange JSON database is set to update only when
its handler is called, but it should update on regular, possibly daily time intervals. The
data in this work are still quite accurate, as variations are rare in the standard leagues.
Tensorflow
After evaluation and over summer of 2017 this project will be rewritten to use the
Tensorflow library [49], a Python collection of machine learning collection algorithms
written entirely by Google. The library wraps extremely efficient device-optimised C and
C++ code to provide excellent performance and great usability at the same time.
WEKA is simply not up to modern standards in both of these areas, and contains a
lot of code which is either broken or very poorly written and does not take advantage of
Java’s new features.
Tensorflow has a Java API, but since it is in its infancy there is always the option to
write a Python wrapper instead.
The one drawback to this library is its lack of variety - it implements far fewer classifiers
60
CHAPTER 6. FURTHER WORK
and regressors than WEKA. However, since this project is concerned mainly with linear
regression and neural networks this is not too much of an issue.
The training set for this project is riddled with outliers. The importance of clean data
cannot be overestimated, as it is guaranteed that better training data will lead to better
classification accuracy. Algorithmic procedures aside, if just one of the community figures
mentioned in the validation section prices 1000 items of the same type over a few weeks
in his or her own time, the results would probably be shockingly good for that type.
However, given the lack of free time of people that create content for a living versus the
abundance of types in this context, it is a much better option to improve the training
set by looking at items which are guaranteed to have been sold at a certain price. That
is, if the item disappears from a stash tab and reappears in another owned by someone
else, it is marked as sold - of course, this requires some very picky hashing similar to the
technique used for indexing documents into ElasticSearch.
Current normalisation procedures are based on reducing variable ranges to a value
between 0 and 1. In contrast, the standard for linear regression is centering the variables
with mean 0, and this is yet another improvement which could be applied with little
coding effort to the software.
Also, a large portion of the more expensive items within the game (those with a value
of 150 dollars or more) cannot be priced correctly by the software. This could be fixed by
trawling the PoE forums with a library like JSoup in search of so called ‘mirror’ items1
(items rolled with six tier 1 perfect modifiers with perfect synergies), which are all priced
correctly by their extremely wealthy owners, and training a separate model to deal with
similar high-end items when encountered.
On a separate note, it has already been shown in two separate graphs that the limited
neural network tests on the data produce marginally more accurate predicted prices than
linear regression. After significant time investments, an effective sampling algorithm will
arise that can be used to reduce the size of current training sets by around 95% without
reducing accuracy. Then, around 84 uninterrupted hours of CPU time would be required
to train the new multilayer perceptrons (in WEKA). The software can already place 7 out
of 10 items on average within a reasonable range of their real price, so the combination
of these models and heavier preprocessing (leading to an improved training set) would
almost certainly bring the accuracy of the classifier up to at least 85%.
PCA was already used to identify the principal components of the raw JSON data in
the initial stages of this work. Even though the data has been greatly reduced already
using the magic of feature hashing, further dimensionality reduction can be achieved by
running a principal components algorithm again, this time on the 64-dimension one-hot
vectors, to identify which indexes have the most impact. This would reduce the size of
1
The name arises from their desirability: many other players pay an expensive fee to be able to duplicate
or mirror their item and own or use a copy.
61
CHAPTER 6. FURTHER WORK
the data and ease the training of models such as multilayer perceptrons. The same is
not recommended, however, for the explicit modifier array, as the number of possible
strings is just too large and touching the n-hot vector with PCA will result in guaranteed
information loss.
Recommendation system
Imagine playing any role-playing game and a notification suddenly popping up alerting
that a gear upgrade has just come on sale for much less than what you would normally pay
for it. Imagine browsing a housing website and getting the same kind of alert, only there
is a five thousand pound saving to benefit from. Once an adaptation to the main code
routines is written, any market at all that meets the characteristics outlined in 4.4 can be
analysed, and there is no reason further steps should not be taken to save user data and
trend information to predict what they will want next based on items they already have or
have been browsing, just like Amazon’s regular service does.
A recommendation system would be especially useful for those new to the economy
being analysed - if it was a virtual one, the game developers would benefit just as much
as the newbie. An interesting example of this is Path of Exile itself, which has been
repeatedly toted by the developers and players alike as an environment that requires too
much effort to really understand [104].
Testing
Each minute component of the preprocessing pipeline was tested to exhaustion, line by
line, to make absolutely sure that the only things that could stop it were the network
disconnecting (a common occurrence, alas) or an HTTP 503 response.
The same cannot be said for the rest of the software, which is not modular and thus
is harder to test. In future, a host of tests should and will be written to probe the
functionality behind the learning algorithms and the user interface.
Front end
The front-end leaves nothing to the imagination. It is a basic, two-pane designed to serve
as a quick way of testing the regression employed in this work. In short, the UI was not
the point - solving the pricing problem was.
Eventually, the front-end will be completely redesigned and ported to a dedicated
website running on a Java back-end, where graphics libraries and other perks will ensure
the most beautiful display possible for all the statistical data generated.
The front-end will be able to price entire collections at once apart from isolated items,
and will also provide the option to run a scan on the entirety of the current market
snapshot to identify relevant flipping opportunities.
62
Chapter 7
Conclusions
Let’s summarise the final pipeline: PoE’s raw, nested market data is streamed from the
public stash tab API, heavily filtered and transformed to simple, almost flat JSON records.
These records are all indexed into an Azure ElasticSearch server as fast as the river
produces them. The records can be polled on demand using an all-hits query, optionally
taking just those items whose price lies within three median absolute deviations of the
median. A combination of feature hashing and n-hot encoding is used on the collection of
all records to procedurally generate 52 CSV files, one for each type of item being analysed.
The CSV files are efficiently translated to ARFF using Java’s buffered IO, then passed to
the WEKA machine learning library, which trains 52 univariate linear regression models.
The models are serialised and stored for further use as project resources. Then, any new
item which the user would like to price is pasted from the system clipboard into a basic
UI, converted into JSON, then CSV, then ARFF and finally into a WEKA Instance object,
which is finally passed to the adequate classifier model and priced.
After 7000 lines of Java code, 1.5 million lines of data-mined JSON and seven different
classifiers producing over 15 GB worth of models, we’ve reached a point were the software
is capable of pricing roughly 72% of all 1017 items possible in the Path of Exile economy.
As one of the first algorithms in the public domain to ever achieve even reasonable pricing
accuracy, reaching the hands of even a small fraction of PoE’s 20 million players would
almost certainly make its use widespread.
This report introduces a new way of looking at videogame economies for the uninitiated
and experienced alike, and provides an entry point for further research on the topic for
anyone who is interested in trading or machine learning. The JSON analysis and feature
hashing techniques described are applicable to many different datasets, and it will be
interesting to see how many of the markets of other IGEs and economies of similar
complexity in the real world can be analysed profitably.
Of course, as already mentioned in the further work section that there is still much to
be done, but the software will only improve from now on in terms of accuracy, usability
and performance alike. To finally conclude this 60-page report on a topic which didn’t
even really exist until the change of the millennium, I’d like to remind the reader that the
original intention was to design and code a proof of concept of what is really possible in
the vast world of videogame economies, and I’m very excited to see what comes next.
63
References
64
REFERENCES REFERENCES
[15] Dwaine Clarke et al. “Incremental multiset hash functions and their application
to memory integrity checking”. In: International conference on the theory and
application of cryptology and information security. Springer. 2003, pp. 188–207.
[16] John G. Cleary and Leonard E. Trigg. “K*: An Instance-based Learner Using
an Entropic Distance Measure”. In: 12th International Conference on Machine
Learning. 1995, pp. 108–114.
[17] William S. Cleveland. “LOWESS: A program for smoothing scatterplots by robust
locally weighted regression”. In: The American Statistician 35.1 (1981), pp. 54–54.
[18] Oracle Corporation. Java 8: JavaFX. 2016. URL: http : / / docs . oracle . com /
javase/8/javase-clienttechnologies.htm.
[19] Bryan E. Denham. “Multinomial Logistic Regression”. In: Categorical Statistics
for Communication Research (), pp. 153–170.
[20] University of Waikato Department of Computer Science. Attribute-Relation File
Format (ARFF). 2002. URL: http://www.cs.waikato.ac.nz/ml/weka/arff.
html.
[21] University of Waikato Department of Computer Science. Waikato Environment for
Knowledge Analysis (WEKA). 2002. URL: http://www.cs.waikato.ac.nz/ml/
weka.
[22] University of Waikato Department of Computer Science. Weka - all classifiers.
2002. URL: http : / / weka . sourceforge . net / doc . dev / weka / classifiers /
Classifier.html.
[23] Elastic. Open Source Search & Analytics: ElasticSearch. URL: https : / / www .
elastic.co.
[24] ExileTrade - An Advanced Search Engine. 2016. URL: https : / / github . com /
exiletrade/exiletrade.
[25] Internet Engineering Task Force. JSON Schema: A Media Type for Describing
JSON Documents. 2016. URL: http://json-schema.org/latest/json-schema-
core.html.
[26] George Forman and Evan Kirshenbaum. “Extremely fast text feature extraction
for classification and indexing”. In: Proceedings of the 17th ACM conference on
Information and knowledge management. ACM. 2008, pp. 1221–1230.
[27] Apache Software Foundation. Apache Kafka, a distributed streaming platform.
2016. URL: https://kafka.apache.org.
[28] Apache Software Foundation. Apache Lucene. 2011. URL: https : / / lucene .
apache.org.
[29] Apache Software Foundation. Apache Mahout. 2017. URL: http : / / mahout .
apache.org.
[30] Apache Software Foundation. MurmurHash docs - Apache Mahout Math. 2008.
URL: http : / / mahout . apache . org / docs / 0 . 13 . 1 - SNAPSHOT / javadocs / org /
apache/mahout/math/MurmurHash.html.
65
REFERENCES REFERENCES
[31] Dayne Freitag. “Machine learning for information extraction in informal domains”.
In: Machine learning 39.2 (2000), pp. 169–202.
[32] Yoav Freund and Robert E. Schapire. “A decision-theoretic generalization of
on-line learning and an application to boosting”. In: European conference on
computational learning theory. Springer. 1995, pp. 23–37.
[33] Jerome H. Friedman. “Multivariate adaptive regression splines”. In: The annals of
statistics (1991), pp. 1–67.
[34] Jerome H Friedman. “Stochastic gradient boosting”. In: Computational Statistics
& Data Analysis 38.4 (2002), pp. 367–378.
[35] Ahmed M. Gad and Maha E. Qura. “Regression Estimation in the Presence of Out-
liers: A Comparative Study”. In: International Journal of Probability and Statistics
5.3 (2016), pp. 65–72.
[36] Grinding Gear Games. Official Path of Exile Website. 2010. URL: https://www.
pathofexile.com/game.
[37] Grinding Gear Games. Official Path of Exile Wiki. 2013. URL: http://pathofexile.
gamepedia.com/Path_of_Exile_Wiki.
[38] Grinding Gear Games. Path of Exile FAQ. 2013. URL: https://www.pathofexile.
com/faq#q6.
[39] Grinding Gear Games. Path of Exile Public Stash Tab API. 2016. URL: http :
//www.pathofexile.com/api/public-stash-tabs.
[40] Paul Geladi and Bruce R Kowalski. “Partial least-squares regression: a tutorial”.
In: Analytica chimica acta 185 (1986), pp. 1–17.
[41] Lise Getoor. Introduction to statistical relational learning. MIT press, 2007.
[42] Rowena Davis (The Guardian). Welcome to the new gold mines. 2009. URL: https:
//www.theguardian.com/technology/2009/mar/05/virtual-world-china.
[43] David Harris and Sarah Harris. Digital design and computer architecture. Elsevier,
2012.
[44] Zellig S. Harris. “Distributional structure”. In: Word 10.2-3 (1954), pp. 146–162.
[45] Jonathan Hedley. JSoup Java HTML DOM parser. 2009. URL: https://jsoup.org.
[46] Gordon Hughes. “On the mean accuracy of statistical pattern recognizers”. In:
IEEE transactions on information theory 14.1 (1968), pp. 55–63.
[47] Laurent Hyafil and Ronald L. Rivest. “Constructing optimal binary decision trees
is NP-complete”. In: Information processing letters 5.1 (1976), pp. 15–17.
[48] ImagineGamesNetwork. Most Expensive Virtual Item Sold. 2010. URL: http :
//www.ign.com/articles/2010/01/04/most-expensive-virtual-item-sold.
[49] Google Inc. Google TensorFlow. 2017. URL: https://www.tensorflow.org.
[50] Meteor Development Group Inc. Meteor. 2017. URL: https://www.meteor.com.
[51] MongoDB Inc. MongoDB Architecture Guide (White Paper). 2016. URL: https:
//webassets.mongodb.com/_com_assets/collateral/MongoDB_Architecture_
Guide.pdf.
66
REFERENCES REFERENCES
[52] OPSkins Group Inc. OPSkins Marketplace - Souvenir AWP Dragon Lore, Factory
New condition. 2017. URL: https : / / opskins . com / ?loc = shop _ search & app =
730 _ 2&search _ item=souvenir%20awp%20dragon%20lore&sort=f&trans _ id=
102058eba1e68f904191262fb6f83f&aff_id=2&marketing_source=Adwords&kw=
souvenir%20awp%20dragon%20lore&campid=662499799&adgrp=37373983823&
mt=p&ap=1t1.
[53] Business Insider. Only Six Percent Make the Cut as Professional Traders. 2011.
URL: http://www.businessinsider.com/what-percentage-of-traders-make-
it-2011-6.
[54] ECMA International. JSON Data Interchange Format ECMA-404 Standard. 2013.
URL: http : / / www . ecma - international . org / publications / files / ECMA -
ST/ECMA-404.pdf.
[55] Norbert Jankowski and Marek Grochowski. “Comparison of instance selection
algorithms II. Results and comments”. In: International Conference on Artificial
Intelligence and Soft Computing (2004).
[56] Ian Jolliffe. Principal component analysis. Wiley Online Library, 2002.
[57] John Kenney F. Mathematics Of Statistics. Van Nostrand Reinhold Company, 1939.
Chap. 15.
[58] Youngjoong Ko. “A study of term weighting schemes using class information
for text classification”. In: Proceedings of the 35th international ACM SIGIR
conference on Research and development in information retrieval. ACM. 2012,
pp. 1029–1030.
[59] S. B. Kotsiantis, D. Kanellopoulos, and P. E. Pintelas. “Data preprocessing for
Supervised Learning”. In: International Journal of Computer Science 1.2 (2006).
ISSN: 1306-4428.
[60] E. Kreyszig. Advanced Engineering Mathematics. Wiley Inc., 1962, pp. 880–880.
[61] Rasmus K. L. poe.ninja. 2015. URL: http://poe.ninja.
[62] Kamakshi Lakshminarayan, Steven A Harp, and Tariq Samad. “Imputation of
missing data in industrial databases”. In: Applied intelligence 11.3 (1999), pp. 259–
275.
[63] Christophe Leys et al. “Detecting outliers: Do not use standard deviation around
the mean, use absolute deviation around the median”. In: Journal of Experimental
Social Psychology 49.4 (2013), pp. 764–766.
[64] Shaul Markovitch and Dan Rosenstein. “Feature generation using general con-
structor functions”. In: Machine Learning 49.1 (2002), pp. 59–98.
[65] Wolfram MathWorld. Zipf’s Law for the English Language. URL: http://mathworld.
wolfram.com/ZipfsLaw.html.
[66] Business Insider Matt Turner. The Robot Revolution is coming for Wall Street
traders. 2015. URL: http://www.businessinsider.com/robots- to- replace-
wall-street-traders-2015-8.
67
REFERENCES REFERENCES
[67] Andrew McCallum, Kamal Nigam, et al. “A comparison of event models for naive
bayes text classification”. In: AAAI-98 workshop on learning for text categorization.
Vol. 752. Madison, WI. 1998, pp. 41–48.
[68] John Neter et al. Applied linear statistical models. Vol. 4. Irwin Chicago, 1996.
[69] Consumer News and Business Channel. Bitcoin miners face fight for survival as
new supply halves. 2016. URL: http://www.cnbc.com/2016/07/09/bitcoin-
miners-face-fight-for-survival-as-new-supply-halves.html.
[70] Aaron Ng and Marc Deisenroth. “Machine learning for a london housing price
prediction mobile application”. In: (2015).
[71] Florian Nigsch et al. “Melting point prediction employing k-nearest neighbor algo-
rithms and genetic parameter optimization”. In: Journal of chemical information
and modeling 46.6 (2006), pp. 2412–2422.
[72] K Pearson. “On lines and planes of closest fit to systems of point in space”. In:
Philosophical Magazine 2.11 (1901), pp. 559–572.
[73] Alan Debonneville & Brock Pierce. International Gaming Entertainment, Ltd. 2001.
URL: https://www.bloomberg.com/research/stocks/private/snapshot.asp?
privcapId=8623083.
[74] ZPG Plc. Zoopla Property API - Zoopla developer network. 2017. URL: https:
//developer.zoopla.co.uk.
[75] PoEPrices. Path of Exile Item Price Check. 2016. URL: http://poeprices.info.
[76] PyPoE - Collection of Tools for Path of Exile. 2015. URL: https://github.com/
OmegaK2/PyPoE.
[77] J Ross Quinlan. C4.5: programs for machine learning. Elsevier, 2014.
[78] Ross Quinlan. C4.5: Programs for Machine Learning. San Mateo, CA: Morgan
Kaufmann Publishers, 1993.
[79] Tilmann Rabl et al. “Solving big data challenges for enterprise application per-
formance management”. In: Proceedings of the VLDB Endowment 5.12 (2012),
pp. 1724–1735.
[80] RePoE - Data Repository for Path of Exile developers. 2015. URL: https://github.
com/brather1ng/RePoE.
[81] Vicente de Rivera et al. ExileTrade - An Advanced Search Engine. 2016. URL:
https://github.com/exiletrade/exiletrade.
[82] David M Rocke and David L Woodruff. “Identification of outliers in multivariate
data”. In: Journal of the American Statistical Association 91.435 (1996), pp. 1047–
1061.
[83] Lior Rokach and Oded Maimon. Data mining with decision trees: theory and
applications. World scientific, 2014.
[84] Ryan A. Rossi et al. “Transforming graph data for statistical relational learning”.
In: Journal of Artificial Intelligence Research 45.1 (2012), pp. 363–441.
68
REFERENCES REFERENCES
[85] Peter J. Rousseeuw and Christophe Croux. “Alternatives to the median absolute
deviation”. In: Journal of the American Statistical association 88.424 (1993),
pp. 1273–1283.
[86] Peter J. Rousseeuw and Annick M. Leroy. Robust regression and outlier detection.
1987.
[87] New Scientist. Sales in virtual goods top $100 million. 2004. URL: https : / /
www.newscientist.com/article/dn6601-sales-in-virtual-goods-top-100-
million.
[88] Y. Shafranovich. Common Format and MIME Type for Comma-Separated Values
(CSV) Files. 2005. URL: http://www.ietf.org/rfc/rfc4180.txt#page-1.
[89] S.K. Shevade et al. “Improvements to the SMO Algorithm for SVM Regression”.
In: IEEE Transactions on Neural Networks. 1999.
[90] A.J. Smola and B. Schoelkopf. A tutorial on support vector regression. Tech. rep.
NeuroCOLT2 Technical Report NC2-TR-1998-030. 1998.
[91] Yunsheng Song et al. “An efficient instance selection algorithm for k nearest
neighbor regression”. In: Neurocomputing 251 (2017), pp. 26–34.
[92] SQL Schema: PoE-Stash-Indexer-NG. 2016. URL: https://github.com/licoffe/
POE-Stash-indexer-NG/blob/master/schema.sql.
[93] Rohini K. Srihari et al. “InfoXtract: A customizable intermediate level information
extraction engine”. In: Natural Language Engineering 14.1 (2008), pp. 33–69.
[94] Stashi.org. 2017. URL: http://stashi.org.
[95] Mervyn Stone and Rodney J. Brooks. “Continuum regression: cross-validated
sequentially constructed prediction embracing ordinary least squares, partial
least squares and principal components regression”. In: Journal of the Royal
Statistical Society. Series B (Methodological) (1990), pp. 237–269.
[96] The Jackson Project. 2013. URL: https://github.com/FasterXML/jackson.
[97] John W. Tukey. “Exploratory data analysis”. In: (1977).
[98] The Association for UK Interactive Entertainment. The Games Inndustry in Num-
bers. 2017. URL: https://ukie.org.uk/research.
[99] Michael Walpole. Taxing Virtual Profits. University of New South Wales, 2008.
[100] Kilian Weinberger et al. “Feature hashing for large scale multitask learning”. In:
Proceedings of the 26th Annual International Conference on Machine Learning.
ACM. 2009, pp. 1113–1120.
[101] Joshua Xu and Wayne Xun. Video Game Machine Learning. 2016. URL: http :
//wayne-x.github.io/VideoGameML/full.
[102] Harry Zhang. “The optimality of naive Bayes”. In: AA 1.2 (2004), p. 3.
[103] Ilya Zhuravlev. PoE Goods. 2014. URL: http://poe.trade.
[104] ZiggyD. Path of Exile is Getting too Complex. 2017. URL: https://www.youtube.
com/watch?v=lm1Fo9J0ffE.
69
Appendix A
• explicitMods: Array of explicit modifiers. By far the most important field on this
list, the explicit mods have the largest impact on the item’s price and are often the
first thing traders look at when pricing an item.
• craftedMods: Array of crafted modifiers. One of the many ways to add value to
an item is to manually add one or more desired mods using an in-game mechanic
known as ‘crafting’ - however, since they can be removed and re-added with relative
ease they are ignored in this work.
• typeLine: Base of the item. A base in Path of Exile is the most basic version of the
item considered - no explicit mods, no sockets, just implicit properties. Unfortunately,
bases do have a significant impact on value, as they determine how high the implicit
properties of an item (see properties below) can go. Fifty of the final dimensions
70
APPENDIX A. RAW DATA JSON
in the final training data are entirely dedicated to this field, and this is only after
feature hashing has been applied.
• ilvl: Item level, the determining factor behind the tier of mods available to the
item, both for initial mod generation and further transformations. This number
cannot be changed in-game in any way.
• league: There are four main leagues in Path of Exile, as outlined in section 2.2.1.
The field represents which league the item belongs to.
• note: Optional price string for the item. A massive amount of filters and extra
processing has to be applied to this string, not only to run the usual user input
checks but to actually get the price of the item in whatever currency the user
chooses and convert it to the internal currency used by the software.
• properties: Array of implicit properties of the item. Most properties are base-
dependent and relate to offensive or defensive stats, but some, such as the quality
modifier (that increases the upper bound of the aforementioned stats), have to be
manually identified and parsed into a more efficient format.
• sockets: Sockets are used in-game to hold gems. Gems are PoE’s way of repre-
senting player abilities, such as ‘shoot some flames’ or ‘make a small earthquake
happen’. These two examples could be what is known as ‘active’ gems - ‘support’
gems, on the other hand, provide benefits to the actives, such as ‘active gem slays
enemies instantly when they fall below 10% health’.’ Gems are further subdivided
into three colours, red, green and blue, each associated to one of the character’s
three attributes (strength, dexterity and intelligence respectively). Each socket can
hold exactly one gem, if and only if the socket is the same colour as the gem1 . White
sockets can hold a gem of any colour, but the chance of hitting more than one on any
item when applying corruption (see corrupted) is quite low. Sockets can be linked,
and support gems only apply their benefits to an active gem if they are linked to it.
The link can be direct (one hop) or indirect (more than one hop to reach the active
gem). A maximum of six sockets can be reached on large items, and items with
six linked sockets are generally quite valuable, as the chances of each one being
linked to the previous chain decrease exponentially. There are further nuances, but
unimportant in this context.
• id: Internal item ID. This would be an extremely useful quality-of-life improvement
if the item’s ID did not change when sold. This completely negates item tracking
without some very careful hashing.
• inventoryId: Internal pointer to the tab’s simplified integer ID within the player’s
overall inventory.
1
Two white gems exist which can be placed in a socket of any colour.
71
APPENDIX A. RAW DATA JSON
• name: Name of the item, often plagued by internationalisation helper strings. Safely
ignored, as it has no impact on the price.
• icon: Link to PoE’s web content distribution network, specifically to an image of the
item. This icon is sometimes generated on the spot.
• talismanTier: If the item is an amulet of type Talisman (much more valuable than
regular amulets in most cases), the tier of the talisman.
• stackSize: If the item is stackable (see frameType), the current size of the stack in
units.
• maxStackSize: If the item is stackable (see frameType), the maximum size of the
stack in units, one of the most obvious cases of functional dependency.
• flavourText: Lore text with no impact on the final price, one of several fields
seemingly added to the API with the only objective of increasing file size and
processing time.
• support: If the item is a gem (see frameType), true if the item is a support gem.
• colour: If the item is a gem (see frameType), colour of the gem (see sockets).
• socket: If the item is a gem (see frameType), numeric ID of the socket the gem is
placed in within its container item (see socketedItems).
• artFilename: If the item is a divination card (see frameType), pointer to the internal
ID used to display the item in game.
• identified: True if the item is identified. It is rare for unidentified items to hold
value, as explicit mods (see below), the most important features of any item, are
generated upon identification. Items are dropped as loot and otherwise generated
in this default, unidentified state, with few exceptions. The player must then use an
item of currency to identify the item.
72
APPENDIX A. RAW DATA JSON
• corrupted: True if the item is corrupted. The semantics are hard to explain in
a few lines: corrupted items may have a more valuable implicit modifier (see
implicitMods below) or white socket (see sockets below), but may not be altered
further in any way without very significant currency investment, and even then in a
very restricted manner. Corrupting an item is a popular gamble among PoE players.
2
A default stash tab is a two-dimensional array of 144 units (12 on a side). The largest items occupy 8
units and the smallest items occupy 1 unit.
73
Appendix B
A list of 17 selected currencies out of the 24 typically used for trading can be found below.
This should make the exponential nature of hypothetical item transformation trees much
clearer.
• Vaal Orb: Unpredictably change the item (may add exclusive modifiers).
74
APPENDIX B. ITEM TRANSFORMATION CURRENCIES
75