Skip to content

Instantly share code, notes, and snippets.

@rubik
Last active October 27, 2018 16:29
Show Gist options
  • Save rubik/67c13f8664840d318e9e7129cb8f15a5 to your computer and use it in GitHub Desktop.
Save rubik/67c13f8664840d318e9e7129cb8f15a5 to your computer and use it in GitHub Desktop.

Beauty and cosmetics report

Our Instagram database features data on 34 million Instagram profiles. Since it was built over time, it also contains deleted or inactive profiles. In this report we will only consider those profiles that are not deleted and have been active in the last 30 days. We will also restrict our analysis to profiles with 1,000 followers or more.

We currently track 169,096 profiles that are in the beauty and cosmetics industry. Quick facts:

  • 7,509 (4.44%) are private profiles
  • 3,839 (2.27%) are verified profiles
  • 111,189 (65.75%) have less than 10,000 followers (micro influencers)
  • 9,782 (5.78%) have more than 100,000 followers (major influencers)
  • the top two countries for this niche are United States and Italy

The first part of this report will present a descriptive analysis of the Instagram influencers belonging to the group of interest, while the second part will focus on some key metrics that can be of assistance to anyone looking to conduct influencer marketing campaigns on Instagram, especially for this niche.

Location

The geographical location of a profile is estimated by taking into account a variety of factors, like the biography of the profile, the posts and the location tags on each post. For the beauty and cosmetics niche, the profiles in our database are distributed according to the following choropleth map:

countries

As can be seen in the image, the countries with the highest number of Instagram profiles in this niche are the Unites States, Italy and the United Kingdom. Right behind are Australia, Spain and France.

In particular, we can focus on the profiles from the United States:

states

In this case, California, New York, Texas and Florida are by far the states with the most profiles in the beauty and cosmetics sector.

Location data, together with the influencer's posts and comments, can be used to infer the language spoken by those Instagram users (only official languages are considered):

languages

Posting frequency

The great majority of the profiles post a few times a week on average. One may wonder if major influencers post more than regular profiles. That is indeed the case: the biggest influencers post close to 8 times per week on average, while smaller profiles have an average of just 4 posts per week.

posts per week

Followers and following

The distribution of the number of followers is incredibly skewed, so it's very difficult to visualize it in a readable manner. This is true for social network profiles in general, but also for those in niches like the beauty and cosmetics one. This is because the great majority of profiles has a low number of followers (less than 1000), whereas there are profiles with hundreds of millions of followers. This is a difference of 5 orders of magnitudes. Thus, the only way to produce readable graphics is to use a logarithmic scale on the x axis:

followers

Another useful metric to gauge profiles is the ratio between the number of followers and the number of profiles one is following:

followers to following formula

The ratio is very low if a person follows a lot of profiles while being followed by very few accounts. On the other hand, it's very high for the so-called influencers, which have a big audience while at the same time following very few accounts. If the denominator is zero, the ratio is undefined. On average, Instagram accounts have 296 times more followers than following, but for verified profiles this ratio jumps to 17,910.

Another important distinction is between micro and major influencers. We calculate that in the beauty and cosmetics niche, the average followers to following ratio for micro influencers is 22.2, whereas for major influencers it is 26846.1. The distributions are once again very much skewed: the median value for the former group is just 2.66 (meaning that half of the micro influencers have a follower to following ratio equal to or below 2.66, i.e. they can barely considered influencers) and there are profiles with very high ratios that contribute to a higher average value. For the major influencers, the median is 504.4; the distribution is similarly skewed. The 90% quantiles for the two groups are 14.5 and 12098.7 respectively.

What do these values tell us? If you are looking to run campaigns in this niche you should look for micro-influencers with a followers to following ratio greater than 14.5 (which represents only 10% of the total number of micro influencers). On the other hand, if your campaign needs major influencers, you should look for profiles with a followers to following ratio greater than 12098.7 (10% of the total number of major influencers).

Engagement

Perhaps the single most important metric that can reasonably summarize an Instagram profile is the engagement rate. It is defined for each unit of content published by the profile (that is, each post) as the ratio between the sum of the number or likes and replies and the number of followers of the profile:

