<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Maria-Luise Volkmar</title>
    <description>The latest articles on DEV Community by Maria-Luise Volkmar (@mlvolkmar).</description>
    <link>https://dev.to/mlvolkmar</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3988623%2Fd3e8e48d-c749-4f72-9f69-ebf9656ac9fa.png</url>
      <title>DEV Community: Maria-Luise Volkmar</title>
      <link>https://dev.to/mlvolkmar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mlvolkmar"/>
    <language>en</language>
    <item>
      <title>Who actually feels lost about Germany's new automatic platform and crypto tax reporting? (a pandas cut)</title>
      <dc:creator>Maria-Luise Volkmar</dc:creator>
      <pubDate>Thu, 02 Jul 2026 19:08:14 +0000</pubDate>
      <link>https://dev.to/mlvolkmar/who-actually-feels-lost-about-germanys-new-automatic-platform-and-crypto-tax-reporting-a-pandas-5fc4</link>
      <guid>https://dev.to/mlvolkmar/who-actually-feels-lost-about-germanys-new-automatic-platform-and-crypto-tax-reporting-a-pandas-5fc4</guid>
      <description>&lt;p&gt;Since January 2026, if you sell on eBay or Vinted, rent a room on Airbnb, or trade on Coinbase or Bitpanda, the platform now reports your income straight to the German tax office. Germany's Platform Tax Transparency Act (PStTG) and the crypto-side KStTG mean the numbers land at the Finanzamt whether you declare them or not. So here is a data question worth asking: now that the reporting is automatic, who actually feels confident about getting their own declaration right, and who feels completely lost?&lt;/p&gt;

&lt;p&gt;I had a strong prior going in. Platform income and crypto are the natural habitat of digital natives, so I expected the youngest cohort to shrug this off and the oldest to struggle. A representative survey (Norstat, n = 1,010, January 2026) that shipped its raw numbers as an open CSV lets us check that prior instead of guessing. The answer flips the intuition on its head.&lt;/p&gt;

&lt;h2&gt;
  
  
  The headline figure
&lt;/h2&gt;

&lt;p&gt;Across all respondents, &lt;strong&gt;52.9% feel "rather unsure" or "totally overwhelmed"&lt;/strong&gt; about correctly declaring this income. Only &lt;strong&gt;16.1% feel in full command&lt;/strong&gt; of it. So a bare majority of Germans are not confident they can file platform and crypto income correctly under the new rules.&lt;/p&gt;

&lt;p&gt;That is the top line. The interesting part is where the discomfort concentrates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Load the open data
&lt;/h2&gt;

&lt;p&gt;The full survey is published as a CC BY 4.0 open dataset on GitHub. One CSV, one row per segment, values already as percentages of that segment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://raw.githubusercontent.com/DatapulseResearch/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;steuersuender-2026/main/data/tax_uncertainty_survey_2026.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="c1"&gt;# ['segment', 'base_n', 'full_overview_pct', 'secure_with_effort_pct',
#  'rather_unsure_pct', 'overwhelmed_pct']
&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;segment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Total&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each row is a population segment (&lt;code&gt;Total&lt;/code&gt;, the age bands &lt;code&gt;18-29&lt;/code&gt; through &lt;code&gt;60-64&lt;/code&gt;, plus &lt;code&gt;men&lt;/code&gt; and &lt;code&gt;women&lt;/code&gt;), and the four &lt;code&gt;*_pct&lt;/code&gt; columns are the confidence buckets, from "I have full overview" down to "totally overwhelmed, impossible without a professional".&lt;/p&gt;

&lt;h2&gt;
  
  
  Build a "struggling" column
&lt;/h2&gt;

