Rarity on PopRank

5 min readDec 9, 2021

PopRank started as an NFT aesthetics ranking tool, but we have a grand vision. We will become your one-stop shop to find NFTs you love. While we continue to build out aesthetics ranking features, rarity is and always will be an important factor in discovering your forever NFTs, which is why we’re thrilled to announce that rarity rankings have now been added to PopRank.

We have so much planned for the future (Discord bots, personalised NFT recommendations, deep data dives, and more), which is why we’re so excited to release this next step in achieving our grand vision.

We want our rarity calculations to be as transparent as possible, hence this article. This is the first of multiple rarity calculations that we’ll be offering, as during the course of our research, we realised that there is no one “perfect” approach to rarity, as every collection treats traits/metadata differently.

Our Rarity Calculation

Note: Although there are code snippets below, we aim for it to be accessible for everyone, whether technically inclined or not.

Our first rarity calculation is the “Sum of Traits” rarity calculation.

It started as the following: The “rating” of an individual trait is equal to the number of NFTs in the collection divided by the number of NFTs that have that specific trait value. In pseudocode, it looks like:

rating(num_nfts_with_trait, collection_size) = collection_size / num_nfts_with_trait

Note that we also add the number of traits as a meta-trait, such that a BAYC ape with 4 traits (4T ape) would have a fifth trait, “4 Traits”: 254, added to it, indicating that there are 254 apes with 4 traits. The reasoning behind this is that the number of traits itself played a sizeable role in determining an NFT’s rarity. NFT rarity should be higher if the NFT is one of the few to have fewer traits.

This was a satisfactory initial implementation, but it had its issues as can be seen below.

Looks alright, but not amazing. The very-rare traits, such as gold-fur apes, should be rated higher. It seems like the “Bored Unshaven Pizza” and “Bored Unshaven Dagger” mouths are dominating.

Let’s look at a 4T ape:

Shoutout @_etash for allowing us to feature his 4T ape

Oh no, a 4T ape is apparently rarity rank #9026:

Compared to the rank #1:

The rank #1 ape has 2 rare traits that contribute highly to its rating, but we can see that the trait count isn’t counting for nearly enough. Additionally, based on the lack of “Blue Beams” eyes (trait count: 49) and “Solid Gold” fur (trait count: 46) apes in the top 18 above, other, slightly-less-but-still-rare traits aren’t contributing enough.

10000/46 217, which is the rating of a Solid Gold Fur ape (0.46%), which means it is only about 60% as impactful as the 10000/28 “Bored Unshaven Dagger” trait.

So we have two changes to make. We want to:

  • Reduce the rating difference between similarly rare traits
  • Have the meta Trait Count be more impactful
  1. Reduce the rating difference between similarly rare traits

Our initial trait rarity calculation can be seen as the following inverse relation:

where 10,000 is the collection size for BAYC, “x” is the trait count for a given trait, and “f1(x)” is the rating. In order to “smooth” this relation, we can square root the denominator like so:

Let’s look at some numbers.

We can see that before the 32/10000 was doubly as impactful as the 64/10000, but now, while still resulting in a high score, it’s less than 50% more impactful.


2. Have the meta Trait Count be more impactful

Now, we can make the Trait Count meta-trait more impactful by multiplying the rarity of the trait count by the average number of traits per NFT. This is a simple heuristic for now, and we’ll be exploring different ways to weigh Trait Count.

One other addition is changing numNftsWithTrait to numNftsWithTrait — 0.8 within the square root. This is because the square root of 1 equals 1, which means that this “smoothing” won’t affect 1/1s, and would make 1/2s unfairly closer to 1/1s in rating. Similar to the multiplication by the average trait count, 0.8 is a constant arrived at by experimentation and is still under consideration.

This leaves us with the following pseudo-code to calculate our rarity:

def rating(trait_type, num_nfts_with_trait, collection_size, average_trait_count):
return collection_size / math.sqrt(num_nfts_with_trait - 0.8) * (average_trait_count if trait_type == "Trait Count" else 1)

Let’s redo the example from before, and see how the new ratings shake out.

Note: The average number of traits per ape for BAYC is 5.8835

Pink 4T Ape #3132 — now rank #443

The previously ranked #1 ape, which retains its #1 status

Here’s how the rankings look now:

Going Forward

Another rarity calculation we wish to explore is Jaccard Distance, which measures the dissimilarity in sets. We will publish another blog post exploring this calculation upon feature release.

Closing Thoughts

Every collection is different, and our aim is to:

  1. transparently provide a range of rarity calculations that collectors can choose between
  2. give collection owners the ability to indicate their preferred rarity calculation

Despite what many may think, a “one size fits all” NFT rarity algorithm or standard has yet to be perfected. Are there certain rarity calculations that work better for some collection types than others? Should some traits have a higher weight than others and why? If you’re interested in these open questions, we encourage the reader to dig deeper into the subject and join our Discord server for thoughtful rarity (and, of course, aesthetics) discussion and tea.


The PopRank team