engagement rate formula

In the beauty and cosmetics niche, this is the distribution of the engagement rate across micro and major influencers:

engagement rate

The engagement rate and the followers to following ratio are related, but their relationship is not as simple as a linear one, as the chart below illustrates:

engagement rate vs followers to following

We can therefore conclude that the engagement rate can be used in combination with the followers to following ratio to evalute Instagram profiles in the beauty and cosmetics niche.

Engagement and posting frequency

We investigated whether posting frequency had a visible relation with engagement rate. Short answer: it does. In the scatter plot below, one can see that for beauty and cosmetics influencers the engagement tends to get lower as the posting frequency increases:

posts per week vs engagement rate

Profile quality

The engagement rate can be used as an indicator of profile quality and can produce some accurate results. In particular, it appears to be very good at pointing out which profiles don't have genuine engagement.

From the formula that defines the engagement rate, we can see that this rate can be above 1 if the sum of likes and replies exceeds the number of followers of a particular profile. This can happen for a fraction of the total posts of a profile (e.g. if one or two posts gain extreme popularity for some reason) but it cannot certainly be the norm, since the number of followers will balance out.

Hence, for healthy profiles the engagement rate will be well below 1. This holds true both in general and for beauty and cosmetics influencers. In our database we also have profiles with an engagement rate in the hundreds or in the thousands

Images and videos

In the beauty and cosmetics niche, there is a noticeable difference in engagement between image posts and video posts, and the contrast is even more pronounced for major influencers.

engagement rate image vs video

The chart above is fairly dense but very informative. It contains two different histograms, overlaid on the same axes, that display the distribution of the ratio between the engagement rate for image posts and the engagement rate for video posts. If one thinks that image posts have a higher engagement than video posts, then they would expect this ratio to be higher than 1. The chart confirms this belief. The methodology that we followed in order to produce such an image is the following: for each profile in our database we took the average engagement rate for image posts and the average engagement rate for video posts and we computed the ratio between them. Then we created the histograms above, which display the frequency of each value.

The result is that, on average, for a micro influencer in this niche image posts have 1.65 times more engagement than video posts, while for major influencers this multiple increases to 2.26 times. Note: this is not to say that video posts have terrible engagement, but the conclusion is that with respect to image posts and as calculated by the formula above the engagement is lower for videos. This may be explained by the fact that the Instagram application itself facilitates the action of liking image posts over video ones. However, investigating systematic biases like that one is outside the scope of this post.

That is only one side of the coin: the engagement quality is also determined by replies and likes. For beauty and cosmetics influencers, the number of likes is much higher than the number of replies. In the beauty and cosmetics niche, on average the profile of a major influencer will have 177.6 times more likes than replies, while for micro influencers the multiple is lower at 40.9 times. Replies are usually considered stronger engagement than simple likes, so this should also be considered by those that have to decide which influencers to partner up with for sponsored campaigns.