&lt;p&gt;Let me collapse the two low-confidence buckets into a single &lt;code&gt;struggling&lt;/code&gt; measure (rather unsure + overwhelmed), then look at the age bands only.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;struggling_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rather_unsure_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;overwhelmed_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;age_bands&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;18-29&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;30-39&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;40-49&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;50-59&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;60-64&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;by_age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;segment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;isin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;age_bands&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;segment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;overwhelmed_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;struggling_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;age_bands&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;by_age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the counterintuitive part. Watch the &lt;code&gt;overwhelmed_pct&lt;/code&gt; column, the share who say the task is flat-out impossible without a professional, as age climbs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;age band&lt;/th&gt;
&lt;th&gt;overwhelmed_pct&lt;/th&gt;
&lt;th&gt;struggling_pct&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;18-29&lt;/td&gt;
&lt;td&gt;15.8&lt;/td&gt;
&lt;td&gt;54.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;30-39&lt;/td&gt;
&lt;td&gt;7.4&lt;/td&gt;
&lt;td&gt;50.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;40-49&lt;/td&gt;
&lt;td&gt;15.0&lt;/td&gt;
&lt;td&gt;50.3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;50-59&lt;/td&gt;
&lt;td&gt;22.9&lt;/td&gt;
&lt;td&gt;54.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;60-64&lt;/td&gt;
&lt;td&gt;25.0&lt;/td&gt;
&lt;td&gt;55.5&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The "totally overwhelmed" share does not fall as people get older. It &lt;strong&gt;rises steeply&lt;/strong&gt;: from &lt;strong&gt;7.4% at 30-39 to 25.0% at 60-64&lt;/strong&gt;, more than a threefold climb. The digital natives are not the ones drowning. The people most likely to say they cannot do this without a professional are the oldest cohort, exactly the group you would not expect to be selling on Vinted or trading crypto in the first place.&lt;/p&gt;

&lt;p&gt;You can see the gradient in one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;gradient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;by_age&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;overwhelmed_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gradient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;min -&amp;gt; max:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gradient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gradient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A second cut: the gender gap
&lt;/h2&gt;

&lt;p&gt;The same &lt;code&gt;struggling&lt;/code&gt; column, sliced by gender, gives a smaller but consistent gap.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;gender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;segment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;isin&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;men&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;women&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])]&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;segment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;struggling_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gender&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# women   55.4
# men     50.0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Women report &lt;strong&gt;55.4%&lt;/strong&gt; unsure-or-overwhelmed against &lt;strong&gt;50.0%&lt;/strong&gt; for men, a 5.4 point spread. It runs the same direction as the age story: the confidence is not evenly distributed, and the groups you might assume are least exposed to platform and crypto income are not the most confident.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the intuition is wrong
&lt;/h2&gt;

&lt;p&gt;My guess is that "confidence about declaring crypto and platform income" is not really a proxy for "uses crypto and platforms". It is a proxy for &lt;strong&gt;comfort with the German tax system under a new rule&lt;/strong&gt;, and that comfort tracks age (and, more mildly, gender) rather than digital fluency. A 27-year-old who sells sneakers on eBay may not think twice about the paperwork; a 62-year-old who rents out a holiday flat sees an unfamiliar automatic-reporting regime and reasonably concludes they need help. The automation does not simplify the declaration, it just removes the option of it going unnoticed, and that is precisely what raises the anxiety in the groups least fluent in the process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data and method
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Study:&lt;/strong&gt; &lt;a href="https://www.buchhaltungsbutler.de/steuersuender-2026/" rel="noopener noreferrer"&gt;Digital Tax Transparency in Germany 2026&lt;/a&gt; by BuchhaltungsButler, the full write-up with methodology and charts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open dataset (CC BY 4.0):&lt;/strong&gt; &lt;a href="https://github.com/DatapulseResearch/steuersuender-2026" rel="noopener noreferrer"&gt;DatapulseResearch/steuersuender-2026 on GitHub&lt;/a&gt;, including the exact &lt;a href="https://raw.githubusercontent.com/DatapulseResearch/steuersuender-2026/main/data/tax_uncertainty_survey_2026.csv" rel="noopener noreferrer"&gt;tax_uncertainty_survey_2026.csv&lt;/a&gt; loaded above.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Survey:&lt;/strong&gt; representative online panel by Norstat, n = 1,010 adults in Germany, fielded January 2026. Percentages are within each segment; segment base sizes are in the &lt;code&gt;base_n&lt;/code&gt; column.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reproduce:&lt;/strong&gt; every number in this post comes from the four snippets above run against the raw CSV. Clone the repo, run them, and you should land on the same 52.9% headline, the 7.4 to 25.0 age gradient, and the 55.4 vs 50.0 gender split.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Community close
&lt;/h2&gt;

&lt;p&gt;If you pull the CSV, I would be curious what you find in the &lt;code&gt;secure_with_effort_pct&lt;/code&gt; column, the "I can manage but it takes real effort" middle group, which I did not touch here. Where does it peak, and does it fill in the gap left by the confident young and the overwhelmed old? Drop your cut in the comments.&lt;/p&gt;

</description>
      <category>dataanalysis</category>
      <category>opendata</category>
      <category>python</category>
      <category>datavisualization</category>
    </item>
    <item>
      <title>Does the month you start predict whether you keep a habit? 1.1M piano learners say yes</title>
      <dc:creator>Maria-Luise Volkmar</dc:creator>
      <pubDate>Thu, 02 Jul 2026 19:05:51 +0000</pubDate>
      <link>https://dev.to/mlvolkmar/does-the-month-you-start-predict-whether-you-keep-a-habit-11m-piano-learners-say-yes-4970</link>
      <guid>https://dev.to/mlvolkmar/does-the-month-you-start-predict-whether-you-keep-a-habit-11m-piano-learners-say-yes-4970</guid>
      <description>&lt;p&gt;Every January, a wave of people decide this is the year they finally learn something. New gym membership, new language app, new instrument. And every February, most of them quit.&lt;/p&gt;

&lt;p&gt;I wanted to test a narrower version of that folk wisdom with real data: does the calendar month you start a habit actually predict whether you are still doing it six months later? Not "do resolutions fail" (they do), but "is the resolution &lt;em&gt;window itself&lt;/em&gt; a bad time to start"?&lt;/p&gt;

&lt;p&gt;There is a clean dataset for this. Skoove, an online piano-learning platform, tracked six-month retention by signup month across &lt;strong&gt;1,137,446 learners&lt;/strong&gt; from 2021 to 2024. The dataset is open on GitHub, so you can reproduce every number below.&lt;/p&gt;

&lt;h2&gt;
  
  
  The headline figure
&lt;/h2&gt;

&lt;p&gt;Here is the finding in one sentence: &lt;strong&gt;the December-to-January resolution window, which pulls in roughly a quarter of all signups, has the worst six-month retention of any part of the year.&lt;/strong&gt; People who start in spring stick with it far more.&lt;/p&gt;

&lt;p&gt;The dataset expresses each quantified month as a percentage difference from the average learner's six-month retention:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;start_month&lt;/th&gt;
&lt;th&gt;six_month_retention_vs_average_pct&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;December&lt;/td&gt;
&lt;td&gt;-28&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;January&lt;/td&gt;
&lt;td&gt;-21&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;April&lt;/td&gt;
&lt;td&gt;+18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;June&lt;/td&gt;
&lt;td&gt;+18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;May&lt;/td&gt;
&lt;td&gt;+23&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Load it yourself
&lt;/h2&gt;

&lt;p&gt;The dataset is a plain CSV on GitHub. No key, no download, pandas reads the raw URL directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://raw.githubusercontent.com/DatapulseResearch/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;new-year-resolution-retention/main/data/retention_by_start_month.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Sort worst-to-best on six-month retention vs the average learner
&lt;/span&gt;&lt;span class="n"&gt;ranked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort_values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;six_month_retention_vs_average_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ranked&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;start_month&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;six_month_retention_vs_average_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sorting worst-to-best puts the story on one screen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  start_month  six_month_retention_vs_average_pct
     December                                 -28
      January                                 -21
        April                                  18
         June                                  18
          May                                  23
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The two months sitting at the bottom are exactly the two months of the resolution season. The top of the table is spring.&lt;/p&gt;

&lt;h2&gt;
  
  
  The counterintuitive part
&lt;/h2&gt;

&lt;p&gt;The intuitive model is that motivation is highest in January (fresh start, clean slate, public commitment), so January starters should do at least average. The data says the opposite: &lt;strong&gt;the most popular time to begin is one of the worst times to persist.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A quick way to see the gap between "when people start" and "when starting works":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;resolution_window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;start_month&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;isin&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;December&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;January&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])]&lt;/span&gt;
&lt;span class="n"&gt;spring_window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;start_month&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;isin&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;April&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;May&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;June&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])]&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;resolution window avg:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resolution_window&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;six_month_retention_vs_average_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spring window avg:    &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spring_window&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;six_month_retention_vs_average_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resolution window avg: -24.5
spring window avg:     19.7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a roughly 44 percentage-point swing in six-month retention between starting on a New Year's resolution and starting in spring. Same platform, same lessons, same learners, different month.&lt;/p&gt;

&lt;p&gt;Why might spring win? The dataset does not encode causes, so I will not overclaim. But two hypotheses are worth stating and testing elsewhere: resolution-season starters are often driven by a calendar deadline rather than genuine interest, and spring starters may self-select as people who decided to learn piano for its own reasons, on their own timing, with no crowd and no January pressure.&lt;/p&gt;

&lt;h2&gt;
  
  
  An honest note on coverage
&lt;/h2&gt;

&lt;p&gt;The dataset only contains the months the underlying study actually quantified. February, March, and July through November are not in the CSV, and I have not invented values for them.&lt;/p&gt;

&lt;p&gt;Two of the figures are range bounds rather than point estimates: the study reported the spring lift as a "+18 to +23%" band, so &lt;strong&gt;April and June are entered at +18, the lower bound&lt;/strong&gt; (the true spring effect is at least that large). December (-28), January (-21) and May (+23) are stated exactly.&lt;/p&gt;

&lt;p&gt;So the correct claim is narrow and defensible: &lt;strong&gt;among the months that were measured, the resolution window is the worst and spring is the best.&lt;/strong&gt; It is not a claim about the eight months no one measured.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data and method
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dataset (CC BY 4.0):&lt;/strong&gt; &lt;a href="https://github.com/DatapulseResearch/new-year-resolution-retention" rel="noopener noreferrer"&gt;new-year-resolution-retention on GitHub&lt;/a&gt;. The repo also ships a second CSV, &lt;a href="https://raw.githubusercontent.com/DatapulseResearch/new-year-resolution-retention/main/data/resolution_stats_by_country.csv" rel="noopener noreferrer"&gt;resolution_stats_by_country.csv&lt;/a&gt;, with resolution-abandonment metrics by country and source.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sample:&lt;/strong&gt; 1,137,446 Skoove piano learners, 2021 to 2024, six-month retention tracked by signup month.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source study:&lt;/strong&gt; &lt;a href="https://www.skoove.com/blog/de/klavier-neujahrsvorsaetze/" rel="noopener noreferrer"&gt;New Year's Resolution Retention (Skoove, 2021-2024)&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reproducibility:&lt;/strong&gt; every number above comes straight from the raw CSV loaded in the snippets; run them and you will get the same output.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Close
&lt;/h2&gt;

&lt;p&gt;If you are shipping a habit-formation feature, a learning product, or just your own side project, the "New Year, New You" spike is a tempting moment to launch into. This dataset is a small reminder that the crowded start line is not the same as the finish line. If you re-run the numbers or slice the country CSV differently, I would love to see what you find in the comments.&lt;/p&gt;

</description>
      <category>dataanalysis</category>
      <category>opendata</category>
      <category>python</category>
      <category>datavisualization</category>
    </item>
    <item>
      <title>Europe's brain drain: the biggest loser flips when you normalize per 1,000 residents</title>
      <dc:creator>Maria-Luise Volkmar</dc:creator>
      <pubDate>Thu, 02 Jul 2026 18:06:36 +0000</pubDate>
      <link>https://dev.to/mlvolkmar/europes-brain-drain-the-biggest-loser-flips-when-you-normalize-per-1000-residents-4bk5</link>
      <guid>https://dev.to/mlvolkmar/europes-brain-drain-the-biggest-loser-flips-when-you-normalize-per-1000-residents-4bk5</guid>
      <description>&lt;p&gt;Here is a question I could not answer from the headlines: which European countries are actually losing people the fastest, in absolute terms or per capita? Those are two different questions, and they give two different answers. So I pulled the open data and ran the numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The headline figure
&lt;/h2&gt;

&lt;p&gt;Across the 19 European countries in the 2024 dataset, &lt;strong&gt;17 recorded a net loss of native-born residents&lt;/strong&gt;. Only two were net positive. So the "brain drain" story is not a handful of outliers, it is the default state of the continent.&lt;/p&gt;

&lt;p&gt;But the interesting part is &lt;em&gt;who&lt;/em&gt; tops the ranking, because it depends entirely on how you measure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Load the data yourself
&lt;/h2&gt;

&lt;p&gt;The dataset is public on GitHub (CC BY 4.0). Every number below is reproducible with a few lines of pandas. No download, no API key, it reads the raw CSV straight from the repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://raw.githubusercontent.com/DatapulseResearch/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;brain-drain-eu/main/data/net_migration_native_born_2024.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;# (19, 3)
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;  &lt;span class="c1"&gt;# ['country', 'net_migration', 'per_1000_residents']
&lt;/span&gt;
&lt;span class="c1"&gt;# How many countries lost native-born residents?
&lt;/span&gt;&lt;span class="n"&gt;losers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;net_migration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;losers&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; of &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; countries had a net loss&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# 17 of 19
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;net_migration&lt;/code&gt; is the raw count for 2024 (negative means a net loss of native-born residents). &lt;code&gt;per_1000_residents&lt;/code&gt; is the same flow normalized by population size.&lt;/p&gt;

&lt;h2&gt;
  
  
  The absolute ranking: Germany runs away with it
&lt;/h2&gt;

&lt;p&gt;Sort by the raw count and one country dominates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;worst_absolute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort_values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;net_migration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;head&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;worst_absolute&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;country&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;net_migration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csvs"&gt;&lt;code&gt;       &lt;span class="k"&gt;country&lt;/span&gt;  &lt;span class="k"&gt;net&lt;/span&gt;&lt;span class="err"&gt;_&lt;/span&gt;&lt;span class="k"&gt;migration&lt;/span&gt;
&lt;span class="mf"&gt;0&lt;/span&gt;      &lt;span class="k"&gt;Germany&lt;/span&gt;         &lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;91067&lt;/span&gt;
&lt;span class="err"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Germany loses &lt;strong&gt;-91,067&lt;/strong&gt; native-born residents, far more than anyone else in absolute terms. If you stop reading here, the story writes itself: "Germany, Europe's biggest brain drain." Plenty of coverage did exactly that.&lt;/p&gt;

&lt;h2&gt;
  
  
  The counterintuitive finding: the ranking inverts per capita
&lt;/h2&gt;

&lt;p&gt;Now normalize by population and sort by &lt;code&gt;per_1000_residents&lt;/code&gt;. The leaderboard is unrecognizable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;worst_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort_values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;per_1000_residents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;head&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;worst_rate&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;country&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;per_1000_residents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csvs"&gt;&lt;code&gt;      &lt;span class="k"&gt;country&lt;/span&gt;  &lt;span class="k"&gt;per&lt;/span&gt;&lt;span class="err"&gt;_&lt;/span&gt;&lt;span class="mf"&gt;1000&lt;/span&gt;&lt;span class="err"&gt;_&lt;/span&gt;&lt;span class="k"&gt;residents&lt;/span&gt;
   &lt;span class="k"&gt;Luxembourg&lt;/span&gt;               &lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2.35&lt;/span&gt;
      &lt;span class="k"&gt;Belgium&lt;/span&gt;               &lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.27&lt;/span&gt;
       &lt;span class="k"&gt;Sweden&lt;/span&gt;               &lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.23&lt;/span&gt;
