Skip to content

View or edit on GitHub

This page is synchronized from trase/products/analysis/notebooks/qa/brazil_soy_2023_24/bol_mdic_matching_check.md. Last modified on 2026-08-05 15:56 CEST by Harry Biddle. Please view or edit the original file there; changes should be reflected here after a midnight build (CET time), or manually triggering it with a GitHub action (link).

Brazil soy: matching Bills of Lading to MDIC/SECEX on region & port

group

This notebook is a data-quality check of the two custom fields we added to both the Brazil Bill-of-Lading (BOL) dataset and the MDIC/SECEX customs export dataset so that the two can be matched:

  • mdic_bol_region_of_destination — the destination country mapped to a broad world region.
  • mdic_bol_port_group — the export port mapped to a named port group / complex.

Both columns are derived from a single shared, hard-coded crosswalk, trase/data/brazil/trade/mdic_bol_matching.py, so the two datasets use identical labels and can be joined directly. This notebook summarises what the columns contain and quantifies how well BOL and MDIC agree on the distribution of soybean export volume across each dimension.

Motivation for introducing regions and port groups

Both sources already record a destination country and an export port — but they define these differently, so matching on the raw fields is unreliable:

  • Country of destination. BOL records the documented shipment destination — which may be a port of discharge, the consignee’s country, or an intermediate transshipment hub — whereas MDIC records the customs-declared destination. Grouping destinations into broad world regions absorbs most of this transshipment / consignee noise.
  • Export port / customs unit. BOL records the maritime port of export (from Datamar), whereas MDIC records the customs unit (URF) that cleared the goods — a different concept that often carries a different name for the same physical complex (e.g. BOL’s BARCARENA vs MDIC’s BELEM). Grouping both into named port complexes harmonises these.

mdic_bol_region_of_destination and mdic_bol_port_group are the resulting harmonised, lower-cardinality columns. The section How well do BOL and MDIC match? quantifies how much matching on them improves over matching on the raw country and port.

Datasets

Object Version ID Last modified
s3://trase-storage/brazil/trade/bol/2023/gold/brazil_bol_2023_gold.parquet ACfJ9lqXsWG3zBOm2upDcpKsfpaemv6R 2026-06-29 19:23:07 UTC
s3://trase-storage/brazil/trade/mdic/port/brazil_mdic_port_2023.parquet E39iN8kUCDr.ewQdq1yT8Zurt_VyG91J 2026-06-29 19:23:20 UTC
  • BOL is the cleaned “gold” Bill-of-Lading dataset. Each row is a maritime export shipment. Volume is net_weight_tonnes — the product weight of the merchandise as shipped (not soybean-equivalent).
  • MDIC/SECEX is the processed port-level customs export dataset. Volume is vol (KG_LIQUIDO, net kilograms of product), which we divide by 1000 to get tonnes.

Filtering to a like-for-like soybean slice

We restrict to soybeans (HS4 1201; cake and oil are excluded). We filter BOL to that HS4, then filter MDIC to whichever HS6 codes appear in the BOL soybean slice, and to maritime trade only (via = "01") — because BOL only covers maritime shipments.

The two sources report similar but not identical totals for this slice — they are independent measurements, so we do not expect them to agree exactly. The agreement metrics further down are deliberately insensitive to this absolute-volume gap.

Value
BOL soybean total (t) 94,396,388
MDIC soybean total (t) 99,906,130
BOL / MDIC ratio 0.945

The two sources label soybeans with different HS6 codes

A finding worth flagging: the two sources use different HS6 nomenclatures for soybeans. The BOL (Datamar) data still uses the pre-2022 code 120100, whereas MDIC 2023 uses the HS2022 code 120190. Filtering MDIC by BOL’s HS6 set works here only because the BOL data also carries a handful of 120190 rows, so 120190 is in the set. The tables below show the product-tonne split by HS6 in each source.

HS6 BOL (t) MDIC (t)
120100 94,305,741 0
120190 90,578 99,905,935
120110 69 195

What the two columns contain

Region of destination

mdic_bol_region_of_destination groups the destination country into a broad world region. Here is the soybean product volume in each region, from each source, with each source’s share of its own total.

Region BOL (t) MDIC (t) BOL % MDIC %
Asia 76,157,591 81,635,503 80.7 81.7
Europe 8,232,184 7,409,718 8.7 7.4
Middle East 4,279,699 4,976,104 4.5 5.0
Americas 3,935,487 4,490,932 4.2 4.5
Africa 1,494,528 1,393,873 1.6 1.4
Oceania 32,999 0 0.0 0.0
Unknown 263,900 0 0.3 0.0

Port group

mdic_bol_port_group groups the export port into a named port complex. On the BOL side it is keyed on the port-of-export name; on the MDIC side on the customs unit (URF). A few groups deliberately unify the different spellings the two sources use for the same physical complex — most notably Belém (the BOL data calls it BARCARENA, MDIC calls it BELEM) and Açu (BOL PORTO ACU, MDIC IRF CAMPOS DOS GOYTACAZES).

Port group BOL (t) MDIC (t) BOL % MDIC %
Santos 28,110,515 30,560,637 29.8 30.6
Paranaguá 14,173,875 14,314,237 15.0 14.3
São Luís 12,514,720 12,921,919 13.3 12.9
Rio Grande 9,200,251 10,467,891 9.7 10.5
Belém 9,858,110 10,285,218 10.4 10.3
São Francisco do Sul 4,845,958 5,031,110 5.1 5.0
Salvador 4,248,341 4,166,081 4.5 4.2
Vitória 3,933,145 4,130,754 4.2 4.1
Manaus 3,361,884 4,020,480 3.6 4.0
Santarém 3,002,335 2,999,501 3.2 3.0
Santana 439,108 408,227 0.5 0.4
Imbituba 524,480 307,616 0.6 0.3
Aracaju 156,098 161,098 0.2 0.2
Açu 27,500 97,937 0.0 0.1
Porto Murtinho 0 33,423 0.0 0.0
Rio de Janeiro 0 0 0.0 0.0
Porto Alegre 0 0 0.0 0.0
São Sebastião 69 0 0.0 0.0
Itajaí 0 0 0.0 0.0

How well do BOL and MDIC match?

We measure agreement as the histogram intersection of the two volume-share distributions. For a set of buckets (e.g. each region), let $p_i$ be BOL’s share of its own total soybean volume in bucket $i$ and $q_i$ be MDIC’s. Then

$$\text{agreement} = \sum_i \min(p_i, q_i).$$

This is the share of volume that both sources place in the same bucket; its complement is the share that would have to be reallocated to make the two distributions identical. It is scale-free: even though absolute totals differ by about 6% (BOL 94.4 Mt vs MDIC 99.9 Mt), the agreement metric is deliberately insensitive to this.

Grouping improves the match

The point of the two new columns is that matching on them is more robust than matching on the raw destination country or export port. The table below reports the agreement — and the number of buckets — when we match on each raw field versus its grouped counterpart.

Match on Buckets Agreement (%)
Destination country (raw) 65 87.6
→ Region of destination (grouped) 7 98.2
Export port (raw) 21 87.8
→ Port group (harmonised) 19 97.9

Both grouped columns lift agreement by roughly ten percentage points. For country, the gain comes from collapsing the ~65 destination countries — which the two sources often disagree on because of transshipment and consignee conventions — into a handful of regions. For port, the gain is almost entirely from harmonisation rather than fewer buckets (the count barely changes): the raw names differ for the same physical complex (BOL BARCARENA ↔ MDIC BELEM; BOL PORTO ACU ↔ MDIC IRF CAMPOS DOS GOYTACAZES), and the port group unifies them.

Matched jointly on region × port group, agreement is 96.7%

— almost as high as either grouped dimension alone, so the residual disagreements in region and in port group are largely independent of one another rather than compounding.

How much did grouping collapse the categories?

Grouping reduces cardinality, but the raw unique count treats a dominant destination and a negligible one alike — collapsing ten tiny ports into one is very different from merging two large ones. So we also report an effective count: the Hill number of order 2 (inverse Simpson index, $1 / \sum_i p_i^2$), which weights each value by its share of volume and gives the effective number of equally-sized categories. It only falls materially when volume-bearing categories are merged. We report both, on each dataset, for each mapping.

Dataset Mapping Unique (raw) Unique (grouped) Effective (raw) Effective (grouped)
BOL Country → region 53 7 2.2 1.5
BOL Port → port group 16 15 6.4 6.3
MDIC Country → region 56 6 1.8 1.5
MDIC Port → port group 19 19 6.2 6.2

The contrast is the point. Country → region slashes the unique count (BOL 53 → 7) yet the effective count barely moves (≈2.2 → 1.5): soybean exports are so concentrated on a handful of destinations (China above all) that the dozens of countries folded away carried almost no volume. Port → port group moves neither count much — its value is harmonisation (relabelling BOL’s BARCARENA as BELEM so it lines up with MDIC), not the consolidation of large ports. In short, the unique count overstates how much the region grouping “loses”, while the effective count shows the real, volume-weighted change is small — which is exactly why the grouped columns match so well without discarding meaningful resolution.

Where the small differences are

The dumbbell charts below show each source’s share of soybean volume per bucket, so the totals gap is removed and only the distribution is compared. A perfectly matched bucket has its two dots on top of one another.

Takeaways

  • The two custom columns line up very well: BOL and MDIC agree on roughly 98% of soybean volume by destination region and 98% by port group, on identical labels and with no crosswalk needed at read time.
  • This is a clear improvement over matching on the raw fields (88% on destination country, 88% on export port) — grouping absorbs the differing country concepts and harmonises the differing port/customs-unit names, which is exactly why the columns were added.
  • Watch the HS6 nomenclature difference (BOL 120100 vs MDIC 120190): the soybean slice only lines up because we filter MDIC by the BOL HS6 set and BOL happens to carry both codes. If the BOL source ever drops its 120190 rows, this filter would silently exclude the bulk of MDIC soybeans.

Appendix: the full mappings

For reference, the complete crosswalks from trase/data/brazil/trade/mdic_bol_matching.py. Note these are the entire mappings (all commodities and destinations), not just the soybean slice used above.

Country → region

Every destination country (by Trase id / ISO 3166-1 alpha-2) mapped to its world region.

Region # countries Countries
Africa 56 Algeria, Angola, Benin, Burkina Faso, Burundi, Cabo Verde, Cameroon, Central African Republic (the), Chad, Comoros (the), Congo (the Democratic Republic of the), Congo (the), Côte d’Ivoire, Djibouti, Egypt, Equatorial Guinea, Eritrea, Eswatini, Ethiopia, Gabon, Gambia (the), Ghana, Guinea, Guinea-Bissau, Kenya, Liberia, Libya, Madagascar, Malawi, Mali, Mauritania, Mauritius, Mayotte, Morocco, Mozambique, Namibia, Niger (the), Nigeria, Rwanda, Réunion, Saint Helena, Ascension and Tristan da Cunha, Sao Tome and Principe, Senegal, Seychelles, Sierra Leone, Somalia, South Africa, South Sudan, Sudan (the), Tanzania, United Republic of, Togo, Tunisia, Uganda, Western Sahara, Zambia, Zimbabwe
Americas 54 Anguilla, Antigua and Barbuda, Argentina, Aruba, Bahamas (the), Barbados, Belize, Bermuda, Bolivia (Plurinational State of), Bonaire, Sint Eustatius and Saba, Brazil, Canada, Cayman Islands (the), Chile, Colombia, Costa Rica, Cuba, Curaçao, Dominica, Dominican Republic (the), Ecuador, El Salvador, Falkland Islands (the) [Malvinas], French Guiana, Greenland, Grenada, Guadeloupe, Guatemala, Guyana, Haiti, Honduras, Jamaica, Martinique, Mexico, Montserrat, Nicaragua, Panama, Paraguay, Peru, Puerto Rico, Saint Barthélemy, Saint Kitts and Nevis, Saint Lucia, Saint Martin (French part), Saint Vincent and the Grenadines, Sint Maarten (Dutch part), Suriname, Trinidad and Tobago, Turks and Caicos Islands (the), United States of America (the), Uruguay, Venezuela (Bolivarian Republic of), Virgin Islands (British), Virgin Islands (U.S.)
Europe 45 Albania, Austria, Belarus, Belgium, Bosnia and Herzegovina, Bulgaria, Croatia, Cyprus, Czechia, Denmark, EU, Estonia, Faroe Islands (the), Finland, France, Germany, Gibraltar, Greece, Hungary, Iceland, Ireland, Isle of Man, Italy, Latvia, Lithuania, Luxembourg, Malta, Moldova (the Republic of), Monaco, Montenegro, Netherlands (the), Norway, Poland, Portugal, Republic of North Macedonia, Romania, Russian Federation (the), Serbia, Slovakia, Slovenia, Spain, Sweden, Switzerland, Ukraine, United Kingdom of Great Britain and Northern Ireland (the)
Asia 35 Afghanistan, Armenia, Azerbaijan, Bangladesh, Bhutan, Brunei Darussalam, Cambodia, China, Georgia, Hong Kong, India, Indonesia, Japan, Kazakhstan, Korea (the Democratic People’s Republic of), Korea (the Republic of), Kyrgyzstan, Lao People’s Democratic Republic (the), Macao, Malaysia, Maldives, Mongolia, Myanmar, Nepal, Pakistan, Philippines (the), Singapore, Sri Lanka, Taiwan (Province of China), Tajikistan, Thailand, Timor-Leste, Turkmenistan, Uzbekistan, Viet Nam
Oceania 24 American Samoa, Australia, Cocos (Keeling) Islands (the), Cook Islands (the), Fiji, French Polynesia, Guam, Kiribati, Marshall Islands (the), Micronesia (Federated States of), Nauru, New Caledonia, New Zealand, Norfolk Island, Northern Mariana Islands (the), PU, Palau, Papua New Guinea, Pitcairn, Samoa, Tokelau, Tonga, Vanuatu, Wallis and Futuna
Middle East 15 Bahrain, Iran (Islamic Republic of), Iraq, Israel, Jordan, Kuwait, Lebanon, Oman, Palestine, State of, Qatar, Saudi Arabia, Syrian Arab Republic, Turkey, United Arab Emirates (the), Yemen
Other 1 French Southern Territories (the)
Unknown 1 XX

Export port → port group

Each port group and the raw port / customs-unit names (BOL and MDIC spellings) that map into it.

Port group # names Source names (BOL / MDIC spellings)
Aracaju 1 ARACAJU
Açu 2 IRF CAMPOS DOS GOYTACAZES, PORTO ACU
Belém 2 BARCARENA, BELEM
Cabedelo 1 CABEDELO
Corumbá 1 CORUMBA
Fortaleza 1 FORTALEZA
Imbituba 1 IMBITUBA
Itajaí 1 ITAJAI
Maceió 1 MACEIO
Manaus 1 MANAUS
Natal 1 NATAL
Niterói 1 NITEROI
Paranaguá 2 ANTONINA, PARANAGUA
Pecém 1 PECEM
Porto Alegre 1 PORTO ALEGRE
Porto Murtinho 1 PORTO MURTINHO
Porto Velho 1 PORTO VELHO
Recife 1 RECIFE
Rio Grande 1 RIO GRANDE
Rio de Janeiro 1 RIO DE JANEIRO
Salvador 1 SALVADOR
Santana 1 SANTANA
Santarém 1 SANTAREM
Santos 1 SANTOS
Suape 1 SUAPE
São Francisco do Sul 1 SAO FRANCISCO DO SUL
São Luís 1 SAO LUIS
São Sebastião 1 SAO SEBASTIAO
Vitória 1 VITORIA