Skip to content
0

Demystifying data salaries

📖 Context

collected between 2020 and 2024. The data includes detailed information on job roles, experience levels, remote work status, company sizes, and salaries in USD. The goal is to understand how different factors relate to compensation trends across regions and professional profiles. This information serves as a foundation for helping companies remain competitive in attracting and retaining top talent in a rapidly evolving job market.

🔎 executive summary

In this global salary analysis within the tech industry, I explored how job role, remote work setup, and company size influence compensation. I identified the top five highest-paying roles, highlighting both technical and strategic positions. I also compared salaries across 100%, 50%, and 0% remote workers, noticing an advantage for fully on-site roles. Finally, I analyzed salary distribution by company size and found that larger companies tend to show greater variation in pay, with a stronger on-site presence among employees.

🍛 Importing dependencies and functions

!pip install pywaffle
import pandas as pd
import numpy as np
import plotly.express as px
import matplotlib.pyplot as plt
import seaborn as sns
from pywaffle import Waffle
from IPython.display import display, HTML
from plotly.graph_objects import Figure

# Classe para criação dos gráficos


cores = {'2.Hybrid': '#A64D2D', 
         '1.Presencial' : '#260801',
         '3.Remote': '#F2BA52'}  


class Grafico:
        
    def __init__(self, configuracao_grafico):
        self.__config_grafico = configuracao_grafico
        
        sns.set_style("ticks")
        self.__figura, self.__graficos = plt.subplots(
            self.__config_grafico['figura']['linhas'], 
            self.__config_grafico['figura']['colunas'], 
            gridspec_kw={'width_ratios': self.__config_grafico['figura']['proporcao']}, 
            figsize=self.__config_grafico['figura']['tamanho']
        )
        
        self.__figura.suptitle(self.__config_grafico['titulo'], x=0.01, y=1.05)
        self.__figura.text(0.01, 0.945, self.__config_grafico['subtitulo'], fontsize=14)
  
        sns.despine()
          
    def grafico_contagem(self, config_grafico, numero_grafico): 
        ax = sns.countplot(data=config_grafico['data'], 
                           x=config_grafico['eixo_x'], 
                           palette=config_grafico['paleta_cores'], 
                           order=config_grafico['ordem'], 
                           ax=self.__graficos[numero_grafico])
        ax.set_title(config_grafico['titulo'], fontsize=13)
        ax.set(xlabel=config_grafico['rotulo_x'], ylabel=config_grafico['rotulo_y'])
        ax.set_xticklabels(ax.get_xticklabels(), rotation=config_grafico['rotacao_texto_x'])
        ax.text(config_grafico['coord_anotacao_x'], config_grafico['coord_anotacao_y'], 
                config_grafico['anotacao'], ha="left")
    
    def grafico_caixas(self, config_grafico, numero_grafico): 
        ax = sns.boxplot(data=config_grafico['data'], 
                         x=config_grafico['eixo_x'], 
                         y=config_grafico['eixo_y'], 
                         palette=config_grafico['paleta_cores'],
                         order=config_grafico['ordem'],
                         showfliers=False,
                         ax=self.__graficos[numero_grafico])
        ax.set_title(config_grafico['titulo'], fontsize=13)
        ax.set(xlabel=config_grafico['rotulo_x'], ylabel=config_grafico['rotulo_y'])
        ax.annotate(config_grafico['anotacao'],
                    xy=config_grafico['coord_anotacao_xy'],
                    xytext=config_grafico['coord_anotacao_seta'],
                    arrowprops=dict(facecolor='gray', arrowstyle="->"),
                    fontsize=10)
        
        
df = pd.read_csv('salaries.csv')

📈 Dataframe Statistics

In this analysis we can observe that the data refers to a survey between 2020 and 2024, involving around 57,194k professionals, the average salary (USD) for the entire survey period was US 159,233, however for the most recent year we can observe an average salary of US$161,488.

df.describe()
Hidden code

🔝 Top5 Positions with the highest salary

The average salary for the Top 5 Highest Paying Positions is $323,721.32, which is around 200% higher than the overall average salary. We can see that these positions are mainly occupied by management and C-Level positions.

Hidden code

🚏 Salary by type of relationship

We observed that medium and large-sized companies tend to encourage on-site work, with approximately 76% of employees working in person at companies of these sizes. In contrast, small-sized companies show a preference for remote work.

Regarding salaries, we noticed that professionals working on-site tend to have higher salary variation, with generally higher earnings, likely due to their presence in larger companies.

Hidden code
# Paleta de cores personalizada
cores = {
    '2.Hybrid': '#A64D2D', 
    '1.Presencial': '#260801',
    '3.Remote': '#F2BA52'
}

# Ajustando eixo_x para usar uma única coluna válida
eixo_x = 'contract_type'
eixo_y = 'salary_in_usd'

# Garantir que apenas colunas numéricas sejam usadas no agrupamento
df_agrupado = df.groupby(eixo_x)[eixo_y].mean().sort_index()

# Gerar ordem com base na contagem de valores únicos
ordem = df[eixo_x].value_counts().sort_index().index.to_list()

# Configuração do gráfico
config_faixa_idade = {
    'figura': {'linhas': 1, 'colunas': 2, 'proporcao': [2, 4], 'tamanho': (13, 5)},
    'titulo': "Salary range according to the work model\n\n",
    'subtitulo': "The most adopted work model was in-person work."
}

faixa_idade_contagem = {
    'data': df,
    'eixo_x': eixo_x,
    'eixo_y': eixo_y,
    'ordem': ordem,
    'titulo': "Work model \n",
    'rotulo_x': '',
    'rotulo_y': '#Amount',
    'rotacao_texto_x': 45,
    # Usando a paleta de cores personalizada
    'paleta_cores': [cores[x] for x in ordem],
    'coord_anotacao_x': -0.2,
    'coord_anotacao_y': df[eixo_x].value_counts().max() + 500,
    'anotacao': f"The fully in-person model predominated in the survey."
}

faixa_idade_caixas = {
    'data': df,
    'eixo_x': eixo_x,
    'eixo_y': eixo_y,
    'ordem': ordem,
    'titulo': f"Salary Range vs Work Model \n",
    'rotulo_x': '',
    'rotulo_y': f"Salary Range (USD)",
    'rotacao_texto_x': 0,
    # Usando a paleta de cores personalizada
    'paleta_cores': [cores[x] for x in ordem],
    # Coordenadas para anotação
    'coord_anotacao_xy': (0.2, df_agrupado.max() + 10000),
    'coord_anotacao_seta': (0.5, df_agrupado.max() + 30000),
    # Texto da anotação
    'anotacao': f"The in-person model showed greater variation in salaries.",
}

grafico_faixa_idade = Grafico(config_faixa_idade)
grafico_faixa_idade.grafico_contagem(faixa_idade_contagem, 0)
grafico_faixa_idade.grafico_caixas(faixa_idade_caixas, 1)

plt.tight_layout()  # Ajustar o layout para evitar cortes
plt.show()

🏢 Salary by company Size

# Paleta de cores personalizada
cores = {
    'L': '#13678A', 
    'M': '#45C4B0',
    'S': '#9AEBA3'
}

# Ajustando eixo_x para usar uma única coluna válida
eixo_x = 'company_size'
eixo_y = 'salary_in_usd'

# Garantir que apenas colunas numéricas sejam usadas no agrupamento
df_agrupado = df.groupby(eixo_x)[eixo_y].mean().sort_index()

# Gerar ordem com base na contagem de valores únicos
ordem = df[eixo_x].value_counts().sort_index().index.to_list()

# Configuração do gráfico
config_faixa_idade = {
    'figura': {'linhas': 1, 'colunas': 2, 'proporcao': [2, 4], 'tamanho': (13, 5)},
    'titulo': "Salary range according to the company size\n\n",
    'subtitulo': "company size (L) Large, (M) Medium, (S) Small"
}

faixa_idade_contagem = {
    'data': df,
    'eixo_x': eixo_x,
    'eixo_y': eixo_y,
    'ordem': ordem,
    'titulo': "Company Size\n",
    'rotulo_x': '',
    'rotulo_y': '#Amount',
    'rotacao_texto_x': 45,
    # Usando a paleta de cores personalizada
    'paleta_cores': [cores[x] for x in ordem],
    'coord_anotacao_x': -0.2,
    'coord_anotacao_y': df[eixo_x].value_counts().max() + 500,
    'anotacao': f"Most of the respondents belong to medium-sized companies."
}

faixa_idade_caixas = {
    'data': df,
    'eixo_x': eixo_x,
    'eixo_y': eixo_y,
    'ordem': ordem,
    'titulo': f"Salary Range vs Company Size \n",
    'rotulo_x': '',
    'rotulo_y': f"Salary Range (USD)",
    'rotacao_texto_x': 0,
    # Usando a paleta de cores personalizada
    'paleta_cores': [cores[x] for x in ordem],
    # Coordenadas para anotação
    'coord_anotacao_xy': (-0.2,129900),
    'coord_anotacao_seta': (-0.5, df_agrupado.max() + 80000),
    # Texto da anotação
    'anotacao': f"People who work in large companies have greater salary variation\n, but the median is lower than that of people in medium-sized companies.",
}

grafico_faixa_idade = Grafico(config_faixa_idade)
grafico_faixa_idade.grafico_contagem(faixa_idade_contagem, 0)
grafico_faixa_idade.grafico_caixas(faixa_idade_caixas, 1)

plt.tight_layout()
plt.show()