&lt;span class="err"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By rate, the hardest hit are &lt;strong&gt;Luxembourg (-2.35), Belgium (-1.27) and Sweden (-1.23)&lt;/strong&gt;. Germany, the absolute "winner," is nowhere near the top of this list, because -91,067 out of a large population is a modest per-capita rate. A big country losing a big number is not the same as a country bleeding a large share of its people.&lt;/p&gt;

&lt;p&gt;And the only two net-positive countries, the ones actually gaining native-born residents, are &lt;strong&gt;Bulgaria (+0.88) and Lithuania (+2.67)&lt;/strong&gt;, both places long framed as classic emigration stories. That is the reversal that made me want to write this up.&lt;/p&gt;

&lt;p&gt;You can see the whole flip in one frame by putting both ranks side by side:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rank_absolute&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;net_migration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rank_per_capita&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;per_1000_residents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;flip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort_values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;net_migration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;country&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;net_migration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;per_1000_residents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rank_absolute&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rank_per_capita&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Germany sits at rank 1 by absolute loss and drops far down the per-capita rank. Luxembourg does the opposite. Same data, two honest stories, and the one you tell depends only on which column you sort.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data and method
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scope:&lt;/strong&gt; 19 European countries, native-born residents, net migration for 2024. Negative values mean a net loss.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two views:&lt;/strong&gt; raw count (&lt;code&gt;net_migration&lt;/code&gt;) and population-normalized rate (&lt;code&gt;per_1000_residents&lt;/code&gt;). The point of the piece is that these are not interchangeable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open dataset (CC BY 4.0):&lt;/strong&gt; the full CSVs live in the &lt;a href="https://github.com/DatapulseResearch/brain-drain-eu" rel="noopener noreferrer"&gt;DatapulseResearch brain-drain-eu repository on GitHub&lt;/a&gt;. A second file, &lt;a href="https://raw.githubusercontent.com/DatapulseResearch/brain-drain-eu/main/data/german_emigrant_destinations_2024.csv" rel="noopener noreferrer"&gt;german_emigrant_destinations_2024.csv&lt;/a&gt;, breaks the German outflow down by destination country if you want to go a level deeper.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source study:&lt;/strong&gt; the full analysis, charts and methodology are in &lt;a href="https://www.datapulse.de/brain-drain-eu/" rel="noopener noreferrer"&gt;Brain Drain in Europe 2024 by DataPulse&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Takeaway for anyone working with data
&lt;/h2&gt;

&lt;p&gt;This is a clean, small example of a trap that scales to almost any comparative dataset: the metric picks the winner. "Most X in total" and "highest rate of X" answer different questions, and a chart that only shows one of them is not wrong, it is just incomplete. When you see a country-ranking headline, the first thing worth asking is whether it was normalized, because normalizing here does not shade the story, it inverts it.&lt;/p&gt;

&lt;p&gt;The data is right there in the repo. Clone it, re-sort it, and check whether your own intuition survives the per-capita column. Mine did not.&lt;/p&gt;

</description>
      <category>dataanalysis</category>
      <category>opendata</category>
      <category>python</category>
      <category>datavisualization</category>
    </item>
    <item>
      <title>The Bosman Effect, in one open dataset: how World Cup squads went global (1990 to 2026)</title>
      <dc:creator>Maria-Luise Volkmar</dc:creator>
      <pubDate>Wed, 24 Jun 2026 11:52:44 +0000</pubDate>
      <link>https://dev.to/mlvolkmar/the-bosman-effect-in-one-open-dataset-how-world-cup-squads-went-global-1990-to-2026-5hk8</link>
      <guid>https://dev.to/mlvolkmar/the-bosman-effect-in-one-open-dataset-how-world-cup-squads-went-global-1990-to-2026-5hk8</guid>
      <description>&lt;p&gt;In 1990, roughly one in four players at the FIFA World Cup was based at a club outside the country his national team represented. At the 2026 edition it is nearly three in four. That is a structural shift in a labour market, and it has a surprisingly precise cause: a 1995 court ruling.&lt;/p&gt;