location_country total code
United States 12767 USA
Italy 2434 ITA
United Kingdom 2411 GBR
Australia 2079 AUS
Spain 1786 ESP
France 1731 FRA
Canada 1667 CAN
Germany 1456 DEU
Brazil 1412 BRA
Indonesia 1137 IDN
India 1065 IND
Russian Federation 896 RUS
Netherlands 731 NLD
United Arab Emirates 566 ARE
Mexico 560 MEX
Japan 548 JPN
Thailand 506 THA
Philippines 494 PHL
Greece 471 GRC
Malaysia 460 MYS
Poland 439 POL
Nigeria 406 NGA
Portugal 397 PRT
Turkey 375 TUR
Sweden 321 SWE
Belgium 321 BEL
Norway 302 NOR
South Africa 296 ZAF
Israel 294 ISR
Colombia 292 COL
Austria 279 AUT
Argentina 265 ARG
Switzerland 250 CHE
Hungary 245 HUN
Denmark 240 DNK
Lao People's Democratic Republic 224 LAO
Ireland 209 IRL
Puerto Rico 208 PRI
Dominica 205 DMA
Lebanon 204 LBN
Korea, Republic of 195 KOR
Hong Kong 192 HKG
Morocco 189 MAR
New Zealand 180 NZL
Saudi Arabia 176 SAU
Venezuela 160 VEN
Croatia 157 HRV
Egypt 157 EGY
China 149 CHN
Serbia 147 SRB
Ukraine 145 UKR
Cameroon 126 CMR
Pakistan 124 PAK
Czech Republic 119 CZE
Estonia 118 EST
Ghana 116 GHA
Chile 109 CHL
Romania 107 ROU
Jamaica 104 JAM
Dominican Republic 103 DOM
Ecuador 102 ECU
Kenya 100 KEN
Kazakhstan 94 KAZ
Taiwan 92 TWN
Kuwait 90 KWT
Singapore 90 SGP
Montenegro 89 MNE
Finland 88 FIN
Tanzania 83 TZA
Peru 82 PER
Bahrain 66 BHR
Panama 65 PAN
Vietnam 64 VNM
Azerbaijan 64 AZE
Belarus 61 BLR
Tunisia 56 TUN
Cyprus 54 CYP
Iraq 54 IRQ
Jordan 53 JOR
Malta 51 MLT
Qatar 51 QAT
Bulgaria 50 BGR
Fiji 48 FJI
Lithuania 48 LTU
Iran, Islamic Republic of 48 IRN
Bosnia and Herzegovina 46 BIH
Bahamas 46 BHS
Slovakia 45 SVK
Slovenia 44 SVN
Seychelles 44 SYC
Georgia 40 GEO
Latvia 39 LVA
Cuba 38 CUB
New Caledonia 38 NCL
Costa Rica 37 CRI
Iceland 36 ISL
Albania 36 ALB
Andorra 32 AND
Uruguay 32 URY
Maldives 32 MDV
Algeria 32 DZA
Monaco 31 MCO
Moldova 30 MDA
Sri Lanka 28 LKA
Macao 28 MAC
Gabon 28 GAB
Jersey 27 JEY
Mauritius 25 MUS
Paraguay 25 PRY
Luxembourg 24 LUX
Bolivia 23 BOL
Congo, The Democratic Republic of the 22 COD
Armenia 22 ARM
Honduras 20 HND
Côte d'Ivoire 20 CIV
Tonga 19 TON
Nepal 19 NPL
Guatemala 17 GTM
Barbados 17 BRB
Djibouti 16 DJI
Cambodia 16 KHM
Niger 15 NER
Madagascar 13 MDG
Mongolia 13 MNG
Bangladesh 13 BGD
Nicaragua 12 NIC
Namibia 12 NAM
Oman 12 OMN
Trinidad and Tobago 12 TTO
Senegal 11 SEN
Haiti 11 HTI
Holy See (Vatican City State) 11 VAT
Uganda 11 UGA
Benin 11 BEN
Bermuda 11 BMU
Virgin Islands, U.S. 11 VIR
Comoros 10 COM
El Salvador 9 SLV
Equatorial Guinea 9 GNQ
Suriname 9 SUR
Sudan 9 SDN
Myanmar 9 MMR
Syrian Arab Republic 9 SYR
Martinique 9 MTQ
Palestine, State of 8 PSE
Timor-Leste 8 TLS
Cape Verde 8 CPV
Rwanda 7 RWA
Botswana 7 BWA
Somalia 7 SOM
Uzbekistan 7 UZB
Guyana 7 GUY
Angola 7 AGO
Antigua and Barbuda 6 ATG
Guam 6 GUM
Liechtenstein 6 LIE
Belize 6 BLZ
Saint Pierre and Miquelon 6 SPM
Cayman Islands 6 CYM
Mayotte 5 MYT
Saint Lucia 5 LCA
Northern Mariana Islands 5 MNP
Turkmenistan 5 TKM
Sao Tome and Principe 5 STP
Curaçao 5 CUW
Central African Republic 5 CAF
Aruba 4 ABW
Mozambique 4 MOZ
Guinea 4 GIN
Guadeloupe 3 GLP
Togo 3 TGO
Tuvalu 3 TUV
San Marino 3 SMR
Zambia 3 ZMB
Zimbabwe 3 ZWE
Réunion 3 REU
Sierra Leone 3 SLE
Macedonia, Republic of 3 MKD
Mali 3 MLI
Grenada 3 GRD
Gambia 3 GMB
Åland Islands 3 ALA
Papua New Guinea 3 PNG
Tajikistan 3 TJK
Micronesia, Federated States of 2 FSM
Afghanistan 2 AFG
Greenland 2 GRL
Mauritania 2 MRT
Marshall Islands 2 MHL
Guinea-Bissau 2 GNB
Pitcairn 2 PCN
Kyrgyzstan 2 KGZ
Anguilla 2 AIA
Burkina Faso 2 BFA
Brunei Darussalam 2 BRN
Libya 2 LBY
Saint Kitts and Nevis 2 KNA
Liberia 1 LBR
Sint Maarten (Dutch part) 1 SXM
Turks and Caicos Islands 1 TCA
Bhutan 1 BTN
South Sudan 1 SSD
French Polynesia 1 PYF
Saint Martin (French part) 1 MAF
Isle of Man 1 IMN
French Southern Territories 1 ATF
Saint Helena, Ascension and Tristan da Cunha 1 SHN
Congo 1 COG
Samoa 1 WSM
Svalbard and Jan Mayen 1 SJM
Ethiopia 1 ETH
Malawi 1 MWI
Solomon Islands 1 SLB
Guernsey 1 GGY
Swaziland 1 SWZ
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.countries {
fill: none;
stroke: #fff;
stroke-linejoin: round;
}
.legendThreshold {
font-size: 12px;
font-family: sans-serif;
}
.caption {
fill: #000;
text-anchor: start;
font-weight: bold;
}
.graticule {
fill: none;
stroke: #777;
stroke-width: 0.5px;
stroke-opacity: 0.35;
}
</style>
<svg width="960" height="600"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script src="https://d3js.org/d3-geo-projection.v2.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.24.0/d3-legend.js"></script>
<script>
// The svg
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
// Map and projection
var path = d3.geoPath();
//var projection = d3.geoMollweide()
var projection = d3.geoRobinson()
.scale(width / 2 / Math.PI)
.translate([width / 2, height / 2])
var path = d3.geoPath()
.projection(projection);
var graticule = d3.geoGraticule();
svg.append("path")
.datum(graticule)
.attr("class", "graticule")
.attr("d", path);
// Data and color scale
var data = d3.map();
var colorScheme = d3.schemeReds[5];
colorScheme.unshift("#eee")
var colorScale = d3.scaleThreshold()
.domain([1, 250, 500, 1000, 5000, 10000])
.range(colorScheme);
// Legend
var g = svg.append("g")
.attr("class", "legendThreshold")
.attr("transform", "translate(20,20)");
g.append("text")
.attr("class", "caption")
.attr("x", 0)
.attr("y", -6)
.text("Beauty blogger profiles");
var labels = ['1-250', '250-500', '500-1,000', '1,000-5,000', '5,000-10,000', '>10,000'];
var legend = d3.legendColor()
.labels(function (d) { return labels[d.i]; })
.shapePadding(4)
.scale(colorScale);
svg.select(".legendThreshold")
.call(legend);
// Load external data and boot
d3.queue()
.defer(d3.json, "world-110m.geojson")
.defer(d3.csv, "countries.csv", function(d) { data.set(d.code, +d.total); })
.await(ready);
function ready(error, topo) {
if (error) throw error;
// Draw the map
svg.append("g")
.attr("class", "countries")
.selectAll("path")
.data(topo.features)
.enter().append("path")
.attr("fill", function (d){
// Pull data for this country
d.total = data.get(d.id) || 0;
// Set the color
return colorScale(d.total);
})
.attr("d", path);
}
</script>
state value
California 3908
New York 2312
Texas 1104
Florida 1030
New Jersey 407
Illinois 267
Pennsylvania 253
Georgia 230
Tennessee 226
Arizona 221
North Carolina 210
Ohio 191
Washington 189
Colorado 170
Utah 147
Massachusetts 144
Nevada 141
South Carolina 124
Michigan 118
Oregon 104
Hawaii 100
Louisiana 81
Alabama 70
Maryland 69
Virginia 67
Oklahoma 59
Kansas 53
Indiana 41
Missouri 40
Rhode Island 39
Connecticut 39
Minnesota 39
Wisconsin 31
New Mexico 29
Arkansas 20
Mississippi 20
Delaware 19
Nebraska 17
Kentucky 16
Maine 15
Idaho 14
Iowa 12
Alaska 9
South Dakota 9
Montana 8
Vermont 8
Wyoming 7
New Hampshire 7
West Virginia 5
North Dakota 4
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style type="text/css">
/* Legend Font Style */
body {
font: 11px sans-serif;
background-color: #ffffff;
}
/* Legend Position Style */
.legend {
position:absolute;
left:20px;
top:30px;
}
.axis text {
font: 10px sans-serif;
}
.caption {
fill: #000;
text-anchor: start;
font-weight: bold;
}
.axis line, .axis path {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
</style>
</head>
<body>
<script type="text/javascript">
//Width and height of map
var width = 960;
var height = 500;
var lowColor = '#f9f9f9'
var highColor = '#7a0141'
// D3 Projection
var projection = d3.geoAlbersUsa()
.translate([width / 2, height / 2]) // translate to center of screen
.scale([1000]); // scale things down so see entire US
// Define path generator
var path = d3.geoPath() // path generator that will convert GeoJSON to SVG paths
.projection(projection); // tell path generator to use albersUsa projection
//Create SVG element and append map to the SVG
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
// Load in my states data!
d3.csv("states.csv", function(data) {
var dataArray = [];
for (var d = 0; d < data.length; d++) {
dataArray.push(parseFloat(data[d].value))
}
var minVal = d3.min(dataArray)
var maxVal = d3.max(dataArray)
var ramp = d3.scalePow().exponent(1 / 3).domain([minVal,maxVal]).range([lowColor,highColor])
// Load GeoJSON data and merge with states data
d3.json("us-states.json", function(json) {
// Loop through each state data value in the .csv file
for (var i = 0; i < data.length; i++) {
// Grab State Name
var dataState = data[i].state;
// Grab data value
var dataValue = data[i].value;
// Find the corresponding state inside the GeoJSON
for (var j = 0; j < json.features.length; j++) {
var jsonState = json.features[j].properties.name;
if (dataState == jsonState) {
// Copy the data value into the JSON
json.features[j].properties.value = dataValue;
// Stop looking through the JSON
break;
}
}
}
// Bind the data to the SVG and create one path per GeoJSON feature
svg.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path)
.style("stroke", "#fff")
.style("stroke-width", "1")
.style("fill", function(d) { return ramp(d.properties.value) });
// add a legend
var w = 140, h = 300;
var key = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h)
.attr("class", "legend");
key.append('text').attr("class", "caption")
.attr("x", 0)
.attr("y", 10)
.text("Beauty blogger profiles");
var legend = key.append("defs")
.append("svg:linearGradient")
.attr("id", "gradient")
.attr("x1", "100%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "100%")
.attr("spreadMethod", "pad");
legend.append("stop")
.attr("offset", "0%")
.attr("stop-color", highColor)
.attr("stop-opacity", 1);
legend.append("stop")
.attr("offset", "100%")
.attr("stop-color", lowColor)
.attr("stop-opacity", 1);
key.append("rect")
.attr("width", w - 100)
.attr("height", h)
.style("fill", "url(#gradient)")
.attr("transform", "translate(0,20)");
var y = d3.scaleLinear()
.range([h, 0])
.domain([minVal, maxVal]);
var yAxis = d3.axisRight(y);
key.append("g")
.attr("class", "y axis")
.attr("transform", "translate(41,20)")
.call(yAxis)
});
});
</script>
</body>
</html>
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment