dayrize-usecase/notebooks/exploration.ipynb

1476 lines
112 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

{
"cells": [
{
"cell_type": "code",
"execution_count": 3,
"id": "98ded03d-0208-4416-a5e5-720a2e0742fa",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>title</th>\n",
" <th>url</th>\n",
" <th>brand</th>\n",
" <th>main_image</th>\n",
" <th>sku</th>\n",
" <th>description</th>\n",
" <th>raw_description</th>\n",
" <th>gtin13</th>\n",
" <th>currency</th>\n",
" <th>price</th>\n",
" <th>...</th>\n",
" <th>sub_category_1</th>\n",
" <th>sub_category_2</th>\n",
" <th>sub_category_3</th>\n",
" <th>images</th>\n",
" <th>raw_specifications</th>\n",
" <th>specifications</th>\n",
" <th>highlights</th>\n",
" <th>raw_highlights</th>\n",
" <th>uniq_id</th>\n",
" <th>scraped_at</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>NMR Distribution Zoltar Fortunes Playing Cards...</td>\n",
" <td>https://www.target.com/p/nmr-distribution-zolt...</td>\n",
" <td>NMR Distribution</td>\n",
" <td>https://target.scene7.com/is/image/Target/GUES...</td>\n",
" <td>81917300</td>\n",
" <td>Zoltar the Great Gypsy can see your future… Yo...</td>\n",
" <td>&lt;div class=\"h-margin-v-default\" data-test=\"ite...</td>\n",
" <td>840391145528</td>\n",
" <td>USD</td>\n",
" <td>10.99</td>\n",
" <td>...</td>\n",
" <td>Games</td>\n",
" <td>Adult Games</td>\n",
" <td>NaN</td>\n",
" <td>https://target.scene7.com/is/image/Target/GUES...</td>\n",
" <td>&lt;div class=\"styles__StyledCol-sc-ct8kx6-0 iKGd...</td>\n",
" <td>Suggested Age: 6 Years and Up | Suggested Age:...</td>\n",
" <td>ZOLTAR CARDS: Zoltar the Great Gypsy can see y...</td>\n",
" <td>&lt;li class=\"styles__Bullet-sc-6aebpn-0 eIfLaI\"&gt;...</td>\n",
" <td>898ca3c8-8bfa-5fac-a48e-53879845cf48</td>\n",
" <td>06/12/22</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>The Gifted Stationery 2021 - 2022 Monthly Wall...</td>\n",
" <td>https://www.target.com/p/the-gifted-stationery...</td>\n",
" <td>The Gifted Stationary</td>\n",
" <td>https://target.scene7.com/is/image/Target/GUES...</td>\n",
" <td>84821007</td>\n",
" <td>16 month wall calendar provides easy planning ...</td>\n",
" <td>&lt;div class=\"h-margin-v-default\" data-test=\"ite...</td>\n",
" <td>9781801433983</td>\n",
" <td>USD</td>\n",
" <td>12.99</td>\n",
" <td>...</td>\n",
" <td>Calendars</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>https://target.scene7.com/is/image/Target/GUES...</td>\n",
" <td>&lt;div class=\"styles__StyledCol-sc-ct8kx6-0 iKGd...</td>\n",
" <td>Dimensions (Overall): 11.9 inches (L), 11.9 in...</td>\n",
" <td>16-MONTH CALENDAR: Easy planning and goal sett...</td>\n",
" <td>&lt;li class=\"styles__Bullet-sc-6aebpn-0 eIfLaI\"&gt;...</td>\n",
" <td>b7c8e8ce-55b6-529d-b52e-dbfbd70b066e</td>\n",
" <td>06/12/22</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Doctor Who: Series Three, Part Two (DVD)</td>\n",
" <td>https://www.target.com/p/doctor-who-series-thr...</td>\n",
" <td>Warner Bros.</td>\n",
" <td>https://target.scene7.com/is/image/Target/GUES...</td>\n",
" <td>15432753</td>\n",
" <td>Tenth Doctor David Tennant (Broadchurch, Harry...</td>\n",
" <td>&lt;div class=\"h-margin-v-default\" data-test=\"ite...</td>\n",
" <td>883929408115</td>\n",
" <td>USD</td>\n",
" <td>10.89</td>\n",
" <td>...</td>\n",
" <td>Movies</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>https://target.scene7.com/is/image/Target/GUES...</td>\n",
" <td>&lt;div class=\"styles__StyledCol-sc-ct8kx6-0 iKGd...</td>\n",
" <td>Movie Category: Television | Movie Category: T...</td>\n",
" <td>Run Time: 315:00 min | Disc Count: 2 | Rating:...</td>\n",
" <td>&lt;li class=\"styles__Bullet-sc-6aebpn-0 eIfLaI\"&gt;...</td>\n",
" <td>97fd83d8-e76b-5bac-999c-b734fdcafe66</td>\n",
" <td>06/12/22</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Blue Panda 75 Pieces Tie Dye Birthday Party Su...</td>\n",
" <td>https://www.target.com/p/blue-panda-75-pieces-...</td>\n",
" <td>Blue Panda</td>\n",
" <td>https://target.scene7.com/is/image/Target/GUES...</td>\n",
" <td>84199597</td>\n",
" <td>Throwing a party has never been easier, weve ...</td>\n",
" <td>&lt;div class=\"h-margin-v-default\" data-test=\"ite...</td>\n",
" <td>194425194489</td>\n",
" <td>USD</td>\n",
" <td>26.99</td>\n",
" <td>...</td>\n",
" <td>Birthday Party Supplies</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>https://target.scene7.com/is/image/Target/GUES...</td>\n",
" <td>&lt;div class=\"styles__StyledCol-sc-ct8kx6-0 iKGd...</td>\n",
" <td>Number of Pieces: 24 | Number of Pieces: 24 | ...</td>\n",
" <td>Serves 24: Includes 1 plastic table cover, a b...</td>\n",
" <td>&lt;li class=\"styles__Bullet-sc-6aebpn-0 eIfLaI\"&gt;...</td>\n",
" <td>3b4d60b0-0888-596e-babe-d9e6e4e3131c</td>\n",
" <td>06/12/22</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Sullivans Hammered Metal Wall Medallions Set o...</td>\n",
" <td>https://www.target.com/p/sullivans-hammered-me...</td>\n",
" <td>Sullivans</td>\n",
" <td>https://target.scene7.com/is/image/Target/GUES...</td>\n",
" <td>86345566</td>\n",
" <td>Bring a little charm and delight to your space...</td>\n",
" <td>&lt;div class=\"h-margin-v-default\" data-test=\"ite...</td>\n",
" <td>23271231140</td>\n",
" <td>USD</td>\n",
" <td>118.99</td>\n",
" <td>...</td>\n",
" <td>Home Decor</td>\n",
" <td>Wall Decor</td>\n",
" <td>Wall Accents</td>\n",
" <td>https://target.scene7.com/is/image/Target/GUES...</td>\n",
" <td>&lt;div class=\"styles__StyledCol-sc-ct8kx6-0 iKGd...</td>\n",
" <td>Dimensions (Overall): 23 inches (H) x 1 inches...</td>\n",
" <td>This unique wall set will be the perfect addit...</td>\n",
" <td>&lt;li class=\"styles__Bullet-sc-6aebpn-0 eIfLaI\"&gt;...</td>\n",
" <td>036188d9-4546-5952-af8f-bc234d1f8113</td>\n",
" <td>06/12/22</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>5 rows × 24 columns</p>\n",
"</div>"
],
"text/plain": [
" title \\\n",
"0 NMR Distribution Zoltar Fortunes Playing Cards... \n",
"1 The Gifted Stationery 2021 - 2022 Monthly Wall... \n",
"2 Doctor Who: Series Three, Part Two (DVD) \n",
"3 Blue Panda 75 Pieces Tie Dye Birthday Party Su... \n",
"4 Sullivans Hammered Metal Wall Medallions Set o... \n",
"\n",
" url brand \\\n",
"0 https://www.target.com/p/nmr-distribution-zolt... NMR Distribution \n",
"1 https://www.target.com/p/the-gifted-stationery... The Gifted Stationary \n",
"2 https://www.target.com/p/doctor-who-series-thr... Warner Bros. \n",
"3 https://www.target.com/p/blue-panda-75-pieces-... Blue Panda \n",
"4 https://www.target.com/p/sullivans-hammered-me... Sullivans \n",
"\n",
" main_image sku \\\n",
"0 https://target.scene7.com/is/image/Target/GUES... 81917300 \n",
"1 https://target.scene7.com/is/image/Target/GUES... 84821007 \n",
"2 https://target.scene7.com/is/image/Target/GUES... 15432753 \n",
"3 https://target.scene7.com/is/image/Target/GUES... 84199597 \n",
"4 https://target.scene7.com/is/image/Target/GUES... 86345566 \n",
"\n",
" description \\\n",
"0 Zoltar the Great Gypsy can see your future… Yo... \n",
"1 16 month wall calendar provides easy planning ... \n",
"2 Tenth Doctor David Tennant (Broadchurch, Harry... \n",
"3 Throwing a party has never been easier, weve ... \n",
"4 Bring a little charm and delight to your space... \n",
"\n",
" raw_description gtin13 currency \\\n",
"0 <div class=\"h-margin-v-default\" data-test=\"ite... 840391145528 USD \n",
"1 <div class=\"h-margin-v-default\" data-test=\"ite... 9781801433983 USD \n",
"2 <div class=\"h-margin-v-default\" data-test=\"ite... 883929408115 USD \n",
"3 <div class=\"h-margin-v-default\" data-test=\"ite... 194425194489 USD \n",
"4 <div class=\"h-margin-v-default\" data-test=\"ite... 23271231140 USD \n",
"\n",
" price ... sub_category_1 sub_category_2 sub_category_3 \\\n",
"0 10.99 ... Games Adult Games NaN \n",
"1 12.99 ... Calendars NaN NaN \n",
"2 10.89 ... Movies NaN NaN \n",
"3 26.99 ... Birthday Party Supplies NaN NaN \n",
"4 118.99 ... Home Decor Wall Decor Wall Accents \n",
"\n",
" images \\\n",
"0 https://target.scene7.com/is/image/Target/GUES... \n",
"1 https://target.scene7.com/is/image/Target/GUES... \n",
"2 https://target.scene7.com/is/image/Target/GUES... \n",
"3 https://target.scene7.com/is/image/Target/GUES... \n",
"4 https://target.scene7.com/is/image/Target/GUES... \n",
"\n",
" raw_specifications \\\n",
"0 <div class=\"styles__StyledCol-sc-ct8kx6-0 iKGd... \n",
"1 <div class=\"styles__StyledCol-sc-ct8kx6-0 iKGd... \n",
"2 <div class=\"styles__StyledCol-sc-ct8kx6-0 iKGd... \n",
"3 <div class=\"styles__StyledCol-sc-ct8kx6-0 iKGd... \n",
"4 <div class=\"styles__StyledCol-sc-ct8kx6-0 iKGd... \n",
"\n",
" specifications \\\n",
"0 Suggested Age: 6 Years and Up | Suggested Age:... \n",
"1 Dimensions (Overall): 11.9 inches (L), 11.9 in... \n",
"2 Movie Category: Television | Movie Category: T... \n",
"3 Number of Pieces: 24 | Number of Pieces: 24 | ... \n",
"4 Dimensions (Overall): 23 inches (H) x 1 inches... \n",
"\n",
" highlights \\\n",
"0 ZOLTAR CARDS: Zoltar the Great Gypsy can see y... \n",
"1 16-MONTH CALENDAR: Easy planning and goal sett... \n",
"2 Run Time: 315:00 min | Disc Count: 2 | Rating:... \n",
"3 Serves 24: Includes 1 plastic table cover, a b... \n",
"4 This unique wall set will be the perfect addit... \n",
"\n",
" raw_highlights \\\n",
"0 <li class=\"styles__Bullet-sc-6aebpn-0 eIfLaI\">... \n",
"1 <li class=\"styles__Bullet-sc-6aebpn-0 eIfLaI\">... \n",
"2 <li class=\"styles__Bullet-sc-6aebpn-0 eIfLaI\">... \n",
"3 <li class=\"styles__Bullet-sc-6aebpn-0 eIfLaI\">... \n",
"4 <li class=\"styles__Bullet-sc-6aebpn-0 eIfLaI\">... \n",
"\n",
" uniq_id scraped_at \n",
"0 898ca3c8-8bfa-5fac-a48e-53879845cf48 06/12/22 \n",
"1 b7c8e8ce-55b6-529d-b52e-dbfbd70b066e 06/12/22 \n",
"2 97fd83d8-e76b-5bac-999c-b734fdcafe66 06/12/22 \n",
"3 3b4d60b0-0888-596e-babe-d9e6e4e3131c 06/12/22 \n",
"4 036188d9-4546-5952-af8f-bc234d1f8113 06/12/22 \n",
"\n",
"[5 rows x 24 columns]"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import functools\n",
"import pandas as pd\n",
"import matplotlib.pyplot as plt\n",
"%matplotlib widget\n",
"from IPython.display import display, HTML\n",
"\n",
"in_file = \"/home/jovyan/data/large_target_store_products_dataset_sample - large_target_store_products_dataset_sample.csv\"\n",
"data = pd.read_csv(in_file)\n",
"data.head()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "c20c14ea-9ef6-4d40-8b7d-4731d0866239",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Index(['title', 'url', 'brand', 'main_image', 'sku', 'description',\n",
" 'raw_description', 'gtin13', 'currency', 'price', 'availability',\n",
" 'availableDeliveryMethod', 'available_branch', 'primary_category',\n",
" 'sub_category_1', 'sub_category_2', 'sub_category_3', 'images',\n",
" 'raw_specifications', 'specifications', 'highlights', 'raw_highlights',\n",
" 'uniq_id', 'scraped_at'],\n",
" dtype='object')"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data.axes[1]"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "165723d1-8152-4e30-b25a-cbca7f4935f9",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div class=\"styles__StyledCol-sc-ct8kx6-0 iKGdHS h-padding-h-tight\" data-test=\"item-details-specifications\"><h3 class=\"h-text-bs h-margin-b-tight\">Specifications</h3><div><div><b>Suggested Age:</b> 6 Years and Up</div><hr/></div><div><div><b>CPSC Choking Hazard Warnings:</b> Choking_hazard_small_parts</div><hr/></div><div><b>TCIN</b>: <!-- -->81917300<hr/></div><div><b>UPC</b>: <!-- -->840391145528<hr/></div><div><b>Origin</b>: <!-- -->imported<hr/></div><div data-test=\"itemDetailsTabMarketplaceMessage\"><p class=\"h-padding-t-x2\">The above item details were provided by the Target Plus™ Partner. Target does not represent or warrant that this information is accurate or complete. On occasion, manufacturers may modify their items and update their labels.</p><p class=\"h-padding-t-x2\">We recommend that you do not rely solely on the information presented. If you have a specific question about this item, you may consult the item's label, contact the manufacturer directly or call Target Guest Services at 1-800-591-3869.</p></div></div>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"def render_html(html: str):\n",
" \"\"\"Render an html string\"\"\"\n",
" display(HTML(html))\n",
"\n",
"render_html(data.loc[0, 'raw_specifications'])"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "d153a732-f18c-4fb7-9282-9c02c49c3cc0",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div class=\"styles__StyledCol-sc-ct8kx6-0 iKGdHS h-padding-h-tight\" data-test=\"item-details-specifications\"><h3 class=\"h-text-bs h-margin-b-tight\">Specifications</h3><div><div><b>Dimensions (Overall):</b> 11.9 inches (L), 11.9 inches (W)</div><hr/></div><div><div><b>Dated format:</b> Monthly</div><hr/></div><div><div><b>Calendar year:</b> 2022</div><hr/></div><div><div><b>Material:</b> Paper</div><hr/></div><div><b>TCIN</b>: <!-- -->84821007<hr/></div><div><b>UPC</b>: <!-- -->9781801433983<hr/></div><div><b>Origin</b>: <!-- -->imported<hr/></div><div data-test=\"itemDetailsTabMarketplaceMessage\"><p class=\"h-padding-t-x2\">The above item details were provided by the Target Plus™ Partner. Target does not represent or warrant that this information is accurate or complete. On occasion, manufacturers may modify their items and update their labels.</p><p class=\"h-padding-t-x2\">We recommend that you do not rely solely on the information presented. If you have a specific question about this item, you may consult the item's label, contact the manufacturer directly or call Target Guest Services at 1-800-591-3869.</p></div></div>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"def look_for_matches(data: pd.DataFrame, pattern: str, colname : str = \"raw_specifications\") -> str:\n",
" \"\"\"Useful for finding cells in raw_specifications containing a given string\"\"\"\n",
" return data.loc[data.loc[:, colname].str.contains(pattern), colname].iloc[0]\n",
"\n",
"render_html(look_for_matches(data, \"Material\"))"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "b06e66af-e0e3-466c-8797-546d5e076f32",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div class=\"styles__StyledCol-sc-ct8kx6-0 iKGdHS h-padding-h-tight\" data-test=\"item-details-specifications\"><h3 class=\"h-text-bs h-margin-b-tight\">Specifications</h3><div><div><b>Contains:</b> Does Not Contain Any of the 8 Major Allergens</div><hr/></div><div><div><b>Dietary Needs:</b> Gluten Free</div><hr/></div><div><div><b>Form:</b> Pieces</div><hr/></div><div><div><b>State of Readiness:</b> Ready to Eat</div><hr/></div><div><div><b>Package Quantity:</b> 1</div><hr/></div><div><div><b>Net weight:</b> 15.6 Ounces</div><hr/></div><div><b>TCIN</b>: <!-- -->54571204<hr/></div><div><b>UPC</b>: <!-- -->022000279729<hr/></div><div><b>Item Number (DPCI)</b>: <!-- -->055-02-1211<hr/></div><div><b>Origin</b>: <!-- -->Made in the USA or Imported<hr/></div><div><b>Grocery Disclaimer</b>:<!-- --> <div>Content on this site is for reference purposes only. Target does not represent or warrant that the nutrition, ingredient, allergen and other product information on our Web or Mobile sites are accurate or complete, since this information comes from the product manufacturers. On occasion, manufacturers may improve or change their product formulas and update their labels. We recommend that you do not rely solely on the information presented on our Web or Mobile sites and that you review the product's label or contact the manufacturer directly if you have specific product concerns or questions. If you have specific healthcare concerns or questions about the products displayed, please contact your licensed healthcare professional for advice or answers. Any additional pictures are suggested servings only.</div></div></div>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"render_html(look_for_matches(data, \"Package\"))"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "015a0d99-b4c2-47cf-9e23-59485a450470",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div class=\"styles__StyledCol-sc-ct8kx6-0 iKGdHS h-padding-h-tight\" data-test=\"item-details-specifications\"><h3 class=\"h-text-bs h-margin-b-tight\">Specifications</h3><div><div><b>Dimensions (Overall):</b> 23 inches (H) x 1 inches (W) x 23 inches (D)</div><hr/></div><div><div><b>Weight:</b> 4.65 pounds</div><hr/></div><div><div><b>Art subject:</b> Geometric Shapes</div><hr/></div><div><div><b>Orientation:</b> Vertical</div><hr/></div><div><div><b>Material:</b> Metal</div><hr/></div><div><div><b>Battery:</b> No Battery Used</div><hr/></div><div><b>TCIN</b>: <!-- -->86345566<hr/></div><div><b>UPC</b>: <!-- -->023271231140<hr/></div><div><b>Origin</b>: <!-- -->imported<hr/></div><div data-test=\"itemDetailsTabMarketplaceMessage\"><p class=\"h-padding-t-x2\">The above item details were provided by the Target Plus™ Partner. Target does not represent or warrant that this information is accurate or complete. On occasion, manufacturers may modify their items and update their labels.</p><p class=\"h-padding-t-x2\">We recommend that you do not rely solely on the information presented. If you have a specific question about this item, you may consult the item's label, contact the manufacturer directly or call Target Guest Services at 1-800-591-3869.</p></div></div>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"render_html(look_for_matches(data, \"Weight\"))"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "99cbfba8-4324-4d2a-b2e2-d766a5e57964",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div class=\"styles__StyledCol-sc-ct8kx6-0 iKGdHS h-padding-h-tight\" data-test=\"item-details-specifications\"><h3 class=\"h-text-bs h-margin-b-tight\">Specifications</h3><div><div><b>Dimensions (Overall):</b> 11.9 inches (L), 11.9 inches (W)</div><hr/></div><div><div><b>Dated format:</b> Monthly</div><hr/></div><div><div><b>Calendar year:</b> 2022</div><hr/></div><div><div><b>Material:</b> Paper</div><hr/></div><div><b>TCIN</b>: <!-- -->84821007<hr/></div><div><b>UPC</b>: <!-- -->9781801433983<hr/></div><div><b>Origin</b>: <!-- -->imported<hr/></div><div data-test=\"itemDetailsTabMarketplaceMessage\"><p class=\"h-padding-t-x2\">The above item details were provided by the Target Plus™ Partner. Target does not represent or warrant that this information is accurate or complete. On occasion, manufacturers may modify their items and update their labels.</p><p class=\"h-padding-t-x2\">We recommend that you do not rely solely on the information presented. If you have a specific question about this item, you may consult the item's label, contact the manufacturer directly or call Target Guest Services at 1-800-591-3869.</p></div></div>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"render_html(look_for_matches(data, \"Dimensions\"))"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "6c05e1db-7181-422e-924b-e67a28886abe",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div class=\"styles__StyledCol-sc-ct8kx6-0 iKGdHS h-padding-h-tight\" data-test=\"item-details-specifications\"><h3 class=\"h-text-bs h-margin-b-tight\">Specifications</h3><div><div><b>Suggested Age:</b> 6 Years and Up</div><hr/></div><div><div><b>CPSC Choking Hazard Warnings:</b> Choking_hazard_small_parts</div><hr/></div><div><b>TCIN</b>: <!-- -->81917300<hr/></div><div><b>UPC</b>: <!-- -->840391145528<hr/></div><div><b>Origin</b>: <!-- -->imported<hr/></div><div data-test=\"itemDetailsTabMarketplaceMessage\"><p class=\"h-padding-t-x2\">The above item details were provided by the Target Plus™ Partner. Target does not represent or warrant that this information is accurate or complete. On occasion, manufacturers may modify their items and update their labels.</p><p class=\"h-padding-t-x2\">We recommend that you do not rely solely on the information presented. If you have a specific question about this item, you may consult the item's label, contact the manufacturer directly or call Target Guest Services at 1-800-591-3869.</p></div></div>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"render_html(look_for_matches(data, \"TCIN\"))"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "bf3a07d9-11c0-48c4-be03-373a3ba5f755",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div class=\"styles__StyledCol-sc-ct8kx6-0 iKGdHS h-padding-h-tight\" data-test=\"item-details-specifications\"><h3 class=\"h-text-bs h-margin-b-tight\">Specifications</h3><div><div><b>Suggested Age:</b> 6 Years and Up</div><hr/></div><div><div><b>CPSC Choking Hazard Warnings:</b> Choking_hazard_small_parts</div><hr/></div><div><b>TCIN</b>: <!-- -->81917300<hr/></div><div><b>UPC</b>: <!-- -->840391145528<hr/></div><div><b>Origin</b>: <!-- -->imported<hr/></div><div data-test=\"itemDetailsTabMarketplaceMessage\"><p class=\"h-padding-t-x2\">The above item details were provided by the Target Plus™ Partner. Target does not represent or warrant that this information is accurate or complete. On occasion, manufacturers may modify their items and update their labels.</p><p class=\"h-padding-t-x2\">We recommend that you do not rely solely on the information presented. If you have a specific question about this item, you may consult the item's label, contact the manufacturer directly or call Target Guest Services at 1-800-591-3869.</p></div></div>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"render_html(look_for_matches(data, \"Origin\"))"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "3853dd07-1977-44c6-bc97-2ecdaa98980e",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"raw_specifications\n",
"False 124\n",
"True 43\n",
"Name: count, dtype: int64"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"colname = \"raw_specifications\"\n",
"patterns = [\"Material\", \"Package Quantity\", \"Weight\", \"Dimensions\", \"TCIN\", \"Origin\"]\n",
"\n",
"(data.loc[:, colname].str.contains(\"Package Quantity\") | data.loc[:, colname].str.contains(\"Number of Pieces\")).value_counts()\n",
"\n",
"# Package Quantity and Number of Pieces are never found together. Maybe they refer to the same thing?"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "be8a7628-9199-4f25-a533-d041a7ff540c",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>title</th>\n",
" <th>url</th>\n",
" <th>brand</th>\n",
" <th>main_image</th>\n",
" <th>sku</th>\n",
" <th>description</th>\n",
" <th>raw_description</th>\n",
" <th>gtin13</th>\n",
" <th>currency</th>\n",
" <th>price</th>\n",
" <th>...</th>\n",
" <th>sub_category_1</th>\n",
" <th>sub_category_2</th>\n",
" <th>sub_category_3</th>\n",
" <th>images</th>\n",
" <th>raw_specifications</th>\n",
" <th>specifications</th>\n",
" <th>highlights</th>\n",
" <th>raw_highlights</th>\n",
" <th>uniq_id</th>\n",
" <th>scraped_at</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>NCAA Illinois Fighting Illini Circo Cheese Cut...</td>\n",
" <td>https://www.target.com/p/ncaa-illinois-fightin...</td>\n",
" <td>NCAA</td>\n",
" <td>https://target.scene7.com/is/image/Target/GUES...</td>\n",
" <td>79646040</td>\n",
" <td>Reach out to the complex cheese lover in your ...</td>\n",
" <td>&lt;div class=\"h-margin-v-default\" data-test=\"ite...</td>\n",
" <td>99967205276</td>\n",
" <td>USD</td>\n",
" <td>58.95</td>\n",
" <td>...</td>\n",
" <td>Sports Fan Shop</td>\n",
" <td>Sports Fan Shop Home Goods</td>\n",
" <td>Sports Fan Shop Barware &amp; Drinkware</td>\n",
" <td>https://target.scene7.com/is/image/Target/GUES...</td>\n",
" <td>&lt;div class=\"styles__StyledCol-sc-ct8kx6-0 iKGd...</td>\n",
" <td>Number of Pieces: 5 | Number of Pieces: 5 | We...</td>\n",
" <td>BEAUTY &amp; ELEGANCE - The Circo swivel-style cir...</td>\n",
" <td>&lt;li class=\"styles__Bullet-sc-6aebpn-0 eIfLaI\"&gt;...</td>\n",
" <td>0c549116-75c8-56cb-8877-165380d0efd9</td>\n",
" <td>06/12/22</td>\n",
" </tr>\n",
" <tr>\n",
" <th>13</th>\n",
" <td>Blue Panda Jumbo Dinosaur Floor Puzzle, Double...</td>\n",
" <td>https://www.target.com/p/blue-panda-jumbo-dino...</td>\n",
" <td>Blue Panda</td>\n",
" <td>https://target.scene7.com/is/image/Target/GUES...</td>\n",
" <td>80405355</td>\n",
" <td>Package Includes\\r\\nLarge Dinosaur Floor Puzzl...</td>\n",
" <td>&lt;div class=\"h-margin-v-default\" data-test=\"ite...</td>\n",
" <td>194425203808</td>\n",
" <td>USD</td>\n",
" <td>19.99</td>\n",
" <td>...</td>\n",
" <td>Puzzles</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>https://target.scene7.com/is/image/Target/GUES...</td>\n",
" <td>&lt;div class=\"styles__StyledCol-sc-ct8kx6-0 iKGd...</td>\n",
" <td>Number of Pieces: 17 | Number of Pieces: 17 | ...</td>\n",
" <td>JUMBO DINOSAUR PUZZLE: This t-rex foam puzzle ...</td>\n",
" <td>&lt;li class=\"styles__Bullet-sc-6aebpn-0 eIfLaI\"&gt;...</td>\n",
" <td>151c72b4-4856-502f-a508-961cc81fffa9</td>\n",
" <td>06/12/22</td>\n",
" </tr>\n",
" <tr>\n",
" <th>14</th>\n",
" <td>Women's Round Aviator Sunglasses - Universal T...</td>\n",
" <td>https://www.target.com/p/women-39-s-round-avia...</td>\n",
" <td>Universal Thread</td>\n",
" <td>https://target.scene7.com/is/image/Target/GUES...</td>\n",
" <td>84201225</td>\n",
" <td>Round out your eyewear collection with the Rou...</td>\n",
" <td>&lt;div class=\"h-margin-v-default\" data-test=\"ite...</td>\n",
" <td>195995526496</td>\n",
" <td>USD</td>\n",
" <td>15.00</td>\n",
" <td>...</td>\n",
" <td>Eye Care</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>https://target.scene7.com/is/image/Target/GUES...</td>\n",
" <td>&lt;div class=\"styles__StyledCol-sc-ct8kx6-0 iKGd...</td>\n",
" <td>Material: Metal (Frame) | Material: Metal (Fra...</td>\n",
" <td>Universal Thread round aviator sunglasses with...</td>\n",
" <td>&lt;li class=\"styles__Bullet-sc-6aebpn-0 eIfLaI\"&gt;...</td>\n",
" <td>2a803c0f-00bf-50a6-a490-d381620ac3a3</td>\n",
" <td>06/12/22</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>3 rows × 24 columns</p>\n",
"</div>"
],
"text/plain": [
" title \\\n",
"8 NCAA Illinois Fighting Illini Circo Cheese Cut... \n",
"13 Blue Panda Jumbo Dinosaur Floor Puzzle, Double... \n",
"14 Women's Round Aviator Sunglasses - Universal T... \n",
"\n",
" url brand \\\n",
"8 https://www.target.com/p/ncaa-illinois-fightin... NCAA \n",
"13 https://www.target.com/p/blue-panda-jumbo-dino... Blue Panda \n",
"14 https://www.target.com/p/women-39-s-round-avia... Universal Thread \n",
"\n",
" main_image sku \\\n",
"8 https://target.scene7.com/is/image/Target/GUES... 79646040 \n",
"13 https://target.scene7.com/is/image/Target/GUES... 80405355 \n",
"14 https://target.scene7.com/is/image/Target/GUES... 84201225 \n",
"\n",
" description \\\n",
"8 Reach out to the complex cheese lover in your ... \n",
"13 Package Includes\\r\\nLarge Dinosaur Floor Puzzl... \n",
"14 Round out your eyewear collection with the Rou... \n",
"\n",
" raw_description gtin13 currency \\\n",
"8 <div class=\"h-margin-v-default\" data-test=\"ite... 99967205276 USD \n",
"13 <div class=\"h-margin-v-default\" data-test=\"ite... 194425203808 USD \n",
"14 <div class=\"h-margin-v-default\" data-test=\"ite... 195995526496 USD \n",
"\n",
" price ... sub_category_1 sub_category_2 \\\n",
"8 58.95 ... Sports Fan Shop Sports Fan Shop Home Goods \n",
"13 19.99 ... Puzzles NaN \n",
"14 15.00 ... Eye Care NaN \n",
"\n",
" sub_category_3 \\\n",
"8 Sports Fan Shop Barware & Drinkware \n",
"13 NaN \n",
"14 NaN \n",
"\n",
" images \\\n",
"8 https://target.scene7.com/is/image/Target/GUES... \n",
"13 https://target.scene7.com/is/image/Target/GUES... \n",
"14 https://target.scene7.com/is/image/Target/GUES... \n",
"\n",
" raw_specifications \\\n",
"8 <div class=\"styles__StyledCol-sc-ct8kx6-0 iKGd... \n",
"13 <div class=\"styles__StyledCol-sc-ct8kx6-0 iKGd... \n",
"14 <div class=\"styles__StyledCol-sc-ct8kx6-0 iKGd... \n",
"\n",
" specifications \\\n",
"8 Number of Pieces: 5 | Number of Pieces: 5 | We... \n",
"13 Number of Pieces: 17 | Number of Pieces: 17 | ... \n",
"14 Material: Metal (Frame) | Material: Metal (Fra... \n",
"\n",
" highlights \\\n",
"8 BEAUTY & ELEGANCE - The Circo swivel-style cir... \n",
"13 JUMBO DINOSAUR PUZZLE: This t-rex foam puzzle ... \n",
"14 Universal Thread round aviator sunglasses with... \n",
"\n",
" raw_highlights \\\n",
"8 <li class=\"styles__Bullet-sc-6aebpn-0 eIfLaI\">... \n",
"13 <li class=\"styles__Bullet-sc-6aebpn-0 eIfLaI\">... \n",
"14 <li class=\"styles__Bullet-sc-6aebpn-0 eIfLaI\">... \n",
"\n",
" uniq_id scraped_at \n",
"8 0c549116-75c8-56cb-8877-165380d0efd9 06/12/22 \n",
"13 151c72b4-4856-502f-a508-961cc81fffa9 06/12/22 \n",
"14 2a803c0f-00bf-50a6-a490-d381620ac3a3 06/12/22 \n",
"\n",
"[3 rows x 24 columns]"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sel = data.loc[:, \"raw_specifications\"].str.contains(\"Dimensions\")\n",
"dimensions = data.loc[sel]\n",
"sel_overall = ~dimensions.loc[sel, \"raw_specifications\"].str.contains(\"Overall\")\n",
"#for x in dimensions.loc[sel_overall, \"raw_specifications\"]:\n",
"# render_html(x)\n",
"dimensions.loc[sel_overall]\n",
"\n",
"# looks like \"dimenions\" can be \"Dimensions (Overall)\", \"Dimensions\" or other things\n",
"# like \"Assembled Dimensions\" or \"Piece X Dimensions\". But this latter two options are\n",
"# incomplete (lack the height), harder to parse and rare enough that I'll just drop them"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "3fd14c61-c1f8-4b18-b04a-9b616e6cf9a7",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"\"Dimensions (Overall): 11.9 inches (L), 11.9 inches (W) | Dimensions (Overall): 11.9 inches (L), 11.9 inches (W) | Dated format: Monthly | Dated format: Monthly | Calendar year: 2022 | Calendar year: 2022 | Material: Paper | Material: Paper | TCIN: 84821007 | UPC: 9781801433983 | Origin: imported | The above item details were provided by the Target Plus™ Partner. Target does not represent or warrant that this information is accurate or complete. On occasion, manufacturers may modify their items and update their labels.We recommend that you do not rely solely on the information presented. If you have a specific question about this item, you may consult the item's label, contact the manufacturer directly or call Target Guest Services at 1-800-591-3869.\""
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import xml.etree.ElementTree as ET\n",
"\n",
"# There seem to be dupliucates on \"specifications\" that are not \n",
"# found on \"raw_specifications\"\n",
"# I think it's safe to just remove the duplicates\n",
"\n",
"specifications = data.loc[1,\"specifications\"]\n",
"specifications"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "88894d7c-dc68-42ee-9c9d-a53474762a7a",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0 None\n",
"1 Paper\n",
"2 None\n",
"3 Paper\n",
"4 Metal\n",
" ... \n",
"162 Plastic\n",
"163 None\n",
"164 Fabric\n",
"165 None\n",
"166 Stoneware\n",
"Name: raw_specifications, Length: 167, dtype: object\n",
"0 None\n",
"1 None\n",
"2 None\n",
"3 24\n",
"4 None\n",
" ... \n",
"162 None\n",
"163 None\n",
"164 None\n",
"165 None\n",
"166 1\n",
"Name: raw_specifications, Length: 167, dtype: object\n",
"0 None\n",
"1 11.9 inches (L), 11.9 inches (W)\n",
"2 None\n",
"3 None\n",
"4 23 inches (H) x 1 inches (W) x 23 inches (D)\n",
" ... \n",
"162 5.0 inches (W) x 9.5 inches (D)\n",
"163 12.0 inches (H) x 12.0 inches (W)\n",
"164 4.75 inches (H) x 2.25 inches (W) x 2.25 inch...\n",
"165 None\n",
"166 4.5 inches (H) x 12.5 inches (W) x 4.5 inches...\n",
"Name: raw_specifications, Length: 167, dtype: object\n",
"0 None\n",
"1 None\n",
"2 None\n",
"3 None\n",
"4 4.65 pounds\n",
" ... \n",
"162 .28 pounds\n",
"163 32.0 pounds\n",
"164 None\n",
"165 None\n",
"166 None\n",
"Name: raw_specifications, Length: 167, dtype: object\n",
"0 81917300\n",
"1 84821007\n",
"2 15432753\n",
"3 84199597\n",
"4 86345566\n",
" ... \n",
"162 83388852\n",
"163 80836585\n",
"164 75477923\n",
"165 85634544\n",
"166 80239765\n",
"Name: raw_specifications, Length: 167, dtype: object\n",
"0 imported\n",
"1 imported\n",
"2 Made in the USA\n",
"3 imported\n",
"4 imported\n",
" ... \n",
"162 made in the USA or imported\n",
"163 made in the USA or imported\n",
"164 made in the USA or imported\n",
"165 imported\n",
"166 imported\n",
"Name: raw_specifications, Length: 167, dtype: object\n"
]
}
],
"source": [
"def parse_specs(specifications: str) -> dict[str,str]:\n",
" fields_mapping = {\n",
" \"Material\": \"materials\",\n",
" \"Package Quantity\": \"packaging\",\n",
" \"Number of Pieces\": \"packaging\",\n",
" \"Dimensions (Overall)\": \"dimensions\",\n",
" \"Dimensions\": \"dimensions\",\n",
" \"Weight\": \"weight\",\n",
" \"TCIN\": \"tcin\",\n",
" \"Origin\": \"origin\", \n",
" }\n",
" spec_dict = {}\n",
" for spec in specifications.split(\"|\"):\n",
" if \":\" in spec:\n",
" try:\n",
" field, value = spec.split(\":\")\n",
" except ValueError:\n",
" print(spec)\n",
" return {}\n",
" field = field.strip()\n",
" if field in fields_mapping:\n",
" field = fields_mapping[field]\n",
" spec_dict[field] = value.strip()\n",
" return spec_dict\n",
"\n",
"\n",
"\n",
"def iter_parse(root: ET.Element) -> dict[str,str]:\n",
" \"\"\"Recursively parse the XML tree into a dictionary\n",
" Each key/value pair is inside it's own <div> tag and\n",
" the key inside a <b> tag.\n",
" The fields that I believe are compulsory (TCIN, UPC and Origin)\n",
" are only nested one level deep, while the rest of fields seem\n",
" to be always nested two levels deep. But parsing it recursively\n",
" helps generalise both cases.\"\"\"\n",
" \n",
" spec_dict = {}\n",
" for child in root:\n",
" if child.tag == \"div\":\n",
" if \"b\" in [x.tag for x in child]:\n",
" key, *values = child.itertext()\n",
" key = key.strip(\":\")\n",
" value = \"\".join(values).strip(\":\")\n",
" spec_dict[key] = value\n",
" else:\n",
" spec_dict.update(iter_parse(child))\n",
" return spec_dict\n",
"\n",
"def parse_raw_specs(raw_specs: str) -> dict[str,str]:\n",
" \"\"\"Parse a raw specifications XML string into a dictionary\n",
" This involves first recursively parsing the XML tree and then\n",
" renaming the key values\"\"\"\n",
" \n",
" fields_mapping = {\n",
" \"Material\": \"materials\",\n",
" \"Package Quantity\": \"packaging\",\n",
" \"Number of Pieces\": \"packaging\",\n",
" \"Dimensions (Overall)\": \"dimensions\",\n",
" \"Dimensions\": \"dimensions\",\n",
" \"Weight\": \"weight\",\n",
" \"TCIN\": \"tcin\",\n",
" \"Origin\": \"origin\", \n",
" }\n",
" xml_root = ET.fromstring(raw_specs)\n",
" parsed = iter_parse(xml_root)\n",
" specs_dict = {\n",
" fields_mapping[key]: value\n",
" for key, value in parsed.items()\n",
" if key in fields_mapping\n",
" }\n",
" return specs_dict\n",
" \n",
"\n",
"def parse_value(specs: str, value: str) -> str:\n",
" return parse_raw_specs(specs).get(value)\n",
"\n",
"for x in [\"materials\", \"packaging\", \"dimensions\", \"weight\", \"tcin\", \"origin\"]:\n",
" print(data[\"raw_specifications\"].apply(parse_value, value=x))\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "5902f1b3-a77e-4353-92aa-71cc729e8c87",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0 None\n",
"1 {'width': 30.226000000000003}\n",
"2 None\n",
"3 None\n",
"4 {'height': 58.42, 'width': 2.54, 'depth': 58.42}\n",
" ... \n",
"162 {'width': 12.7, 'depth': 24.13}\n",
"163 {'height': 30.48, 'width': 30.48}\n",
"164 {'height': 12.065, 'width': 5.715, 'depth': 5....\n",
"165 None\n",
"166 {'height': 11.43, 'width': 31.75, 'depth': 11.43}\n",
"Name: raw_specifications, Length: 167, dtype: object"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import re\n",
"from typing import Optional\n",
"\n",
"def parse_dimensions_measure(dimensions: str, measure: str) -> Optional[dict[str,str]]:\n",
" expr = f\"(?P<value>\\d*[.,]?\\d*)\\s+(?P<unit>[a-zA-Z]*)\\s+\\({measure}\\)\" \n",
" if match := re.search(expr, dimensions):\n",
" return {\n",
" \"value\": float(match.group(\"value\")),\n",
" \"unit\": match.group(\"unit\").lower()\n",
" }\n",
"\n",
"def units_to_cm(value: float, unit: str) -> float:\n",
" conversions = {\n",
" \"inches\": 2.54,\n",
" \"feet\": 30.48,\n",
" \"cm\": 1\n",
" }\n",
" return value * conversions[unit]\n",
"\n",
"\n",
"def parse_dimensions(dimensions: Optional[str]) -> Optional[dict[str,float]]:\n",
" if dimensions is None:\n",
" return None\n",
" height = parse_dimensions_measure(dimensions, \"H\")\n",
" width = parse_dimensions_measure(dimensions, \"W\")\n",
" depth = parse_dimensions_measure(dimensions, \"D\")\n",
" dimensions = {\n",
" \"height\": height,\n",
" \"width\": width,\n",
" \"depth\": depth,\n",
" }\n",
" return {\n",
" key: units_to_cm(**value)\n",
" for key,value in dimensions.items()\n",
" if value is not None\n",
" }\n",
"\n",
"dimensions = data[\"raw_specifications\"].apply(parse_value, value=\"dimensions\").apply(parse_dimensions)\n",
"dimensions"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "26ece1d2-c466-498c-aeb6-5610fb16c7d3",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0 NaN\n",
"1 NaN\n",
"2 NaN\n",
"3 NaN\n",
"4 2109.202800\n",
" ... \n",
"162 127.005760\n",
"163 14514.944000\n",
"164 0.078812\n",
"165 NaN\n",
"166 0.829595\n",
"Name: raw_specifications, Length: 167, dtype: float64"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def units_to_g(value: float, unit: str) -> float:\n",
" conversions = {\n",
" \"pounds\": 453.592,\n",
" \"ounces\": 28.3495,\n",
" \"g\": 1\n",
" }\n",
" return value * conversions[unit]\n",
"\n",
"def parse_weight(weight: str):\n",
" if weight is None:\n",
" return None\n",
" expr = f\"(?P<value>\\d*[.,]?\\d*)\\s+(?P<unit>[a-zA-Z]*)\"\n",
"\n",
" # strip is needed to prevent the regex from lazily\n",
" # matching just from the first whitespace separator,\n",
" # this could happen because the number part in the\n",
" # expression is technically all optional, to avoid\n",
" # an expression too complex and unreadable\n",
" if match := re.search(expr, weight.strip()):\n",
" value = float(match.group(\"value\"))\n",
" unit = match.group(\"unit\").lower()\n",
" return units_to_g(value, unit)\n",
"\n",
" return weight\n",
"\n",
"def calculate_dimensional_weight(dimensions: dict[str,float]):\n",
" \"\"\"The dimensional weight (in kg) is calculated as\n",
" Length * Height * Width (in cm) / 5000.\n",
" We'll return it in g here\"\"\"\n",
" if dimensions is None:\n",
" return None\n",
" \n",
" height = dimensions.get(\"height\")\n",
" width = dimensions.get(\"width\")\n",
" depth = dimensions.get(\"depth\")\n",
" if None in [height, width, depth]:\n",
" return None\n",
" \n",
" return height * width * depth / 5000\n",
"\n",
"weight = data[\"raw_specifications\"].apply(parse_value, value=\"weight\").apply(parse_weight)\n",
"\n",
"dimensional_weight = list(map(calculate_dimensional_weight, dimensions))\n",
"\n",
"sel = weight.isnull()\n",
"weight[sel] = pd.Series(dimensional_weight)[sel]\n",
"\n",
"weight"
]
},
{
"cell_type": "code",
"execution_count": 40,
"id": "49c7495f-1f36-4dc9-8686-de3af7b230a9",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "4e6b4e140b0840f6a35e4249c0d1f5f4",
"version_major": 2,
"version_minor": 0
},
"image/png": "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",
"text/html": [
"\n",
" <div style=\"display: inline-block;\">\n",
" <div class=\"jupyter-widgets widget-label\" style=\"text-align: center;\">\n",
" Figure 22\n",
" </div>\n",
" <img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABdwAAAH0CAYAAAAnhe8sAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABLAklEQVR4nO3dfXRW1Z0v8F8gGMCGtIIkoYCGW4oIlSI4ilrBWnHwpXW0nbaKxb4tGUBFlqWNzozBGUl1HBZ1UCxei3op6p0irZ2qhU4laMHKi1SrFLUyhlJSbiwmiBIEzv3D+pSYBAme5MnL57PWWcuzzz7P+e2dh2cnX09OcpIkSQIAAAAAAPhAumS7AAAAAAAA6AgE7gAAAAAAkAKBOwAAAAAApEDgDgAAAAAAKRC4AwAAAABACgTuAAAAAACQAoE7AAAAAACkQOAOAAAAAAApELgDAAAAAEAKBO4AAAAAAJACgTsAAAAAAKRA4A4AAAAAACkQuAMAAAAAQAoE7gAAAAAAkAKBOwAAAAAApEDgDgAAAAAAKRC4AwAAAABACgTuAAAAAACQAoE7AAAAAACkQOAOAAAAAAApELgDAAAAAEAKBO4AAAAAAJACgTsAAAAAAKRA4A4AAAAAACkQuAMAAAAAQAoE7gAAAAAAkAKBOwAAAAAApEDgDgAAAAAAKRC4AwAAAABACgTuAAAAAACQAoE7AAAAAACkQOAOAAAAAAApELgDAAAAAEAKBO4AAAAAAJACgTsAAAAAAKRA4A4AAAAAACkQuAMAAAAAQAoE7gAAAAAAkAKBOwAAAAAApEDgDgAAAAAAKRC4AwAAAABACgTuAAAAAACQAoE7AAAAAACkQOAOAAAAAAApELgDAAAAAEAKBO4AAAAAAJACgTsAAAAAAKRA4A4AAAAAACkQuAMAAAAAQAoE7gAAAAAAkAKBOwAAAAAApEDgDgAAAAAAKRC4AwAAAABACgTuAAAAAACQAoE7AAAAAACkQOAOAAAAAAApELgDAAAAAEAKBO4AAAAAAJCC3GwXAK1l//798cc//jHy8/MjJycn2+UAtGtJksTOnTujX79+0aWL/38fYZ0BSJu1pj7rDEC6rDO0FIE7ncYf//jHGDBgQLbLAOhQtmzZEv379892GW2CdQagZVhr3mGdAWgZ1hnSJnCn08jPz4+Idz5Ie/XqleVqANq32traGDBgQOazFesMQNqsNfVZZwDSZZ2hpQjc6TTe/bXLXr16+QYVICV+pf2vrDMALcNa8w7rDEDLsM6QNg8oAgAAAACAFAjcAQAAAAAgBQJ3AAAAAABIgcAdAAAAAABSIHAHAAAAAIAUCNxpE7Zu3RoTJ06M3r17R8+ePeOTn/xkrFu3LnM8SZIoKyuLfv36RY8ePWLcuHHx/PPPZ7FiAAAAAID6BO5k3Y4dO+K0006Lbt26xaOPPhovvPBC/Pu//3t8+MMfzvS55ZZbYs6cOTFv3rxYs2ZNFBUVxdlnnx07d+7MXuEAAAAAAAfIzXYBcPPNN8eAAQNi4cKFmbZjjz02899JksTcuXPj+uuvj4suuigiIu69994oLCyMxYsXxxVXXNHaJQMAAAAANOAOd7Lu4YcfjtGjR8cXvvCF6Nu3b4wcOTLuuuuuzPHNmzdHVVVVjB8/PtOWl5cXY8eOjVWrVjX5unV1dVFbW1tvAwAAAABoKQJ3su6VV16J+fPnx+DBg+PnP/95TJ48Oa666qq47777IiKiqqoqIiIKCwvrnVdYWJg51pjy8vIoKCjIbAMGDGi5QQAAAAAAnZ7Anazbv39/nHjiiTF79uwYOXJkXHHFFfHNb34z5s+fX69fTk5Ovf0kSRq0Hai0tDRqamoy25YtW1qkfgAAAACACIE7bUBxcXEcf/zx9dqGDh0alZWVERFRVFQUEdHgbvbt27c3uOv9QHl5edGrV696GwAAwAcxf/78OOGEEzI/Y4wZMyYeffTRg55TUVERo0aNiu7du8egQYPizjvvbKVqAYDWJnAn60477bTYtGlTvbYXX3wxjjnmmIiIKCkpiaKioli+fHnm+J49e6KioiJOPfXUVq0VAADo3Pr37x/f/e53Y+3atbF27dr49Kc/HZ/73Ofi+eefb7T/5s2b49xzz41PfepT8cwzz8R1110XV111VSxZsqSVKwcAWkNutguAa665Jk499dSYPXt2/P3f/308/fTTsWDBgliwYEFEvPMomenTp8fs2bNj8ODBMXjw4Jg9e3b07NkzLrnkkixXDwAAdCYXXHBBvf2bbrop5s+fH0899VQMGzasQf8777wzBg4cGHPnzo2Id36bd+3atXHrrbfGxRdf3BolAwCtSOBO1p100kmxdOnSKC0tjRtvvDFKSkpi7ty5cemll2b6zJw5M956662YMmVK7NixI04++eRYtmxZ5Ofnt1qdlZWVUV1d3aC9T58+MXDgwFarA4COqal1JsJaA9BW7du3L/7zP/8zdu3aFWPGjGm0z+rVq2P8+PH12s4555y4++674+23345u3bo1el5dXV3U1dVl9mtra9Mr/BD5GQgAmk/gTptw/vnnx/nnn9/k8ZycnCgrK4uysrLWK+oAlZWVMWTI0Ni9+80Gx7p37xmbNm30DScAh+1g60yEtQagrXnuuedizJgxsXv37vjQhz4US5cubfB3qd5VVVXV4G9PFRYWxt69e6O6ujqKi4sbPa+8vDxmzZqVeu2Hys9AAHB4PMMdDkF1dfVfvtFcFBHrDtgWxe7dbzZ5RyIAHIqm1xlrDUBbNGTIkNiwYUM89dRT8Q//8A8xadKkeOGFF5rsn5OTU28/SZJG2w9UWloaNTU1mW3Lli3pFH+I/AwEAIfHHe7QLEMj4sRsFwFAh2WdAWgPjjjiiPjYxz4WERGjR4+ONWvWxPe+9734/ve/36BvUVFRVFVV1Wvbvn175ObmRu/evZu8Rl5eXuTl5aVb+GGxNgFAc7jDHQAAAD6AJEnqPW/9QGPGjInly5fXa1u2bFmMHj26yee3AwDtl8AdAAAADtF1110XTzzxRPzP//xPPPfcc3H99dfHihUr4tJLL42Idx4F85WvfCXTf/LkyfHqq6/GjBkzYuPGjfGDH/wg7r777rj22muzNQQAoAV5pAwAAAAcoj/96U9x2WWXxbZt26KgoCBOOOGEeOyxx+Lss8+OiIht27ZFZWVlpn9JSUk88sgjcc0118Ttt98e/fr1i9tuuy0uvvjibA0BAGhBAncAAAA4RHffffdBj99zzz0N2saOHRvr169voYoAgLbEI2UAAAAAACAFAncAAAAAAEiBwB0AAAAAAFIgcAcAAAAAgBQI3AEAAAAAIAUCdwAAAAAASIHAHQAAAAAAUiBwBwAAAACAFAjcAQAAAAAgBQJ3AAAAAABIgcAdAAAAAABSIHAHAAAAAIAUCNwBAAAAACAFAncAAAAAAEiBwB0AAAAAAFIgcAcAAAAAgBQI3AEAAAAAIAUCdwAAAAAASIHAHQAAAAAAUiBwBwAAAACAFAjcAQAAAAAgBQJ3AAAAAABIgcAdAOjwVq5cGRdccEH069cvcnJy4sc//nG940mSRFlZWfTr1y969OgR48aNi+effz47xQIAANBuCdwBgA5v165dMWLEiJg3b16jx2+55ZaYM2dOzJs3L9asWRNFRUVx9tlnx86dO1u5UgAAANqz3GwXAADQ0iZMmBATJkxo9FiSJDF37ty4/vrr46KLLoqIiHvvvTcKCwtj8eLFccUVV7RmqQAAALRj7nAHADq1zZs3R1VVVYwfPz7TlpeXF2PHjo1Vq1ZlsTIAAADaG3e4AwCdWlVVVUREFBYW1msvLCyMV199tcnz6urqoq6uLrNfW1vbMgUCAADQbrjDHQAgInJycurtJ0nSoO1A5eXlUVBQkNkGDBjQ0iUCAADQxgncAYBOraioKCL+eqf7u7Zv397grvcDlZaWRk1NTWbbsmVLi9YJAABA2ydwBwA6tZKSkigqKorly5dn2vbs2RMVFRVx6qmnNnleXl5e9OrVq94GAABA5+YZ7gBAh/fGG2/Eyy+/nNnfvHlzbNiwIY466qgYOHBgTJ8+PWbPnh2DBw+OwYMHx+zZs6Nnz55xySWXZLFqAAAA2huBOwDQ4a1duzbOPPPMzP6MGTMiImLSpElxzz33xMyZM+Ott96KKVOmxI4dO+Lkk0+OZcuWRX5+frZKBgAAoB0SuAMAHd64ceMiSZImj+fk5ERZWVmUlZW1XlEAAAB0OJ7hDgAAAAAAKRC4AwAAAABACgTuAAAAAACQAoE7AAAAAACkQOAOAAAAAAApELgDAAAAAEAKBO4AAAAAAJACgTsAAAAAAKRA4A4AAAAAACkQuAMAAAAAQAoE7gAAAAAAkAKBOwAAAAAApEDgTtaVlZVFTk5Ova2oqChzPEmSKCsri379+kWPHj1i3Lhx8fzzz2exYgAAAACAhgTutAnDhg2Lbdu2Zbbnnnsuc+yWW26JOXPmxLx582LNmjVRVFQUZ599duzcuTOLFQMAAAAA1Cdwp03Izc2NoqKizHb00UdHxDt3t8+dOzeuv/76uOiii2L48OFx7733xptvvhmLFy/OctUAAAAAAH8lcKdNeOmll6Jfv35RUlISX/rSl+KVV16JiIjNmzdHVVVVjB8/PtM3Ly8vxo4dG6tWrTroa9bV1UVtbW29DQAAAACgpQjcybqTTz457rvvvvj5z38ed911V1RVVcWpp54ar732WlRVVUVERGFhYb1zCgsLM8eaUl5eHgUFBZltwIABLTYGAAAAAACBO1k3YcKEuPjii+MTn/hEfOYzn4mf/exnERFx7733Zvrk5OTUOydJkgZt71VaWho1NTWZbcuWLekXDwAAdCrl5eVx0kknRX5+fvTt2zcuvPDC2LRp00HPWbFiReTk5DTYfve737VS1QBAaxG40+YceeSR8YlPfCJeeumlKCoqiohocDf79u3bG9z1/l55eXnRq1evehsAAMAHUVFREVOnTo2nnnoqli9fHnv37o3x48fHrl273vfcTZs2xbZt2zLb4MGDW6FiAKA15Wa7AHivurq62LhxY3zqU5+KkpKSKCoqiuXLl8fIkSMjImLPnj1RUVERN998c5YrBQAAOpvHHnus3v7ChQujb9++sW7dujjjjDMOem7fvn3jwx/+cAtWBwBkmzvcybprr702KioqYvPmzfHrX/86Pv/5z0dtbW1MmjQpcnJyYvr06TF79uxYunRp/Pa3v43LL788evbsGZdcckm2SwcAADq5mpqaiIg46qij3rfvyJEjo7i4OM4666x4/PHHD9q3rq4uamtr620AQNvnDney7g9/+EN8+ctfjurq6jj66KPjlFNOiaeeeiqOOeaYiIiYOXNmvPXWWzFlypTYsWNHnHzyybFs2bLIz8/PcuUAAEBnliRJzJgxI04//fQYPnx4k/2Ki4tjwYIFMWrUqKirq4v/83/+T5x11lmxYsWKJu+KLy8vj1mzZrVU6QBACxG4k3UPPPDAQY/n5OREWVlZlJWVtU5BAAAAh2DatGnx7LPPxpNPPnnQfkOGDIkhQ4Zk9seMGRNbtmyJW2+9tcnAvbS0NGbMmJHZr62tjQEDBqRTOADQYjxSBgAAAJrpyiuvjIcffjgef/zx6N+/f7PPP+WUU+Kll15q8nheXl706tWr3gYAtH3ucAcAAIBDlCRJXHnllbF06dJYsWJFlJSUHNbrPPPMM1FcXJxydQBAtgncAQAA4BBNnTo1Fi9eHD/5yU8iPz8/qqqqIiKioKAgevToERHvPA5m69atcd9990VExNy5c+PYY4+NYcOGxZ49e2LRokWxZMmSWLJkSdbGAQC0DIE7AAAAHKL58+dHRMS4cePqtS9cuDAuv/zyiIjYtm1bVFZWZo7t2bMnrr322ti6dWv06NEjhg0bFj/72c/i3HPPba2yAYBWInAHAACAQ5Qkyfv2ueeee+rtz5w5M2bOnNlCFQEAbYk/mgoAAAAAACkQuAMAAAAAQAoE7gAAAAAAkAKBOwAAAAAApEDgDgAAAAAAKRC4AwAAAABACgTuAAAAAACQAoE7AAAAAACkQOAOAAAAAAApELgDAAAAAEAKBO4AAAAAAJACgTsAAAAAAKRA4A4AAAAAACkQuAMAAAAAQAoE7gAAAAAAkAKBOwAAAAAApEDgDgAAAAAAKRC4AwAAAABACgTuAAAAAACQAoE7AAAAAACkQOAOAAAAAAApELgDAAAAAEAKBO4AAAAAAJACgTsAAAAAAKRA4A4AAAAAACkQuAMAAAAAQAoE7gAAAAAAkAKBOwAAAAAApEDgDgB0env37o1//Md/jJKSkujRo0cMGjQobrzxxti/f3+2SwMAAKAdyc12AQAA2XbzzTfHnXfeGffee28MGzYs1q5dG1/96lejoKAgrr766myXBwAAQDshcAcAOr3Vq1fH5z73uTjvvPMiIuLYY4+N+++/P9auXZvlygAAAGhPPFIGAOj0Tj/99Pjv//7vePHFFyMi4je/+U08+eSTce655zZ5Tl1dXdTW1tbbAAAA6Nzc4Q4AdHrf/va3o6amJo477rjo2rVr7Nu3L2666ab48pe/3OQ55eXlMWvWrFasEgAAgLbOHe4AQKf34IMPxqJFi2Lx4sWxfv36uPfee+PWW2+Ne++9t8lzSktLo6amJrNt2bKlFSsGAACgLXKHOwDQ6X3rW9+K73znO/GlL30pIiI+8YlPxKuvvhrl5eUxadKkRs/Jy8uLvLy81iwTAACANs4d7gBAp/fmm29Gly71vy3q2rVr7N+/P0sVAQAA0B65wx0A6PQuuOCCuOmmm2LgwIExbNiweOaZZ2LOnDnxta99LdulAQAA0I4I3AGATu8//uM/4p/+6Z9iypQpsX379ujXr19cccUV8c///M/ZLg0AAIB2ROAOAHR6+fn5MXfu3Jg7d262SwEAAKAd8wx3AAAAAABIgcAdAAAAAABSIHAHAAAAAIAUCNwBAAAAACAFAncAAAAAAEiBwB0AAAAAAFIgcAcAAAAAgBQI3GlzysvLIycnJ6ZPn55pS5IkysrKol+/ftGjR48YN25cPP/889krEgAAAADgPQTutClr1qyJBQsWxAknnFCv/ZZbbok5c+bEvHnzYs2aNVFUVBRnn3127Ny5M0uVAgAAAADUJ3CnzXjjjTfi0ksvjbvuuis+8pGPZNqTJIm5c+fG9ddfHxdddFEMHz487r333njzzTdj8eLFWawYAAAAAOCvBO60GVOnTo3zzjsvPvOZz9Rr37x5c1RVVcX48eMzbXl5eTF27NhYtWpVk69XV1cXtbW19TYAAAAAgJYicKdNeOCBB2L9+vVRXl7e4FhVVVVERBQWFtZrLywszBxrTHl5eRQUFGS2AQMGpFs0AADQ6ZSXl8dJJ50U+fn50bdv37jwwgtj06ZN73teRUVFjBo1Krp37x6DBg2KO++8sxWqBQBam8CdrNuyZUtcffXVsWjRoujevXuT/XJycurtJ0nSoO1ApaWlUVNTk9m2bNmSWs0AAEDnVFFREVOnTo2nnnoqli9fHnv37o3x48fHrl27mjxn8+bNce6558anPvWpeOaZZ+K6666Lq666KpYsWdKKlQMArSE32wXAunXrYvv27TFq1KhM2759+2LlypUxb968zN0iVVVVUVxcnOmzffv2Bne9HygvLy/y8vJarnAAAKDTeeyxx+rtL1y4MPr27Rvr1q2LM844o9Fz7rzzzhg4cGDMnTs3IiKGDh0aa9eujVtvvTUuvvjili4ZAGhF7nAn684666x47rnnYsOGDZlt9OjRcemll8aGDRti0KBBUVRUFMuXL8+cs2fPnqioqIhTTz01i5UDAACdXU1NTUREHHXUUU32Wb16db2/SRURcc4558TatWvj7bffbtH6AIDW5Q53si4/Pz+GDx9er+3II4+M3r17Z9qnT58es2fPjsGDB8fgwYNj9uzZ0bNnz7jkkkuyUTIAAEAkSRIzZsyI008/vcHPNAeqqqpq9G9S7d27N6qrq+v9Ju+76urqoq6uLrNfW1ubXuHvUVlZGdXV1fXaNm7ceNBzGjvep0+fGDhwYKq1AUB7I3CnXZg5c2a89dZbMWXKlNixY0ecfPLJsWzZssjPz892aQAAQCc1bdq0ePbZZ+PJJ598376N/U2qxtrfVV5eHrNmzfrgRb6PysrKGDJkaOze/eYhnrEtIrrExIkTGxzp3r1nbNq0UegOQKcmcKdNWrFiRb39nJycKCsri7KysqzUAwAAcKArr7wyHn744Vi5cmX079//oH2LioqiqqqqXtv27dsjNzc3evfu3eg5paWlMWPGjMx+bW1tDBgw4IMX/h7V1dV/CdsXRcTQA448EhH/1MgZr0fE/kb6b4zduydGdXW1wB2ATk3gDgAAAIcoSZK48sorY+nSpbFixYooKSl533PGjBkTP/3pT+u1LVu2LEaPHh3dunVr9Jy8vLzIy8tLpeZDMzQiTjxg/+CPlGnYHwCI8EdTAQAA4JBNnTo1Fi1aFIsXL478/PyoqqqKqqqqeOuttzJ9SktL4ytf+Upmf/LkyfHqq6/GjBkzYuPGjfGDH/wg7r777rj22muzMQQAoAUJ3AEAAOAQzZ8/P2pqamLcuHFRXFyc2R588MFMn23btkVlZWVmv6SkJB555JFYsWJFfPKTn4x/+Zd/idtuuy0uvvjibAwBAGhBHikDAAAAh+jdP3Z6MPfcc0+DtrFjx8b69etboCIAoC1xhzsAAAAAAKRA4A4AAAAAACkQuAMAAAAAQAoE7gAAAAAAkAKBOwAAAAAApEDgDgAAAAAAKRC4AwAAAABACgTuAAAAAACQAoE7AAAAAACkQOAOAAAAAAApELgDAAAAAEAKBO4AAAAAAJACgTsAAAAAAKRA4A4AAAAAACkQuAMAAAAAQAoE7gAAAAAAkAKBOwAAAAAApEDgDgAAAAAAKRC4AwAAAABACgTuAAAAAACQAoE7AAAAAACkQOAOAAAAAAApELgDAAAAAEAKBO4AAAAAAJACgTsAAAAAAKRA4A4AAAAAACkQuAMAAAAAQAoE7gAAAAAAkAKBOwAAAAAApEDgDgAAAAAAKRC4AwAAAABACgTuAAAAAACQAoE7AAAAAACkQOAOAAAAAAApELgDAETE1q1bY+LEidG7d+/o2bNnfPKTn4x169ZluywAAADakdxsFwAAkG07duyI0047Lc4888x49NFHo2/fvvH73/8+PvzhD2e7NAAAANoRgTsA0OndfPPNMWDAgFi4cGGm7dhjj81eQQAAALRLHikDAHR6Dz/8cIwePTq+8IUvRN++fWPkyJFx1113HfScurq6qK2trbcBAADQuQncAYBO75VXXon58+fH4MGD4+c//3lMnjw5rrrqqrjvvvuaPKe8vDwKCgoy24ABA1qxYgAAANoigTsA0Ont378/TjzxxJg9e3aMHDkyrrjiivjmN78Z8+fPb/Kc0tLSqKmpyWxbtmxpxYoBAABoiwTuAECnV1xcHMcff3y9tqFDh0ZlZWWT5+Tl5UWvXr3qbQAAAHRuAncAoNM77bTTYtOmTfXaXnzxxTjmmGOyVBEAAADtkcAdAOj0rrnmmnjqqadi9uzZ8fLLL8fixYtjwYIFMXXq1GyXBgAAQDsicAcAOr2TTjopli5dGvfff38MHz48/uVf/iXmzp0bl156abZLAwAAoB3JzXYBAABtwfnnnx/nn39+tssAAACgHXOHOwAAAAAApEDgDgAAAAAAKRC4k3Xz58+PE044IXr16hW9evWKMWPGxKOPPpo5niRJlJWVRb9+/aJHjx4xbty4eP7557NYMQAAAABAQwJ3sq5///7x3e9+N9auXRtr166NT3/60/G5z30uE6rfcsstMWfOnJg3b16sWbMmioqK4uyzz46dO3dmuXIAAAAAgL8SuJN1F1xwQZx77rnx8Y9/PD7+8Y/HTTfdFB/60IfiqaeeiiRJYu7cuXH99dfHRRddFMOHD49777033nzzzVi8eHG2SwcAAAAAyBC406bs27cvHnjggdi1a1eMGTMmNm/eHFVVVTF+/PhMn7y8vBg7dmysWrUqi5UCAACd1cqVK+OCCy6Ifv36RU5OTvz4xz8+aP8VK1ZETk5Og+13v/td6xQMALSa3GwXABERzz33XIwZMyZ2794dH/rQh2Lp0qVx/PHHZ0L1wsLCev0LCwvj1VdfPehr1tXVRV1dXWa/trY2/cIBAIBOZ9euXTFixIj46le/GhdffPEhn7dp06bo1atXZv/oo49uifIAgCwSuNMmDBkyJDZs2BCvv/56LFmyJCZNmhQVFRWZ4zk5OfX6J0nSoO29ysvLY9asWS1SLwAA0HlNmDAhJkyY0Ozz+vbtGx/+8IfTLwgAaDM8UoY24YgjjoiPfexjMXr06CgvL48RI0bE9773vSgqKoqIiKqqqnr9t2/f3uCu9/cqLS2NmpqazLZly5YWqx8AAOD9jBw5MoqLi+Oss86Kxx9/PNvlAAAtQOBOm5QkSdTV1UVJSUkUFRXF8uXLM8f27NkTFRUVceqppx70NfLy8qJXr171NgAAgNZWXFwcCxYsiCVLlsRDDz0UQ4YMibPOOitWrlzZ5Dl1dXVRW1tbbwMA2j6PlCHrrrvuupgwYUIMGDAgdu7cGQ888ECsWLEiHnvsscjJyYnp06fH7NmzY/DgwTF48OCYPXt29OzZMy655JJslw4AAPC+hgwZEkOGDMnsjxkzJrZs2RK33nprnHHGGY2e4xGZANA+CdzJuj/96U9x2WWXxbZt26KgoCBOOOGEeOyxx+Lss8+OiIiZM2fGW2+9FVOmTIkdO3bEySefHMuWLYv8/PwsVw4AAHB4TjnllFi0aFGTx0tLS2PGjBmZ/dra2hgwYEBrlAYAfAACd7Lu7rvvPujxnJycKCsri7KystYpCAAAoIU988wzUVxc3OTxvLy8yMvLa8WKAIA0CNwBAACgGd544414+eWXM/ubN2+ODRs2xFFHHRUDBw6M0tLS2Lp1a9x3330RETF37tw49thjY9iwYbFnz55YtGhRLFmyJJYsWZKtIQAALUTgDgAAAM2wdu3aOPPMMzP77z76ZdKkSXHPPffEtm3borKyMnN8z549ce2118bWrVujR48eMWzYsPjZz34W5557bqvXDgC0LIE7AAAANMO4ceMiSZImj99zzz319mfOnBkzZ85s4aoAgLagS7YLAAAAAACAjkDgDgAAAAAAKRC4AwAAAABACgTuAAAAAACQAoE7AAAAAACkQOAOAAAAAAApELgDAAAAAEAKBO4AAAAAAJACgTsAAAAAAKRA4A4AAAAAACkQuAMAAAAAQAoE7gAAAAAAkAKBOwAAAAAApEDgDgAAAAAAKRC4AwAAAABACgTuAAAAAACQAoE7AAAAAACkQOAOAAAAAAApELgDAAAAAEAKBO4AAAAAAJACgTsAAAAAAKRA4A4AAAAAACkQuAMAAAAAQAoE7gAAAAAAkAKBOwAAAAAApEDgDgAAAAAAKRC4AwAAAABACgTuAAAAAACQAoE7AAAAAACkQOAOAAAAAAApELgDAAAAAEAKBO4AAAAAAJACgTsAAAAAAKRA4A4AAAAAACkQuAMAAAAAQAoE7gAAAAAAkAKBOwAAAAAApEDgDgAAAAAAKRC4AwAAAABACgTuAADvUV5eHjk5OTF9+vRslwIAAEA7InAHADjAmjVrYsGCBXHCCSdkuxQAAADaGYE7AMBfvPHGG3HppZfGXXfdFR/5yEeyXQ4AAADtjMAdAOAvpk6dGuedd1585jOfyXYpAAAAtEO52S4AAKAteOCBB2L9+vWxZs2aQ+pfV1cXdXV1mf3a2tqWKg0AAIB2wh3uAECnt2XLlrj66qtj0aJF0b1790M6p7y8PAoKCjLbgAEDWrhKAAAA2jqBOwDQ6a1bty62b98eo0aNitzc3MjNzY2Kioq47bbbIjc3N/bt29fgnNLS0qipqclsW7ZsyULlAAAAtCUeKQMAdHpnnXVWPPfcc/XavvrVr8Zxxx0X3/72t6Nr164NzsnLy4u8vLzWKhEAAIB2QOAOAHR6+fn5MXz48HptRx55ZPTu3btBOwAAADTFI2XIuvLy8jjppJMiPz8/+vbtGxdeeGFs2rSpXp8kSaKsrCz69esXPXr0iHHjxsXzzz+fpYoBAAAAABoSuJN1FRUVMXXq1Hjqqadi+fLlsXfv3hg/fnzs2rUr0+eWW26JOXPmxLx582LNmjVRVFQUZ599duzcuTOLlQPQka1YsSLmzp2b7TIAAABoRwTuZN1jjz0Wl19+eQwbNixGjBgRCxcujMrKyli3bl1EvHN3+9y5c+P666+Piy66KIYPHx733ntvvPnmm7F48eIsVw8AAHQ2K1eujAsuuCD69esXOTk58eMf//h9z6moqIhRo0ZF9+7dY9CgQXHnnXe2fKEAQKsTuNPm1NTURETEUUcdFRERmzdvjqqqqhg/fnymT15eXowdOzZWrVqVlRoBAIDOa9euXTFixIiYN2/eIfXfvHlznHvuufGpT30qnnnmmbjuuuviqquuiiVLlrRwpQBAa/NHU2lTkiSJGTNmxOmnn575I3VVVVUREVFYWFivb2FhYbz66qtNvlZdXV3U1dVl9mtra1ugYgAAoLOZMGFCTJgw4ZD733nnnTFw4MDMo8qGDh0aa9eujVtvvTUuvvjiFqoSAMgGd7jTpkybNi2effbZuP/++xscy8nJqbefJEmDtgOVl5dHQUFBZhswYEDq9QIAALyf1atX1/uN3YiIc845J9auXRtvv/12lqoCAFqCO9xpM6688sp4+OGHY+XKldG/f/9Me1FRUUS8c6d7cXFxpn379u0N7no/UGlpacyYMSOzX1tbK3QHAABaXVVVVaO/sbt3796orq6u93POu1riN3YrKyujurq6XtvGjRs/8OseyuvV1dVFXl7eIbf36dMnBg4cmEpNjY27PV4jrWtns9ZsamrcEemNvalrNPU+b41rH841mjuOtvg+h2wSuJN1SZLElVdeGUuXLo0VK1ZESUlJveMlJSVRVFQUy5cvj5EjR0ZExJ49e6KioiJuvvnmJl83Ly+vyQUNAACgNTX2G7uNtb+rvLw8Zs2aldr1KysrY8iQobF795upvWZ92yKiS0ycOLGJ410jYt8ht3fv3jM2bdr4gYO0g427PV0jrWtns9Zser/3fxpjP/g1mnr/t8a1m3eNwxlHW3ufQ7YJ3Mm6qVOnxuLFi+MnP/lJ5OfnZ57ZXlBQED169IicnJyYPn16zJ49OwYPHhyDBw+O2bNnR8+ePeOSSy7JcvUAAAAHV1RUlPk5513bt2+P3Nzc6N27d6PnpP0bu9XV1X8JqxZFxNADjjwSEf902K/7V69HxP5GXv/AazR17fe2b4zduydGdXX1Bw7Rmh53+7pGWtfOZq3Z1PS4I9Ia+/v/G8vGtZt/jeaPo+29zyHbBO5k3fz58yMiYty4cfXaFy5cGJdffnlERMycOTPeeuutmDJlSuzYsSNOPvnkWLZsWeTn57dytQAAAM0zZsyY+OlPf1qvbdmyZTF69Ojo1q1bo+e03G/sDo2IEw/YT/eRMg1f/8BrNHXtxs5JW0e5RlrXzmat2ZSN90F7fZ9ncxxN6azvW9obgTtZ9+6vUh5MTk5OlJWVRVlZWcsXBAAAcBBvvPFGvPzyy5n9zZs3x4YNG+Koo46KgQMHRmlpaWzdujXuu+++iIiYPHlyzJs3L2bMmBHf/OY3Y/Xq1XH33XfH/fffn60hAAAtROAOAAAAzbB27do488wzM/vvPvpl0qRJcc8998S2bduisrIyc7ykpCQeeeSRuOaaa+L222+Pfv36xW233RYXX3xxq9cOALQsgTsAAAA0w7hx4w76m7r33HNPg7axY8fG+vXrW7AqAKAt6JLtAgAAAAAAoCMQuAMAAAAAQAoE7gAAAAAAkAKBOwAAAAAApEDgDgAAAAAAKRC4AwAAAABACgTuAAAAAACQAoE7AAAAAACkQOAOAAAAAAApELgDAAAAAEAKBO4AAAAAAJACgTsAAAAAAKRA4A4AAAAAACkQuAMAAAAAQAoE7gAAAAAAkILcbBcAAMD727hxY4O2Pn36xMCBAxu0V1ZWRnV1dYP2urq6yMvLO+TXaS1N1ZvtugAAAJpL4A4A0KZti4guMXHixAZHunfvGZs2bawXSldWVsaQIUNj9+43G3mtrhGx75Bep7UcrN5s1gUAAHA4BO4AAG3a6xGxPyIWRcTQA9o3xu7dE6O6urpeIF1dXf2X8Pq9/R+JiH865NdpLU3Xm926AAAADofAHQCgXRgaESd+gP4bm2hvK9pqXQAAAIfOH00FAAAAAIAUCNwBAAAAACAFAncAAAAAAEiBwB0AAAAAAFIgcAcAAAAAgBQI3AEAAAAAIAUCdwAAAAAASIHAHQAAAAAAUiBwBwAAAACAFAjcAQAAAAAgBQJ3AAAAAABIgcAdAAAAAABSIHAHAAAAAIAUCNwBAAAAACAFAncAAAAAAEiBwB0AAAAAAFIgcAcAAAAAgBQI3AEAAAAAIAUCdwAAAAAASIHAHQAAAAAAUiBwBwAAAACAFAjcAQAAAAAgBQJ3AAAAAABIgcAdAAAAAABSIHAHAAAAAIAUCNwBAAAAACAFAncAoNMrLy+Pk046KfLz86Nv375x4YUXxqZNm7JdFgAAAO2MwB0A6PQqKipi6tSp8dRTT8Xy5ctj7969MX78+Ni1a1e2SwMAAKAdyc12AQAA2fbYY4/V21+4cGH07ds31q1bF2eccUaWqgIAAKC9EbgDALxHTU1NREQcddRRTfapq6uLurq6zH5tbW2L19WYjRs3HnS/vWtsPH369ImBAwdmoRoAAICDE7jTJqxcuTL+7d/+LdatWxfbtm2LpUuXxoUXXpg5niRJzJo1KxYsWBA7duyIk08+OW6//fYYNmxY9ooGoENKkiRmzJgRp59+egwfPrzJfuXl5TFr1qxWrOy9tkVEl5g4cWIWa2hJTY+ve/eesWnTRqE7AADQ5niGO23Crl27YsSIETFv3rxGj99yyy0xZ86cmDdvXqxZsyaKiori7LPPjp07d7ZypQB0dNOmTYtnn3027r///oP2Ky0tjZqamsy2ZcuWVqrwXa9HxP6IWBQR6w7Y/qWV62gpr0fj41sUu3e/GdXV1VmsDSDijjvuiJKSkujevXuMGjUqnnjiiSb7rlixInJychpsv/vd71qxYgCgNbjDnTZhwoQJMWHChEaPJUkSc+fOjeuvvz4uuuiiiIi49957o7CwMBYvXhxXXHFFa5YKQAd25ZVXxsMPPxwrV66M/v37H7RvXl5e5OXltVJlBzM0Ik48YL9jPVKm4fgAsu/BBx+M6dOnxx133BGnnXZafP/7348JEybECy+8cNDfvtm0aVP06tUrs3/00Ue3RrkAQCtyhztt3ubNm6OqqirGjx+facvLy4uxY8fGqlWrslgZAB1FkiQxbdq0eOihh+KXv/xllJSUZLskANqwOXPmxNe//vX4xje+EUOHDo25c+fGgAEDYv78+Qc9r2/fvlFUVJTZunbt2koVAwCtReBOm1dVVRUREYWFhfXaCwsLM8caU1dXF7W1tfU2AGjM1KlTY9GiRbF48eLIz8+PqqqqqKqqirfeeivbpQHQxuzZsyfWrVtX74agiIjx48e/7w1BI0eOjOLi4jjrrLPi8ccfb8kyAYAsEbjTbuTk5NTbT5KkQduBysvLo6CgILMNGDCgpUsEoJ2aP39+1NTUxLhx46K4uDizPfjgg9kuDYA2prq6Ovbt29esG4KKi4tjwYIFsWTJknjooYdiyJAhcdZZZ8XKlSubvI4biACgffIMd9q8oqKiiHjnTvfi4uJM+/bt2xt8k3ug0tLSmDFjRma/trZW6A5Ao5IkyXYJALQzzbkhaMiQITFkyJDM/pgxY2LLli1x6623xhlnnNHoOeXl5TFr1qz0CgYAWoU73GnzSkpKoqioKJYvX55p27NnT1RUVMSpp57a5Hl5eXnRq1evehsAAMAH0adPn+jatWuDu9nf74ag9zrllFPipZdeavJ4aWlp1NTUZLYtW7Ycds0AQOtxhzttwhtvvBEvv/xyZn/z5s2xYcOGOOqoo2LgwIExffr0mD17dgwePDgGDx4cs2fPjp49e8Yll1ySxaoBAIDO5ogjjohRo0bF8uXL4+/+7u8y7cuXL4/Pfe5zh/w6zzzzTL3f4H2vvLy8yMvL+0C1AgCtT+BOm7B27do488wzM/vvPgpm0qRJcc8998TMmTPjrbfeiilTpsSOHTvi5JNPjmXLlkV+fn62SgYAADqpGTNmxGWXXRajR4+OMWPGxIIFC6KysjImT54cEe/cnb5169a47777IiJi7ty5ceyxx8awYcNiz549sWjRoliyZEksWbIkm8MAAFqAwJ02Ydy4cQd9fm5OTk6UlZVFWVlZ6xUFAADQiC9+8Yvx2muvxY033hjbtm2L4cOHxyOPPBLHHHNMRERs27YtKisrM/337NkT1157bWzdujV69OgRw4YNi5/97Gdx7rnnZmsIAEALEbgDAABAM02ZMiWmTJnS6LF77rmn3v7MmTNj5syZrVAVAJBt/mgqAAAAAACkQOAOAAAAAAApELgDAAAAAEAKBO4AAAAAAJACgTsAAAAAAKRA4A4AAAAAACkQuAMAAAAAQAoE7gAAAAAAkAKBOwAAAAAApEDgDgAAAAAAKcjNdgHQEWzcuLFBW58+fWLgwIFZqAYAAAAAyAaBO3wg2yKiS0ycOLHBke7de8amTRuF7gAAAADQSXikDHwgr0fE/ohYFBHrDtgWxe7db0Z1dXUWawMAAAAAWpM73CEVQyPixGwXAQAAAABkkTvcAQAAAAAgBQJ3AAAAAABIgcAdAAAAAABSIHAHAAAAAIAUCNwBAAAAACAFAncAAAAAAEiBwB0AAAAAAFKQm+0CAABouyorK6O6urpBe58+fWLgwIGH3L+uri7y8vIatG/cuDGdQg9y7aZqPdxzWlpbrKkpTdUa0Tbrba6OPr40taf3LQBASxK4AwDQqMrKyhgyZGjs3v1mg2Pdu/eMTZs21gvSDtY/omtE7GsztR7uOS2tLdbUlIN/vdtevc3V0ceXpvb0vgUAaGkCd2hBTd21504fANqD6urqvwRoiyJi6AFHNsbu3ROjurq63nrWdP9HIuKfGmk/8Fjr1nq457S0tlhTU5quNaIt1ttcHX18aWpP71sAgJYmcIcWsS0iusTEiRMbPepOHwDal6ERceIH6L+xifYDj6WlubUe7jktrS3W1JT2VOvh6OjjS5O5AgAQuEOLeD0i9oc7ogAAAACg8xC4Q4tylw8AAAAAdBZdsl0AAAAAAAB0BAJ3AAAAAABIgcAdAAAAAABSIHAHAAAAAIAUCNwBAAAAACAFAncAAAAAAEiBwB0AAAAAAFIgcAcAAAAAgBTkZrsA6Kw2btzYoK1Pnz4xcODALFQDAAAAAHxQAndoddsioktMnDixwZHu3XvGpk0bhe4AAAAA0A55pAy0utcjYn9ELIqIdQdsi2L37jejuro6i7UBAAAAAIfLHe6QNUMj4sRsFwEAAAAApMQd7gAAAAAAkAKBOwAAAAAApEDgDgAAAAAAKfAMd6BDqaysbPQPz/bp0ycGDhyYhYpoDl8/AAAAoD0TuAMdRmVlZQwZMjR2736zwbHu3XvGpk0bhbZtmK8fAAAA0N55pAzQYVRXV/8lrF0UEesO2BbF7t1vNnrnNG2Hrx8AAADQ3rnDHeiAhkbEidkugsPm6wcAAAC0T+5wBwAAAACAFAjcAQAAAAAgBR4pA+1AZWVlo8+v7tOnT7P/iGRzX6up/nV1dZGXl9foNZo61txrHM74mqs15ra583E4sjmOtL7eGzdubFadh6Opa0e0zfdnmjrKOAAAAKAtE7hDG1dZWRlDhgz9yx+TrK97956xadPGQw7LmvtaB+sf0TUi9jVxpcaPNfcazR1fc7XW3DZnPg5HtseR1te7pb3ftdva+zNNHWUcAAAA0NZ5pAztyh133BElJSXRvXv3GDVqVDzxxBPZLqnFVVdX/yUkWxQR6w7YFsXu3W82ebduGq/VdP9/iXcC1ve2H+xYc6/R/PE1V+vMbfPmo/2NI62v97uv1XIOfu229/5MU0cZR2vojOsMAIenuWtGRUVFjBo1Krp37x6DBg2KO++8s5UqBQBakzvcaTcefPDBmD59etxxxx1x2mmnxfe///2YMGFCvPDCC53kzsyhEXFill7rvf03NtH+fsfSrClNLTm3hzsfaVw7zddqahxpfr1b/pEyTV+7Jc5pizrKOFqGdQaAQ9XcNWPz5s1x7rnnxje/+c1YtGhR/OpXv4opU6bE0UcfHRdffHEWRgAAtBR3uNNuzJkzJ77+9a/HN77xjRg6dGjMnTs3BgwYEPPnz892aQB0ANYZAA5Vc9eMO++8MwYOHBhz586NoUOHxje+8Y342te+FrfeemsrVw4AtDSBO+3Cnj17Yt26dTF+/Ph67ePHj49Vq1ZlqSoAOgrrDACH6nDWjNWrVzfof84558TatWvj7bffbrFaAYDW55EytAvV1dWxb9++KCwsrNdeWFgYVVVVjZ5TV1cXdXV1mf2ampqIiKitrW329d94442//Ne6iHjjgCMbm9l+sGOb3mldt+6A60Vs2rSpWf3f1aVLl9i/f3+9tua+VtP9O/r40rx28+ajqdc/vGs3/xrNH0daX+/mv9bBxtG8eTqcetP7+rVG+/uN44033mj2Z+O7/ZMkadZ5bVXbXWcimv/vL51/rxHZXjdafj1J8994c9ubOtaePncO53O1pWtK87U6+vjSvEZLrDMRbXetOZw1o6qqqtH+e/fujerq6iguLm5wTprrTESaP9Ok+TNQ+/pe+XC/10rjGk0dy+bPQK3RntZrtcZn+uF9H5S9n3XSG0fLv3c62zpDB5BAO7B169YkIpJVq1bVa//Xf/3XZMiQIY2ec8MNNyQRYbPZbLYW3LZs2dIay0CLs87YbDZb293a2lpzOGvG4MGDk9mzZ9dre/LJJ5OISLZt29boOdYZm81ma52tra0ztH/ucKdd6NOnT3Tt2rXBHSPbt29vcKfIu0pLS2PGjBmZ/f3798ef//zn6N27d+Tk5DTr+rW1tTFgwIDYsmVL9OrVq/kD6CTM06ExT4fGPB2abM1TkiSxc+fO6NevX6tdsyVZZ7LH2Dvf2DvruCOMvbljb6trzeGsGUVFRY32z83Njd69ezd6ThrrTGd+z72XuXiHeXiHefirzjwXbXWdof0TuNMuHHHEETFq1KhYvnx5/N3f/V2mffny5fG5z32u0XPy8vIiLy+vXtuHP/zhD1RHr169Ot0CdDjM06ExT4fGPB2abMxTQUFBq16vJVlnss/YO9/YO+u4I4y9OWNvi2vN4awZY8aMiZ/+9Kf12pYtWxajR4+Obt26NXpOmutMZ37PvZe5eId5eId5+KvOOhdtcZ2h/RO4027MmDEjLrvsshg9enSMGTMmFixYEJWVlTF58uRslwZAB2CdAeBQvd+aUVpaGlu3bo377rsvIiImT54c8+bNixkzZsQ3v/nNWL16ddx9991x//33Z3MYAEALELjTbnzxi1+M1157LW688cbYtm1bDB8+PB555JE45phjsl0aAB2AdQaAQ/V+a8a2bduisrIy07+kpCQeeeSRuOaaa+L222+Pfv36xW233RYXX3xxtoYAALQQgTvtypQpU2LKlCmtft28vLy44YYbGvxKJ/WZp0Njng6NeTo05ild1pnWZ+ydb+ydddwRxt7Rxn6wNeOee+5p0DZ27NhYv359C1dVX0ec98NlLt5hHt5hHv7KXED6cpIkSbJdBAAAAAAAtHddsl0AAAAAAAB0BAJ3AAAAAABIgcAdAAAAAABSIHAHAAAAAIAUCNzhfdxxxx1RUlIS3bt3j1GjRsUTTzyR7ZJSs3LlyrjggguiX79+kZOTEz/+8Y/rHU+SJMrKyqJfv37Ro0ePGDduXDz//PP1+tTV1cWVV14Zffr0iSOPPDI++9nPxh/+8Id6fXbs2BGXXXZZFBQUREFBQVx22WXx+uuv1+tTWVkZF1xwQRx55JHRp0+fuOqqq2LPnj0tMexmKy8vj5NOOiny8/Ojb9++ceGFF8amTZvq9TFXEfPnz48TTjghevXqFb169YoxY8bEo48+mjlujhpXXl4eOTk5MX369Eybuep8OvJa05hD+VztLBr7DOjItm7dGhMnTozevXtHz54945Of/GSsW7cu22W1qL1798Y//uM/RklJSfTo0SMGDRoUN954Y+zfvz/bpaUuje8tab7mriEVFRUxatSo6N69ewwaNCjuvPPOVqq05TVnLh566KE4++yz4+ijj8587/rzn/+8FattOYf7fcWvfvWryM3NjU9+8pMtW2Arae481NXVxfXXXx/HHHNM5OXlxf/6X/8rfvCDH7RStS2ruXPxwx/+MEaMGBE9e/aM4uLi+OpXvxqvvfZaK1ULHUACNOmBBx5IunXrltx1113JCy+8kFx99dXJkUcembz66qvZLi0VjzzySHL99dcnS5YsSSIiWbp0ab3j3/3ud5P8/PxkyZIlyXPPPZd88YtfTIqLi5Pa2tpMn8mTJycf/ehHk+XLlyfr169PzjzzzGTEiBHJ3r17M33+9m//Nhk+fHiyatWqZNWqVcnw4cOT888/P3N87969yfDhw5MzzzwzWb9+fbJ8+fKkX79+ybRp01p8Dg7FOeeckyxcuDD57W9/m2zYsCE577zzkoEDByZvvPFGpo+5SpKHH344+dnPfpZs2rQp2bRpU3Ldddcl3bp1S377298mSWKOGvP0008nxx57bHLCCSckV199dabdXHUuHX2tacyhfK52Bk19BnRUf/7zn5Njjjkmufzyy5Nf//rXyebNm5Nf/OIXycsvv5zt0lrUv/7rvya9e/dO/uu//ivZvHlz8p//+Z/Jhz70oWTu3LnZLi11aXxvSfM0dw155ZVXkp49eyZXX3118sILLyR33XVX0q1bt+RHP/pRK1eevubOxdVXX53cfPPNydNPP528+OKLSWlpadKtW7dk/fr1rVx5ug73+4rXX389GTRoUDJ+/PhkxIgRrVNsCzqcefjsZz+bnHzyycny5cuTzZs3J7/+9a+TX/3qV61Ydcto7lw88cQTSZcuXZLvfe97ySuvvJI88cQTybBhw5ILL7ywlSuH9kvgDgfxN3/zN8nkyZPrtR133HHJd77znSxV1HLe+0PR/v37k6KiouS73/1upm337t1JQUFBcueddyZJ8s43Zd26dUseeOCBTJ+tW7cmXbp0SR577LEkSZLkhRdeSCIieeqppzJ9Vq9enURE8rvf/S5Jknd+OOvSpUuydevWTJ/7778/ycvLS2pqalpkvB/E9u3bk4hIKioqkiQxVwfzkY98JPnf//t/m6NG7Ny5Mxk8eHCyfPnyZOzYsZmwzVx1Pp1prWnKez9XO4OmPgM6sm9/+9vJ6aefnu0yWt15552XfO1rX6vXdtFFFyUTJ07MUkWt43C+t6T5mruGzJw5MznuuOPqtV1xxRXJKaec0mI1tpY01tPjjz8+mTVrVtqltarDnYcvfvGLyT/+4z8mN9xwQ4cI3Js7D48++mhSUFCQvPbaa61RXqtq7lz827/9WzJo0KB6bbfddlvSv3//FqsROhqPlIEm7NmzJ9atWxfjx4+v1z5+/PhYtWpVlqpqPZs3b46qqqp648/Ly4uxY8dmxr9u3bp4++236/Xp169fDB8+PNNn9erVUVBQECeffHKmzymnnBIFBQX1+gwfPjz69euX6XPOOedEXV1dm/w185qamoiIOOqooyLCXDVm37598cADD8SuXbtizJgx5qgRU6dOjfPOOy8+85nP1Gs3V51LZ19r3vXez9XOoKnPgI7s4YcfjtGjR8cXvvCF6Nu3b4wcOTLuuuuubJfV4k4//fT47//+73jxxRcjIuI3v/lNPPnkk3HuuedmubLWdSjrG81zOGvI6tWrG/Q/55xzYu3atfH222+3WK0tLY31dP/+/bFz5852vRYd7jwsXLgwfv/738cNN9zQ0iW2isOZh3fXqFtuuSU++tGPxsc//vG49tpr46233mqNklvM4czFqaeeGn/4wx/ikUceiSRJ4k9/+lP86Ec/ivPOO681SoYOITfbBUBbVV1dHfv27YvCwsJ67YWFhVFVVZWlqlrPu2NsbPyvvvpqps8RRxwRH/nIRxr0eff8qqqq6Nu3b4PX79u3b70+773ORz7ykTjiiCPa3FwnSRIzZsyI008/PYYPHx4R5upAzz33XIwZMyZ2794dH/rQh2Lp0qVx/PHHZ76ZM0fveOCBB2L9+vWxZs2aBse8nzqXzr7WRDT+udrRHewzoCN75ZVXYv78+TFjxoy47rrr4umnn46rrroq8vLy4itf+Uq2y2sx3/72t6OmpiaOO+646Nq1a+zbty9uuumm+PKXv5zt0lrVoaxvNM/hrCGNrf2FhYWxd+/eqK6ujuLi4hartyWlsZ7++7//e+zatSv+/u//viVKbBWHMw8vvfRSfOc734knnngicnM7RkR0OPPwyiuvxJNPPhndu3ePpUuXRnV1dUyZMiX+/Oc/t+vnuB/OXJx66qnxwx/+ML74xS/G7t27Y+/evfHZz342/uM//qM1SoYOoWN8mkILysnJqbefJEmDto7scMb/3j6N9T+cPm3BtGnT4tlnn40nn3yywTFzFTFkyJDYsGFDvP7667FkyZKYNGlSVFRUZI6bo4gtW7bE1VdfHcuWLYvu3bs32c9cdS6dea052OdqR3SonwEd0f79+2P06NExe/bsiIgYOXJkPP/88zF//vwOHbg/+OCDsWjRoli8eHEMGzYsNmzYENOnT49+/frFpEmTsl1eq+vMn3ctpblz2lj/xtrbo8N9f91///1RVlYWP/nJTxq9YaG9OdR52LdvX1xyySUxa9as+PjHP95a5bWa5rwf9u/fHzk5OfHDH/4wCgoKIiJizpw58fnPfz5uv/326NGjR4vX25KaMxcvvPBCXHXVVfHP//zPcc4558S2bdviW9/6VkyePDnuvvvu1igX2j2PlIEm9OnTJ7p27drg//pu3769wf8d7oiKiooiIg46/qKiotizZ0/s2LHjoH3+9Kc/NXj9//f//l+9Pu+9zo4dO+Ltt99uU3N95ZVXxsMPPxyPP/549O/fP9Nurv7qiCOOiI997GMxevToKC8vjxEjRsT3vvc9c3SAdevWxfbt22PUqFGRm5sbubm5UVFREbfddlvk5uZmajRXnUNnX2ua+lztyN7vM2Dfvn3ZLrHFFBcXx/HHH1+vbejQoVFZWZmlilrHt771rfjOd74TX/rSl+ITn/hEXHbZZXHNNddEeXl5tktrVYfyvQDNczhrSGNr//bt2yM3Nzd69+7dYrW2tA+ynj744IPx9a9/Pf7v//2/7f4xX82dh507d8batWtj2rRpmTXpxhtvjN/85jeRm5sbv/zlL1ur9FQdzvuhuLg4PvrRj2bC9oh31qgkSeIPf/hDi9bbkg5nLsrLy+O0006Lb33rW3HCCSfEOeecE3fccUf84Ac/iG3btrVG2dDuCdyhCUcccUSMGjUqli9fXq99+fLlceqpp2apqtZTUlISRUVF9ca/Z8+eqKioyIx/1KhR0a1bt3p9tm3bFr/97W8zfcaMGRM1NTXx9NNPZ/r8+te/jpqamnp9fvvb39ZbvJctWxZ5eXkxatSoFh3noUiSJKZNmxYPPfRQ/PKXv4ySkpJ6x81V05Ikibq6OnN0gLPOOiuee+652LBhQ2YbPXp0XHrppbFhw4YYNGiQuepEOuta836fqx3Z+30GdO3aNdsltpjTTjstNm3aVK/txRdfjGOOOSZLFbWON998M7p0qf9jV9euXWP//v1Zqig7DuV7AZrncNaQMWPGNOi/bNmyGD16dHTr1q3Fam1ph7ue3n///XH55ZfH4sWLO8TzqZs7D7169WqwJk2ePDnzW6sH/i2g9uRw3g+nnXZa/PGPf4w33ngj0/biiy9Gly5d2vVNAYczF02tWxF//Y0Y4H20+J9lhXbsgQceSLp165bcfffdyQsvvJBMnz49OfLII5P/+Z//yXZpqdi5c2fyzDPPJM8880wSEcmcOXOSZ555Jnn11VeTJEmS7373u0lBQUHy0EMPJc8991zy5S9/OSkuLk5qa2szrzF58uSkf//+yS9+8Ytk/fr1yac//elkxIgRyd69ezN9/vZv/zY54YQTktWrVyerV69OPvGJTyTnn39+5vjevXuT4cOHJ2eddVayfv365Be/+EXSv3//ZNq0aa03GQfxD//wD0lBQUGyYsWKZNu2bZntzTffzPQxV0lSWlqarFy5Mtm8eXPy7LPPJtddd13SpUuXZNmyZUmSmKODGTt2bHL11Vdn9s1V59LR15rGHMrnamfy3s+Ajurpp59OcnNzk5tuuil56aWXkh/+8IdJz549k0WLFmW7tBY1adKk5KMf/WjyX//1X8nmzZuThx56KOnTp08yc+bMbJeWujS+t6R53m8N+c53vpNcdtllmf6vvPJK0rNnz+Saa65JXnjhheTuu+9OunXrlvzoRz/K1hBS09y5WLx4cZKbm5vcfvvt9dai119/PVtDSEVz5+G9brjhhmTEiBGtVG3Lae487Ny5M+nfv3/y+c9/Pnn++eeTioqKZPDgwck3vvGNbA0hNc2di4ULFya5ubnJHXfckfz+979PnnzyyWT06NHJ3/zN32RrCNDuCNzhfdx+++3JMccckxxxxBHJiSeemFRUVGS7pNQ8/vjjSUQ02CZNmpQkSZLs378/ueGGG5KioqIkLy8vOeOMM5Lnnnuu3mu89dZbybRp05Kjjjoq6dGjR3L++ecnlZWV9fq89tpryaWXXprk5+cn+fn5yaWXXprs2LGjXp9XX301Oe+885IePXokRx11VDJt2rRk9+7dLTn8Q9bYHEVEsnDhwkwfc5UkX/va1zL/Vo4++ujkrLPOyoTtSWKODua9YZu56nw68lrTmEP5XO1MOkvgniRJ8tOf/jQZPnx4kpeXlxx33HHJggULsl1Si6utrU2uvvrqZODAgUn37t2TQYMGJddff31SV1eX7dJSl8b3ljTfwdaQSZMmJWPHjq3Xf8WKFcnIkSOTI444Ijn22GOT+fPnt3LFLac5czF27NiDvl/bs+a+Jw7UUQL3JGn+PGzcuDH5zGc+k/To0SPp379/MmPGjA5zM0Bz5+K2225Ljj/++KRHjx5JcXFxcumllyZ/+MMfWrlqaL9yksTvgwAAAAAAwAflGe4AAAAAAJACgTsAAAAAAKRA4A4AAAAAACkQuAMAAAAAQAoE7gAAAAAAkAKBOwAAAAAApEDgDgAAAAAAKRC4AwAAAABACgTuAAAAAACQAoE7AAAAAACkQOAOAAAAAAApELgDAAAAAEAKBO4AAAAAAJACgTsAAAAAAKRA4A4AAAAAACkQuAMAAAAAQAoE7gAAAAAAkAKBOwAAAAAApEDgDgAAAAAAKRC4AwAAAABACgTuAAAAAACQAoE7AAAAAACkQOAOAAAAAAApELgDAAAAAEAKBO4AAAAAAJACgTsAAAAAAKRA4A4AAAAAACkQuAMAAAAAQAoE7gAAAAAAkAKBOwAAAAAApEDgDgAAAAAAKRC4AwAAAABACgTuAAAAAACQgv8PknePQCUBZx0AAAAASUVORK5CYII=' width=1500.0/>\n",
" </div>\n",
" "
],
"text/plain": [
"Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig=plt.figure(figsize=(15, 5))\n",
"ax = plt.subplot(1, 3, 1)\n",
"plt.hist(weight, color='blue', edgecolor='black', bins=50)\n",
"ax = plt.subplot(1, 3, 2)\n",
"plt.hist(weight[weight <= 10], color='blue', edgecolor='black', bins=50)\n",
"ax = plt.subplot(1, 3, 3)\n",
"plt.hist(weight[weight <= 1], color='blue', edgecolor='black', bins=50)\n",
"plt.close(fig)\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 75,
"id": "e6a61e8d-5c55-4312-a48a-a168817e7d77",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0 None\n",
"1 [cardboard]\n",
"2 None\n",
"3 [cardboard]\n",
"4 [metal]\n",
" ... \n",
"162 [plastic]\n",
"163 None\n",
"164 [fabric]\n",
"165 None\n",
"166 [stoneware]\n",
"Name: raw_specifications, Length: 167, dtype: object"
]
},
"execution_count": 75,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"materials = data[\"raw_specifications\"].apply(parse_value, value=\"materials\")\n",
"\n",
"# scoreable materials are:\n",
"# * metal\n",
"# * wood\n",
"# * glass\n",
"# * resin\n",
"# * fabric\n",
"# * plastic\n",
"\n",
"def material_classifier(material: str) -> str:\n",
" \"\"\"I will to match materials to one of the scoreable ones:\n",
" * metal\n",
" * wood\n",
" * glass\n",
" * resin\n",
" * fabric\n",
" * plastic\n",
" I found a few, like stoneware and cardboard that I can't fit\n",
" there, they'll have to remain unscored for now\"\"\"\n",
"\n",
" mapping = {\n",
" \"polyester\": \"fabric\",\n",
" \"spandex\": \"fabric\",\n",
" \"leather\": \"fabric\",\n",
" \"cardboard\": \"carboard\",\n",
" \"crystal\": \"glass\",\n",
" \"hardwood\": \"wood\",\n",
" \"plywood\": \"wood\",\n",
" \"mdf\": \"wood\",\n",
" \"wood\": \"wood\",\n",
" \"steel\": \"metal\",\n",
" \"polycarbonate\": \"plastic\",\n",
" \"polypropylene\": \"plastic\",\n",
" \"pvc\": \"plastic\",\n",
" \"resin\": \"plastic\",\n",
" \"stoneware\": \"stoneware\",\n",
" \"cardboard\": \"cardboard\",\n",
" \"paper\": \"cardboard\",\n",
" }\n",
" for key, value in mapping.items():\n",
" if key in material:\n",
" return value\n",
" return material\n",
"\n",
"def clean_material_name(material: str) -> str:\n",
" no_paren_annotations = re.sub(\"\\(.*\\)\", \"\", material)\n",
" no_amounts = re.sub(\"\\d+%?\", \"\", no_paren_annotations)\n",
" return no_amounts.strip().lower()\n",
" \n",
"def parse_materials(materials: str):\n",
" if materials is None:\n",
" return\n",
" material_ls = [\n",
" material_classifier(clean_material_name(x))\n",
" for x in materials.split(\",\")\n",
" ]\n",
" return list(set(material_ls))\n",
"\n",
"clean_materials = materials.apply(parse_materials)\n",
"clean_materials"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1f0e0e98-d205-4cb1-9e67-e449432fa7e4",
"metadata": {},
"outputs": [],
"source": [
"clean_materials"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "f6fcaae9-9c24-450c-8737-8b6aa0e406a9",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0 1\n",
"1 1\n",
"2 1\n",
"3 24\n",
"4 1\n",
" ... \n",
"162 1\n",
"163 1\n",
"164 1\n",
"165 1\n",
"166 1\n",
"Name: raw_specifications, Length: 167, dtype: object"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"packaging = data[\"raw_specifications\"].apply(parse_value, value=\"packaging\")\n",
"packaging[packaging.isnull()] = 1\n",
"packaging"
]
},
{
"cell_type": "code",
"execution_count": 41,
"id": "f6ed2736-26d2-403f-9ab0-a228057176e4",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{NoneType, dict}"
]
},
"execution_count": 41,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def clean_origin_name(origin: str) -> str:\n",
" mapping = {\n",
" \"assem usa w/foreign/dom. parts\": \"mixed\",\n",
" \"imported\": \"imported\",\n",
" \"made in the usa\": \"usa\",\n",
" \"made in the usa or imported\": \"mixed\",\n",
" }\n",
" origin = origin.lower().strip()\n",
" return mapping[origin]\n",
"\n",
"origin = data[\"raw_specifications\"].apply(parse_value, value=\"origin\")\n",
"clean_origin = origin.apply(clean_origin_name)\n",
"clean_origin"
]
},
{
"cell_type": "code",
"execution_count": 46,
"id": "d2df0c7e-cd03-4628-ae29-fae4f0f37dfa",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>materials</th>\n",
" <th>packaging</th>\n",
" <th>origin</th>\n",
" <th>weight</th>\n",
" <th>height</th>\n",
" <th>width</th>\n",
" <th>depth</th>\n",
" <th>tcin</th>\n",
" <th>primary_category</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>[metal]</td>\n",
" <td>1</td>\n",
" <td>imported</td>\n",
" <td>2109.202800</td>\n",
" <td>58.420</td>\n",
" <td>2.540</td>\n",
" <td>58.420</td>\n",
" <td>86345566</td>\n",
" <td>Home</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>[glass]</td>\n",
" <td>1</td>\n",
" <td>mixed</td>\n",
" <td>0.080297</td>\n",
" <td>20.320</td>\n",
" <td>4.445</td>\n",
" <td>4.445</td>\n",
" <td>75552641</td>\n",
" <td>Holiday Shop</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>[wood]</td>\n",
" <td>1</td>\n",
" <td>mixed</td>\n",
" <td>0.275303</td>\n",
" <td>13.335</td>\n",
" <td>10.160</td>\n",
" <td>10.160</td>\n",
" <td>81632725</td>\n",
" <td>Holiday Shop</td>\n",
" </tr>\n",
" <tr>\n",
" <th>11</th>\n",
" <td>[fabric]</td>\n",
" <td>1</td>\n",
" <td>mixed</td>\n",
" <td>2.726807</td>\n",
" <td>33.020</td>\n",
" <td>20.320</td>\n",
" <td>20.320</td>\n",
" <td>81726538</td>\n",
" <td>Holiday Shop</td>\n",
" </tr>\n",
" <tr>\n",
" <th>15</th>\n",
" <td>[metal]</td>\n",
" <td>1</td>\n",
" <td>imported</td>\n",
" <td>1360.776000</td>\n",
" <td>74.930</td>\n",
" <td>1.270</td>\n",
" <td>31.115</td>\n",
" <td>86435324</td>\n",
" <td>Home</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" materials packaging origin weight height width depth \\\n",
"4 [metal] 1 imported 2109.202800 58.420 2.540 58.420 \n",
"5 [glass] 1 mixed 0.080297 20.320 4.445 4.445 \n",
"6 [wood] 1 mixed 0.275303 13.335 10.160 10.160 \n",
"11 [fabric] 1 mixed 2.726807 33.020 20.320 20.320 \n",
"15 [metal] 1 imported 1360.776000 74.930 1.270 31.115 \n",
"\n",
" tcin primary_category \n",
"4 86345566 Home \n",
"5 75552641 Holiday Shop \n",
"6 81632725 Holiday Shop \n",
"11 81726538 Holiday Shop \n",
"15 86435324 Home "
]
},
"execution_count": 46,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def get_val(xs, i):\n",
" if xs is None:\n",
" return None\n",
" return xs.get(i)\n",
"\n",
"clean_data = pd.DataFrame(\n",
" data={\n",
" \"materials\": clean_materials,\n",
" \"packaging\": packaging,\n",
" \"origin\": clean_origin,\n",
" \"weight\": weight,\n",
" \"height\": dimensions.apply(get_val, i=\"height\"),\n",
" \"width\": dimensions.apply(get_val, i=\"width\"),\n",
" \"depth\": dimensions.apply(get_val, i=\"depth\"),\n",
" \"tcin\": data[\"raw_specifications\"].apply(parse_value, value=\"tcin\"),\n",
" \"primary_category\": data[\"primary_category\"]\n",
" }\n",
")\n",
"\n",
"clean_data\n",
"\n",
"clean_data[~clean_data.isnull().any(axis=1)].head()"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "427c5d6a-8f8b-4441-89c5-193d647b49e2",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"4 23271231140\n",
"Name: gtin13, dtype: int64"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"weight = data[\"raw_specifications\"].apply(parse_value, value=\"weight\")\n",
"sel = weight == \" 4.65 pounds\"\n",
"data.loc[sel, \"gtin13\"]"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.4"
}
},
"nbformat": 4,
"nbformat_minor": 5
}