&lt;p&gt;I pulled the squad data together, cleaned it into a small CSV, and put it on GitHub under CC BY 4.0 so anyone can check the trend or build on it. This post walks through what the data shows and how to reproduce the headline chart in a few lines of Python.&lt;/p&gt;

&lt;h2&gt;
  
  
  The headline number
&lt;/h2&gt;

&lt;p&gt;Share of foreign-based players across World Cup squads:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Foreign-based share&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1990&lt;/td&gt;
&lt;td&gt;26.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2002&lt;/td&gt;
&lt;td&gt;38.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2014&lt;/td&gt;
&lt;td&gt;53.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026&lt;/td&gt;
&lt;td&gt;72.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The inflection point is the &lt;strong&gt;Bosman ruling&lt;/strong&gt; (European Court of Justice, 15 December 1995, Case C-415/93), which abolished EU limits on foreign players and allowed free transfers at contract end. Professional footballers became, legally, ordinary workers with the right to work anywhere in the single market.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reproduce it
&lt;/h2&gt;

&lt;p&gt;The dataset is two CSVs. Loading the time series straight from GitHub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://raw.githubusercontent.com/DatapulseResearch/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;world-cup-players-abroad/main/data/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;world_cup_squads_foreign_based_share_1990_2026.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;year&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;foreign_based_share_percent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;marker&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;o&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;legend&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Foreign-based players in World Cup squads, 1990 to 2026&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;% of squad based abroad&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;axvline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1995&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;linestyle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alpha&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Bosman
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One line and you can see the post-1995 climb.&lt;/p&gt;

&lt;h2&gt;
  
  
  The counterintuitive part
&lt;/h2&gt;

&lt;p&gt;You might expect the strongest nations to export the most players. The opposite is true. The 2026 per-country table (&lt;code&gt;world_cup_2026_foreign_based_by_country.csv&lt;/code&gt;) shows the strongest domestic leagues keep their talent at home:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Nation&lt;/th&gt;
&lt;th&gt;Foreign-based share, 2026&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Switzerland&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Argentina&lt;/td&gt;
&lt;td&gt;94%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Brazil&lt;/td&gt;
&lt;td&gt;89%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;France&lt;/td&gt;
&lt;td&gt;83%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Germany&lt;/td&gt;
&lt;td&gt;33%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;England&lt;/td&gt;
&lt;td&gt;22%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;England and Germany, with the strongest leagues, retain the most. Talent follows the biggest market, not the passport.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data and method
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;"Foreign-based" = a squad member under contract at a club outside his national team's country at tournament time.&lt;/li&gt;
&lt;li&gt;Sources: player citizenship and club affiliation from transfermarkt.de; FIFA World Cup squad lists.&lt;/li&gt;
&lt;li&gt;Dataset: &lt;a href="https://github.com/DatapulseResearch/world-cup-players-abroad" rel="noopener noreferrer"&gt;https://github.com/DatapulseResearch/world-cup-players-abroad&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Full analysis with all charts: &lt;a href="https://www.finalarm.de/studies/world-cup-players-abroad" rel="noopener noreferrer"&gt;https://www.finalarm.de/studies/world-cup-players-abroad&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you do something with the data (a different cut, a model, a better chart), I would love to see it in the comments.&lt;/p&gt;

</description>
      <category>dataanalysis</category>
      <category>opendata</category>
      <category>python</category>
      <category>datavisualization</category>
    </item>
    <item>
      <title>Why there is no single best 'workation' city: a three-way ranking, with open data</title>
      <dc:creator>Maria-Luise Volkmar</dc:creator>
      <pubDate>Fri, 19 Jun 2026 11:34:47 +0000</pubDate>
      <link>https://dev.to/mlvolkmar/why-there-is-no-single-best-workation-city-a-three-way-ranking-with-open-data-7nm</link>
      <guid>https://dev.to/mlvolkmar/why-there-is-no-single-best-workation-city-a-three-way-ranking-with-open-data-7nm</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo84msvmrq01hkgtntvny.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo84msvmrq01hkgtntvny.jpg" alt=" " width="799" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most "best cities for remote work" lists make the same mistake: they hand you one ranking. But the best workation destination is not a single answer, because the constraints are completely different depending on who you are. A freelancer can fly to Bali and stay six months. An employee is tied to a contract, social-insurance rules, and tax thresholds.&lt;/p&gt;

&lt;p&gt;So I built three rankings instead of one, and open-sourced the underlying data (CC BY 4.0) so you can re-weight it for your own situation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Germany really wants this
&lt;/h2&gt;

&lt;p&gt;One number stood out while gathering the search data: &lt;strong&gt;Germany accounts for 52% of all global "workation" searches&lt;/strong&gt;, by far the largest share worldwide.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Country&lt;/th&gt;
&lt;th&gt;Share of global "workation" searches&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Germany&lt;/td&gt;
&lt;td&gt;52%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rest of the World&lt;/td&gt;
&lt;td&gt;30%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Poland&lt;/td&gt;
&lt;td&gt;6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;India&lt;/td&gt;
&lt;td&gt;5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Netherlands&lt;/td&gt;
&lt;td&gt;5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;United States&lt;/td&gt;
&lt;td&gt;3%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://raw.githubusercontent.com/DatapulseResearch/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;workation-atlas/main/data/workation_search_share_by_country.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;sort_values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;share_of_global_workation_searches_percent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ascending&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;barh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;country&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;share_of_global_workation_searches_percent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;legend&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Global share of &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;workation&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; searches&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Three rankings, three winners
&lt;/h2&gt;

&lt;p&gt;Each ranking weights climate, cost of living, flight prices, infrastructure, safety, and (for employees) EU membership differently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Adventure Seeker&lt;/strong&gt; (freelancers and founders): Bangkok, Kuala Lumpur, Chiang Mai, Da Nang, Ubud.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart Spender&lt;/strong&gt; (best value per euro): Jaipur, Bangkok, Da Nang, Chennai, Weligama.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy Mover&lt;/strong&gt; (employees, EU-only): Seville, Ericeira, Valencia, Faro, Rome.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rankings barely overlap. Asia dominates the freelancer lists; EU/Southern Europe wins for employees, who in practice need an A1 certificate to stay in their home social-insurance system and have to watch the 183-day tax threshold. Bureaucracy, not preference, is what separates the lists.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ranks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://raw.githubusercontent.com/DatapulseResearch/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;workation-atlas/main/data/workation_city_rankings_top5.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ranks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rank&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ranking&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;city&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Data and method
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Rankings weight climate, cost of living, flights, infrastructure, safety, and EU/EFTA membership differently per traveller type.&lt;/li&gt;
&lt;li&gt;Search demand from Ahrefs global keyword data; analysis by DataPulse Research.&lt;/li&gt;
&lt;li&gt;Dataset: &lt;a href="https://github.com/DatapulseResearch/workation-atlas" rel="noopener noreferrer"&gt;https://github.com/DatapulseResearch/workation-atlas&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Full study with methodology: &lt;a href="https://www.datapulse.de/en/workation-atlas" rel="noopener noreferrer"&gt;https://www.datapulse.de/en/workation-atlas&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What would your weighting be? Fork the CSV and post your own top 5 in the comments.&lt;/p&gt;

</description>
      <category>dataanalysis</category>
      <category>opendata</category>
      <category>remotework</category>
      <category>trends</category>
    </item>
  </channel>
</rss>
