{"@attributes":{"version":"2.0"},"channel":{"title":"Tom's Blog","link":"https:\/\/tomaugspurger.net\/","description":"Recent content on Tom's Blog","generator":"Hugo -- 0.147.0","language":"en-us","lastBuildDate":"Sun, 28 Dec 2025 15:00:24 -0600","item":[{"title":"My 2025 Year in Books","link":"https:\/\/tomaugspurger.net\/posts\/books-2025\/","pubDate":"Sun, 28 Dec 2025 15:00:24 -0600","guid":"https:\/\/tomaugspurger.net\/posts\/books-2025\/","description":"<p>It&rsquo;s time for another review for books I read this year (previously: <a href=\"books-2024.md\">2024<\/a>, <a href=\"books-2022.md\">2022<\/a>). According to my <a href=\"https:\/\/www.goodreads.com\/user\/year_in_books\/2025\/82176424\">GoodReads<\/a>, I read 27 books this year.\nHere are some highlights:<\/p>\n<h2 id=\"the-demon-haunted-world\">The Demon-Haunted World<\/h2>\n<p><a href=\"https:\/\/www.goodreads.com\/book\/show\/17349.The_Demon_Haunted_World\"><img src=\"https:\/\/m.media-amazon.com\/images\/S\/compressed.photo.goodreads.com\/books\/1553691804i\/17349.jpg\" width=\"200px\"\/><\/a><\/p>\n<p>I started the year with Carl Sagan&rsquo;s <em>The Demon-Haunted World<\/em>, as some kind of antidote to current \/ coming events.\nI last read this in about 2010, and held it in very high regard. I still do, but Carl comes off as a <em>bit<\/em> of a fuddy duddy at times (especially when talking about &ldquo;the youth&rdquo; today \/ in the 1990s). That&rsquo;s not to say that he&rsquo;s wrong about where society has gone (quiet the opposite), but it as a kind of tone. If you&rsquo;re interested in an introduction to skepticism, I&rsquo;d probably recommend the <a href=\"https:\/\/www.theskepticsguide.org\/our-book\/our-book-how-to-know-whats-really-real-in-a-world-increasingly-full-of-fake-the-skeptics-guide-to-the-universe\"><em>Skeptic&rsquo;s Guide to the Universe<\/em><\/a>.<\/p>"},{"title":"GPU-Accelerated Zarr","link":"https:\/\/tomaugspurger.net\/posts\/gpu-accelerated-zarr\/","pubDate":"Thu, 11 Dec 2025 08:00:00 -0600","guid":"https:\/\/tomaugspurger.net\/posts\/gpu-accelerated-zarr\/","description":"<p>This post gives detailed background to my PyData Global talk, &ldquo;GPU-Accelerated\nZarr&rdquo; (<a href=\"https:\/\/assets.tomaugspurger.net\/tomaugspurger\/posts\/gpu-accelerated-zarr\/GPU%20Acceleterated%20Zarr.pdf\">slides<\/a>, <a href=\"https:\/\/youtu.be\/dYt_fabaK60\">video<\/a>). It\ndeliberately gets into the weeds, but I will try to provide some background for\npeople who are new to Zarr, GPUs, or both.<\/p>\n<p>The first takeaway is that zarr-python <a href=\"https:\/\/zarr.readthedocs.io\/en\/stable\/user-guide\/gpu\/\">natively supports<\/a>\nNVIDIA GPUs. With a one-line <code>zarr.config.enable_gpu()<\/code> you can configure zarr\nto return CuPy arrays, which reside on your GPU:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"><code class=\"language-python\" data-lang=\"python\"><span style=\"display:flex;\"><span><span style=\"color:#f92672\">&gt;&gt;&gt;<\/span> <span style=\"color:#f92672\">import<\/span> zarr\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#f92672\">&gt;&gt;&gt;<\/span> zarr<span style=\"color:#f92672\">.<\/span>config<span style=\"color:#f92672\">.<\/span>enable_gpu()\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#f92672\">&gt;&gt;&gt;<\/span> z <span style=\"color:#f92672\">=<\/span> zarr<span style=\"color:#f92672\">.<\/span>open_array(<span style=\"color:#e6db74\">&#34;path\/to\/store.zarr&#34;<\/span>, mode<span style=\"color:#f92672\">=<\/span><span style=\"color:#e6db74\">&#34;r&#34;<\/span>)\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#f92672\">&gt;&gt;&gt;<\/span> type(z[:])\n<\/span><\/span><span style=\"display:flex;\"><span>cupy<span style=\"color:#f92672\">.<\/span>ndarray\n<\/span><\/span><\/code><\/pre><\/div><p>The second takeaway, and the main focus of this post, is that that simple\none-liner leaves performance on the table. It depends a bit on your workload,\nbut I&rsquo;d claim that Zarr&rsquo;s data loading pipeline <em>shouldn&rsquo;t<\/em> ever be the\nbottleneck. Achieving maximum throughput today requires some care to ensure that\nthe system&rsquo;s resources are used efficiently. I&rsquo;m hopeful that we can improve the\nlibraries to do the right thing in more situations.<\/p>"},{"title":"Gone Sailing","link":"https:\/\/tomaugspurger.net\/posts\/gone-sailing\/","pubDate":"Sat, 18 Oct 2025 07:40:38 -0500","guid":"https:\/\/tomaugspurger.net\/posts\/gone-sailing\/","description":"<p>Last weekend I had the chance to sail in the <a href=\"https:\/\/saylorvilleyachtclub.wildapricot.org\/2025-Corn-Coast-Regatta\">2025 Corn Coast Regatta<\/a>. I had\nsuch a great time that I had to jot down my thoughts before they fade. This\npost is mostly for (future) me. We&rsquo;ll return to our regularly scheduled\nprogramming in a future post. I have a post on Zarr performance cooking.<\/p>\n<p>First, some context: in August I attended the <a href=\"https:\/\/sycss.wildapricot.org\">Saylorville Yatch Club Sailing\nSchool<\/a> Adult Small Boat class. This is a 3-day course that mixes some\ntime in the classroom learning the theory and jargon (so much jargon!) with a\nbunch of time on the water. I had a bit of experience from sailing on summer\nweekends with my family growing up, but I wanted to learn more before going out\non my own.<\/p>"},{"title":"Cloud Native Geospatial Conference (2025)","link":"https:\/\/tomaugspurger.net\/posts\/cng-forum-2025\/","pubDate":"Sun, 04 May 2025 00:00:00 -0600","guid":"https:\/\/tomaugspurger.net\/posts\/cng-forum-2025\/","description":"<p><em>You can watch a video version of this talk at <a href=\"https:\/\/youtu.be\/BFFHXNBj7nA\">https:\/\/youtu.be\/BFFHXNBj7nA<\/a><\/em><\/p>\n<p>On Thursday, I presented a talk, <em>GPU Accelerated Cloud-Native Geospatial<\/em>, at the\ninaugural Cloud-Native Geospatial Conference (<a href=\"https:\/\/tomaugspurger.net\/assets\/gpu-accelerated-cng.pdf\">slides<\/a> here). This post will\ngive an overview of the talk and some background on the prep. But first I wanted\nto say a bit about the conference itself.<\/p>\n<p>The organizers (Michelle Roby, Jed Sundell, and others from Radiant Earth) did a\nfantastic job putting on the event. I only have the smallest experience with\nhelping run a conference, but I know it&rsquo;s a ton of work. They did a great job\nhosting this first run of conference.<\/p>"},{"title":"High Performance Remote IO","link":"https:\/\/tomaugspurger.net\/posts\/high-performance-remote-io\/","pubDate":"Fri, 28 Feb 2025 15:18:34 -0600","guid":"https:\/\/tomaugspurger.net\/posts\/high-performance-remote-io\/","description":"<p>I have a new post up at the NVIDIA technical blog on <a href=\"https:\/\/developer.nvidia.com\/blog\/high-performance-remote-io-with-nvidia-kvikio\/\">High-Performance Remote IO with NVIDIA KvikIO<\/a>.<sup id=\"fnref:1\"><a href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\">1<\/a><\/sup><\/p>\n<p>This is mostly general-purpose advice on getting good performance out of cloud\nobject stores (I guess I can&rsquo;t get away from them), but has some specifics for\npeople using NVIDIA GPUs.<\/p>\n<blockquote>\n<p>In the RAPIDS context, NVIDIA KvikIO is notable because<\/p>\n<ol>\n<li>It automatically chunks large requests into multiple smaller ones and makes those requests concurrently.<\/li>\n<li>It can read efficiently into host or device memory, especially if GPU Direct Storage is enabled.<\/li>\n<li>It\u2019s fast.<\/li>\n<\/ol><\/blockquote>\n<p>As part of preparing this, I got to write some C++. Not a fan!<\/p>"},{"title":"Iowa's Proposed State Science Standards","link":"https:\/\/tomaugspurger.net\/posts\/iowa-academic-standards-2025\/","pubDate":"Sat, 01 Feb 2025 12:00:00 -0600","guid":"https:\/\/tomaugspurger.net\/posts\/iowa-academic-standards-2025\/","description":"<p>My local Department of Education has a <a href=\"https:\/\/educate.iowa.gov\/headline-story\/2025-01-03\/public-comment-period-opens-state-science-standards\">public comment\nperiod<\/a>\nfor some proposed changes to Iowa&rsquo;s science education standards. If you live in\nIowa, I&rsquo;d encourage you to read the\n<a href=\"https:\/\/educate.iowa.gov\/media\/10837\/download?inline\">proposal<\/a> (PDF) and share\nfeedback through the <a href=\"https:\/\/www.surveymonkey.com\/r\/GHS2RYC\">survey<\/a>. If you,\nlike me, get frustrated with how difficult it is to see what&rsquo;s changed or link\nto a specific piece of text, read on.<\/p>\n<p>I&rsquo;d heard rumblings that there were some controversial changes around evolution\nand climate change. But rather than just believing what I read in a headline, I\ndecided to do my own research (science in action, right?).<\/p>"},{"title":"Dask Geopandas Spatial Shuffle","link":"https:\/\/tomaugspurger.net\/posts\/dask-geopandas-spatial-shuffle\/","pubDate":"Wed, 18 Dec 2024 10:33:34 -0600","guid":"https:\/\/tomaugspurger.net\/posts\/dask-geopandas-spatial-shuffle\/","description":"<p>Over at <a href=\"https:\/\/github.com\/opengeospatial\/geoparquet\/discussions\/251\">https:\/\/github.com\/opengeospatial\/geoparquet\/discussions\/251<\/a>, we&rsquo;re\nhaving a nice discussion about how best to partition geoparquet files for\nserving over object storage. Thanks to geoparquet&rsquo;s design, just being an\nextension of parquet, it immediately benefits from all the wisdom around how\nbest to partition plain parquet datasets. The only additional wrinkle for\ngeoparquet is, unsurprisingly, the geo component.<\/p>\n<p>It&rsquo;s pretty common for users to read all the features in a small spatial area (a\ncity, say) so optimizing for that use case is a good default. Simplifying a bit,\nreading small spatial subsets of a larger dataset will be fastest if all the\nfeatures that are geographically close together are also &ldquo;close&rdquo; together in the\nparquet dataset, and each part of the parquet dataset only contains data that&rsquo;s\nphysically close together. That gives you the data you want in the fewest number\nof file reads \/ HTTP requests, and minimizes the amount of &ldquo;wasted&rdquo; reads (data\nthat&rsquo;s read, only to be immediately discarded because it&rsquo;s outside your area of\ninterest).<\/p>"},{"title":"My 2024 Year in Books","link":"https:\/\/tomaugspurger.net\/posts\/books-2024\/","pubDate":"Wed, 11 Dec 2024 08:00:00 -0600","guid":"https:\/\/tomaugspurger.net\/posts\/books-2024\/","description":"<p>Here&rsquo;s another Year in Books (I missed last year, but here&rsquo;s <a href=\"books-2022.md\">2022<\/a>).<\/p>\n<p>Most of these came from recommendations by friends, <a href=\"https:\/\/www.theincomparable.com\/theincomparable\/bookclub\/\"><em>The Incomparable<\/em>&rsquo;s Book\nClub<\/a> and (a new\nsource), the &ldquo;Books in the Box&rdquo; episodes of <a href=\"https:\/\/oxide.computer\/podcasts\/oxide-and-friends\">Oxide and\nFriends<\/a>.<\/p>\n<h2 id=\"the-soul-of-a-new-machine-by-tracy-kidder\"><em>The Soul of a New Machine<\/em>, by Tracy Kidder<\/h2>\n<p><a href=\"https:\/\/www.goodreads.com\/book\/show\/7090.The_Soul_of_a_New_Machine\"><img src=\"https:\/\/images-na.ssl-images-amazon.com\/images\/S\/compressed.photo.goodreads.com\/books\/1627012239i\/7090.jpg\" width=\"200px\"\/><\/a><\/p>\n<p>I technically read it in the last few days of 2023, but included here because I\nliked it so much. This came recommended by the Oxide and Friends podcast&rsquo;s\n<a href=\"https:\/\/oxide.computer\/podcasts\/oxide-and-friends\/955244\">Books in the Box<\/a>\nepisode. I didn&rsquo;t know a ton about the history of computing, but have been\npicking up an appreciation for it thanks to reading this book. It goes into a\nton of detail about what it took Data General to design and release a new\nmachine. Highly recommended to anyone interested in computing.<\/p>"},{"title":"Serializing Dataclasses","link":"https:\/\/tomaugspurger.net\/posts\/serializing-dataclasses\/","pubDate":"Sat, 31 Aug 2024 12:00:00 -0500","guid":"https:\/\/tomaugspurger.net\/posts\/serializing-dataclasses\/","description":"<p>This post is a bit of a tutorial on serializing and deserializing Python\n<a href=\"https:\/\/docs.python.org\/3\/library\/dataclasses.html\">dataclasses<\/a>. I&rsquo;ve been hacking on <a href=\"https:\/\/github.com\/zarr-developers\/zarr-python\/\">zarr-python-v3<\/a> a bit, which uses some\ndataclasses to represent some metadata objects. Those objects need to be\nserialized to and deserialized from JSON.<\/p>\n<p>This is a (surprisingly?) challenging area, and there are several excellent\nlibraries out there that you should probably use. My personal favorite is\n<a href=\"https:\/\/jcristharif.com\/msgspec\/\">msgspec<\/a>, but <a href=\"https:\/\/catt.rs\/en\/stable\/\">cattrs<\/a>, <a href=\"https:\/\/docs.pydantic.dev\/latest\/\">pydantic<\/a>, and <a href=\"https:\/\/yukinarit.github.io\/pyserde\/guide\/en\/\">pyserde<\/a> are also options. But\nhopefully this can be helpful for understanding how those libraries work at a\nconceptual level (their exact implementations will look very different.) In\nzarr-python&rsquo;s case, this didn&rsquo;t <em>quite<\/em> warrant needing to bring in a\ndependency, so we rolled our own.<\/p>"},{"title":"stac-geoparquet","link":"https:\/\/tomaugspurger.net\/posts\/stac-geoparquet\/","pubDate":"Thu, 29 Aug 2024 20:00:00 -0500","guid":"https:\/\/tomaugspurger.net\/posts\/stac-geoparquet\/","description":"<p>I wrote up a quick <a href=\"https:\/\/cloudnativegeo.org\/blog\/2024\/08\/introduction-to-stac-geoparquet\/\">introduction to stac-geoparquet<\/a> on the Cloud Native Geo blog with <a href=\"https:\/\/kylebarron.dev\/\">Kyle Barron<\/a> and <a href=\"https:\/\/beta.source.coop\/cholmes\">Chris Holmes<\/a>.<\/p>\n<p>The key takeaway:<\/p>\n<blockquote>\n<p>STAC GeoParquet offers a very convenient and high-performance way to distribute large STAC collections, provided the items in that collection are pretty homogenous<\/p><\/blockquote>\n<p>Check out the project at <a href=\"http:\/\/github.com\/stac-utils\/stac-geoparquet\">http:\/\/github.com\/stac-utils\/stac-geoparquet<\/a>.<\/p>"},{"title":"What's Next? (2024 edition)","link":"https:\/\/tomaugspurger.net\/posts\/leaving-microsoft\/","pubDate":"Mon, 12 Aug 2024 07:00:00 -0500","guid":"https:\/\/tomaugspurger.net\/posts\/leaving-microsoft\/","description":"<p>I have, as they say, some personal news to share. On Monday I (along with some <em>very<\/em> talented teammates, see <a href=\"#whats-next\">below<\/a> if you&rsquo;re hiring) was laid off from Microsoft as part of a reorganization. Like my <a href=\"https:\/\/tomaugspurger.net\/posts\/whats-next\">Moving to Microsoft<\/a> post, I wanted to jot down some of the things I got to work on.<\/p>\n<p>For those of you wondering, the <a href=\"https:\/\/planetarycomputer.microsoft.com\">Planetary Computer<\/a> project <em>does<\/em> continue, just without me.<\/p>\n<h2 id=\"reflections\">Reflections<\/h2>\n<p>It should go without saying that <em>all<\/em> of this was a team effort. I&rsquo;ve been incredibly fortunate to have great teammates over the years, but the team building out the <a href=\"http:\/\/planetarycomputer.microsoft.com\/\">Planetary Computer<\/a> was especially fantastic.\nJust like before, this will be very self-centered and project-focused, overlooking all the other people and work that went into this.<\/p>"},{"title":"My Real-World Match \/ Case","link":"https:\/\/tomaugspurger.net\/posts\/my-real-world-match\/","pubDate":"Wed, 13 Dec 2023 21:00:00 -0600","guid":"https:\/\/tomaugspurger.net\/posts\/my-real-world-match\/","description":"<p>Ned Batchelder recently shared <a href=\"https:\/\/nedbatchelder.com\/blog\/202312\/realworld_matchcase.html\">Real-world match\/case<\/a>, showing a real example of Python&rsquo;s <a href=\"https:\/\/peps.python.org\/pep-0636\/\">Structural Pattern Matching<\/a>. These real-world examples are a great complement to the tutorial, so I&rsquo;ll share mine.<\/p>\n<p>While working on some <a href=\"..\/stac-updates\">STAC + Kerchunk stuff<\/a>, in <a href=\"https:\/\/github.com\/stac-utils\/xstac\/pull\/38\">this pull request<\/a> I used the match statement to parse some nested objects:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"><code class=\"language-python\" data-lang=\"python\"><span style=\"display:flex;\"><span><span style=\"color:#66d9ef\">for<\/span> k, v <span style=\"color:#f92672\">in<\/span> refs<span style=\"color:#f92672\">.<\/span>items():\n<\/span><\/span><span style=\"display:flex;\"><span> <span style=\"color:#66d9ef\">match<\/span> k<span style=\"color:#f92672\">.<\/span>split(<span style=\"color:#e6db74\">&#34;\/&#34;<\/span>):\n<\/span><\/span><span style=\"display:flex;\"><span> <span style=\"color:#66d9ef\">case<\/span> [<span style=\"color:#e6db74\">&#34;.zgroup&#34;<\/span>]:\n<\/span><\/span><span style=\"display:flex;\"><span> <span style=\"color:#75715e\"># k = &#34;.zgroup&#34;<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span> item<span style=\"color:#f92672\">.<\/span>properties[<span style=\"color:#e6db74\">&#34;kerchunk:zgroup&#34;<\/span>] <span style=\"color:#f92672\">=<\/span> json<span style=\"color:#f92672\">.<\/span>loads(v)\n<\/span><\/span><span style=\"display:flex;\"><span> <span style=\"color:#66d9ef\">case<\/span> [<span style=\"color:#e6db74\">&#34;.zattrs&#34;<\/span>]:\n<\/span><\/span><span style=\"display:flex;\"><span> <span style=\"color:#75715e\"># k = &#34;.zattrs&#34;<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span> item<span style=\"color:#f92672\">.<\/span>properties[<span style=\"color:#e6db74\">&#34;kerchunk:zattrs&#34;<\/span>] <span style=\"color:#f92672\">=<\/span> json<span style=\"color:#f92672\">.<\/span>loads(v)\n<\/span><\/span><span style=\"display:flex;\"><span> <span style=\"color:#66d9ef\">case<\/span> [variable, <span style=\"color:#e6db74\">&#34;.zarray&#34;<\/span>]:\n<\/span><\/span><span style=\"display:flex;\"><span> <span style=\"color:#75715e\"># k = &#34;prcp\/.zarray&#34;<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span> <span style=\"color:#66d9ef\">if<\/span> u <span style=\"color:#f92672\">:=<\/span> item<span style=\"color:#f92672\">.<\/span>properties[<span style=\"color:#e6db74\">&#34;cube:dimensions&#34;<\/span>]<span style=\"color:#f92672\">.<\/span>get(variable):\n<\/span><\/span><span style=\"display:flex;\"><span> u[<span style=\"color:#e6db74\">&#34;kerchunk:zarray&#34;<\/span>] <span style=\"color:#f92672\">=<\/span> json<span style=\"color:#f92672\">.<\/span>loads(refs[k])\n<\/span><\/span><span style=\"display:flex;\"><span> <span style=\"color:#66d9ef\">elif<\/span> u <span style=\"color:#f92672\">:=<\/span> item<span style=\"color:#f92672\">.<\/span>properties[<span style=\"color:#e6db74\">&#34;cube:variables&#34;<\/span>]<span style=\"color:#f92672\">.<\/span>get(variable):\n<\/span><\/span><span style=\"display:flex;\"><span> u[<span style=\"color:#e6db74\">&#34;kerchunk:zarray&#34;<\/span>] <span style=\"color:#f92672\">=<\/span> json<span style=\"color:#f92672\">.<\/span>loads(refs[k])\n<\/span><\/span><span style=\"display:flex;\"><span> <span style=\"color:#66d9ef\">case<\/span> [variable, <span style=\"color:#e6db74\">&#34;.zattrs&#34;<\/span>]:\n<\/span><\/span><span style=\"display:flex;\"><span> <span style=\"color:#75715e\"># k = &#34;prcp\/.zattrs&#34;<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span> <span style=\"color:#66d9ef\">if<\/span> u <span style=\"color:#f92672\">:=<\/span> item<span style=\"color:#f92672\">.<\/span>properties[<span style=\"color:#e6db74\">&#34;cube:dimensions&#34;<\/span>]<span style=\"color:#f92672\">.<\/span>get(variable):\n<\/span><\/span><span style=\"display:flex;\"><span> u[<span style=\"color:#e6db74\">&#34;kerchunk:zattrs&#34;<\/span>] <span style=\"color:#f92672\">=<\/span> json<span style=\"color:#f92672\">.<\/span>loads(refs[k])\n<\/span><\/span><span style=\"display:flex;\"><span> <span style=\"color:#66d9ef\">elif<\/span> u <span style=\"color:#f92672\">:=<\/span> item<span style=\"color:#f92672\">.<\/span>properties[<span style=\"color:#e6db74\">&#34;cube:variables&#34;<\/span>]<span style=\"color:#f92672\">.<\/span>get(variable):\n<\/span><\/span><span style=\"display:flex;\"><span> u[<span style=\"color:#e6db74\">&#34;kerchunk:zattrs&#34;<\/span>] <span style=\"color:#f92672\">=<\/span> json<span style=\"color:#f92672\">.<\/span>loads(refs[k])\n<\/span><\/span><span style=\"display:flex;\"><span> <span style=\"color:#66d9ef\">case<\/span> [variable, index]:\n<\/span><\/span><span style=\"display:flex;\"><span> <span style=\"color:#75715e\"># k = &#34;prcp\/0.0.0&#34;<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span> <span style=\"color:#66d9ef\">if<\/span> u <span style=\"color:#f92672\">:=<\/span> item<span style=\"color:#f92672\">.<\/span>properties[<span style=\"color:#e6db74\">&#34;cube:dimensions&#34;<\/span>]<span style=\"color:#f92672\">.<\/span>get(variable):\n<\/span><\/span><span style=\"display:flex;\"><span> u<span style=\"color:#f92672\">.<\/span>setdefault(<span style=\"color:#e6db74\">&#34;kerchunk:value&#34;<\/span>, collections<span style=\"color:#f92672\">.<\/span>defaultdict(dict))\n<\/span><\/span><span style=\"display:flex;\"><span> u[<span style=\"color:#e6db74\">&#34;kerchunk:value&#34;<\/span>][index] <span style=\"color:#f92672\">=<\/span> refs[k]\n<\/span><\/span><span style=\"display:flex;\"><span> <span style=\"color:#66d9ef\">elif<\/span> u <span style=\"color:#f92672\">:=<\/span> item<span style=\"color:#f92672\">.<\/span>properties[<span style=\"color:#e6db74\">&#34;cube:variables&#34;<\/span>]<span style=\"color:#f92672\">.<\/span>get(variable):\n<\/span><\/span><span style=\"display:flex;\"><span> u<span style=\"color:#f92672\">.<\/span>setdefault(<span style=\"color:#e6db74\">&#34;kerchunk:value&#34;<\/span>, collections<span style=\"color:#f92672\">.<\/span>defaultdict(dict))\n<\/span><\/span><span style=\"display:flex;\"><span> u[<span style=\"color:#e6db74\">&#34;kerchunk:value&#34;<\/span>][index] <span style=\"color:#f92672\">=<\/span> refs[k]\n<\/span><\/span><\/code><\/pre><\/div><p>The <code>for<\/code> loop is iterating over a set of <a href=\"https:\/\/fsspec.github.io\/kerchunk\">Kerchunk<\/a> references, which are essentially the keys for a <a href=\"https:\/\/zarr.readthedocs.io\/en\/stable\/spec\/v2.html\">Zarr<\/a> group. The keys vary a bit. They could be:<\/p>"},{"title":"STAC Updates I'm Excited About","link":"https:\/\/tomaugspurger.net\/posts\/stac-updates\/","pubDate":"Sun, 15 Oct 2023 12:00:00 -0500","guid":"https:\/\/tomaugspurger.net\/posts\/stac-updates\/","description":"<p>I wanted to share an update on a couple of developments in the <a href=\"https:\/\/stacspec.org\/\">STAC<\/a> ecosystem\nthat I&rsquo;m excited about. It&rsquo;s a great sign that even after 2 years after its\ninitial release, the STAC ecosystem is still growing and improving how we can\ncatalog, serve, and access geospatial data.<\/p>\n<h2 id=\"stac-and-geoparquet\">STAC and Geoparquet<\/h2>\n<p>A STAC API is a great way to query for data. But, like any API serving JSON, its\nthroughput is limited. So in May 2022, the Planetary Computer team decided to\nexport snapshots of our STAC database as <a href=\"https:\/\/geoparquet.org\/\">geoparquet<\/a>. Each STAC collection is\nexported as a Parquet dataset, where each record in the dataset is a STAC item.\nWe pitched this as a way to do <a href=\"https:\/\/planetarycomputer.microsoft.com\/docs\/quickstarts\/stac-geoparquet\/\">bulk queries<\/a> over the data, where\nreturning many and many pages of JSON would be slow (and expensive for our\nservers and database).<\/p>"},{"title":"Gone Rafting","link":"https:\/\/tomaugspurger.net\/posts\/gone-rafting\/","pubDate":"Sun, 13 Aug 2023 14:30:19 -0500","guid":"https:\/\/tomaugspurger.net\/posts\/gone-rafting\/","description":"<p>Last week, I was fortunate to attend Dave Beazley&rsquo;s <a href=\"https:\/\/dabeaz.com\/raft.html\">Rafting\nTrip<\/a> course. The pretext of the course is to\nimplement the <a href=\"https:\/\/raft.github.io\/\">Raft Consensus Algorithm<\/a>.<\/p>\n<p>I&rsquo;ll post more about Raft, and the journey of implementing, it later. But in\nbrief, Raft is an algorithm that lets a cluster of machines work together to\n<em>reliably<\/em> do something. If you had a service that needed to stay up (and stay\nconsistent), even if some of the machines in the cluster went down, then you\nmight want to use Raft.<\/p>"},{"title":"National Water Model on Azure","link":"https:\/\/tomaugspurger.net\/posts\/noaa-nwm\/","pubDate":"Thu, 25 May 2023 12:04:06 -0500","guid":"https:\/\/tomaugspurger.net\/posts\/noaa-nwm\/","description":"<p>A few colleagues and I recently presented at the <a href=\"https:\/\/ciroh.ua.edu\/devconference\/\">CIROH Training and Developers Conference<\/a>.\nIn preparation for that I created a <a href=\"https:\/\/jupyterbook.org\/en\/stable\/intro.html\">Jupyter Book<\/a>. You can view it at <a href=\"https:\/\/tomaugspurger.net\/noaa-nwm\/intro.html\">https:\/\/tomaugspurger.net\/noaa-nwm\/intro.html<\/a>\nI created a few cloud-optimized versions for subsets of the data, but those will be going away since we don&rsquo;t have operational pipelines to keep them up to date. But hopefully the static notebooks are still helpful.<\/p>\n<h2 id=\"lessons-learned\">Lessons learned<\/h2>\n<p>Aside from running out of time (I always prepare too much material for the amount of time), I think things went well. JupyterHub (perhaps + Dask) and Kubernetes continues to be a great way to run a workshop.<\/p>"},{"title":"Jupyter, STAC, and Tool Building","link":"https:\/\/tomaugspurger.net\/posts\/jupyter-stac-browser\/","pubDate":"Sat, 15 Apr 2023 08:00:00 -0500","guid":"https:\/\/tomaugspurger.net\/posts\/jupyter-stac-browser\/","description":"<p>Over in Planetary Computer land, we&rsquo;re <a href=\"https:\/\/github.com\/microsoft\/planetary-computer-tasks\/pull\/167\">working on<\/a> bringing <a href=\"https:\/\/sentinels.copernicus.eu\/web\/sentinel\/missions\/sentinel-5p\">Sentinel-5P<\/a> into our STAC catalog.<\/p>\n<p>STAC items require a <code>geometry<\/code> property, a GeoJSON object that describes the footprint of the assets. Thanks to the satellites&rsquo; orbit and the (spatial) size of the assets, we started with some&hellip;interesting&hellip; footprints:<\/p>\n<p><img loading=\"lazy\" src=\"https:\/\/user-images.githubusercontent.com\/58314\/231868547-21c786b9-dc88-4830-a07f-7aa3c1fdebc6.png\"><\/p>\n<p>That initial footprint, shown in orange, would render the STAC collection essentially useless for spatial searches. The assets don&rsquo;t actually cover (most of) the southern hemisphere.<\/p>"},{"title":"py-spy in Azure Batch","link":"https:\/\/tomaugspurger.net\/posts\/azure-batch-pyspy\/","pubDate":"Wed, 22 Feb 2023 15:11:37 -0600","guid":"https:\/\/tomaugspurger.net\/posts\/azure-batch-pyspy\/","description":"<p>Today, I was debugging a hanging task in <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/batch\/batch-technical-overview\">Azure Batch<\/a>.\nThis short post records how I used <a href=\"https:\/\/github.com\/benfred\/py-spy\">py-spy<\/a> to investigate the problem.<\/p>\n<h2 id=\"background\">Background<\/h2>\n<p>Azure Batch is a compute service that we use to run <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/batch\/batch-docker-container-workloads\">container\nworkloads<\/a>.\nIn this case, we start up a container that processes a bunch of GOES-GLM data to\ncreate <a href=\"https:\/\/stacspec.org\/en\">STAC items<\/a> for the <a href=\"http:\/\/planetarycomputer.microsoft.com\/\">Planetary\nComputer<\/a> . The workflow is essentially\na big<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"><code class=\"language-python\" data-lang=\"python\"><span style=\"display:flex;\"><span><span style=\"color:#66d9ef\">for<\/span> url <span style=\"color:#f92672\">in<\/span> urls:\n<\/span><\/span><span style=\"display:flex;\"><span> local_file <span style=\"color:#f92672\">=<\/span> download_url(url)\n<\/span><\/span><span style=\"display:flex;\"><span> stac<span style=\"color:#f92672\">.<\/span>create_item(local_file)\n<\/span><\/span><\/code><\/pre><\/div><p>We noticed that some Azure Batch tasks were hanging. Based on our logs, we knew\nit was somewhere in that for loop, but couldn&rsquo;t determine exactly where things\nwere hanging. The <a href=\"https:\/\/github.com\/stactools-packages\/goes-glm\">goes-glm<\/a> stactools package we used does read a NetCDF file,\nand my experience with Dask biased me towards thinking the <code>netcdf<\/code> library (or\nthe HDF5 reader it uses) was hanging. But I wanted to confirm that before trying\nto implement a fix.<\/p>"},{"title":"Planetary Computer Release: January 2023","link":"https:\/\/tomaugspurger.net\/posts\/pc-january-2023\/","pubDate":"Thu, 09 Feb 2023 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/pc-january-2023\/","description":"<p>The Planetary Computer made its <a href=\"https:\/\/planetarycomputer.microsoft.com\/docs\/overview\/changelog\/\">January 2023 release<\/a> a couple weeks back.<\/p>\n<p>The flagship new feature is a <em>really<\/em> cool new ability to visualize the <a href=\"https:\/\/planetarycomputer.microsoft.com\/dataset\/ms-buildings\">Microsoft AI-detected Buildings Footprints<\/a> dataset. Here&rsquo;s a little demo made by my teammate, Rob:<\/p>\n<video controls style=\"height: 400px;\">\n<source src=\"https:\/\/ai4edatasetspublicassets.azureedge.net\/assets\/pc_video\/vector-tile-ms-buildings-feature.mp4\" type=\"video\/mp4\" \/>\n<p>\nYour browser doesn't support HTML video. Here is a\n<a href=\"https:\/\/ai4edatasetspublicassets.azureedge.net\/assets\/pc_video\/vector-tile-ms-buildings-feature.mp4\">link to the video<\/a> instead.\n<\/p>\n<\/video>\n<p>Currently, enabling this feature required converting the data from its native <a href=\"http:\/\/github.com\/opengeospatial\/geoparquet\">geoparquet<\/a> to a <em>lot<\/em> of protobuf files with <a href=\"https:\/\/github.com\/felt\/tippecanoe\">Tippecanoe<\/a>. I&rsquo;m very excited about projects to visualize the geoparquet data directly (see <a href=\"https:\/\/kylebarron.dev\/blog\/geoarrow-and-geoparquet-in-deck-gl\">Kyle Barron&rsquo;s demo<\/a>) but for now we needed to do the conversion.<\/p>"},{"title":"Cloud Optimized Vibes","link":"https:\/\/tomaugspurger.net\/posts\/cloud-optimized-quandary\/","pubDate":"Sat, 14 Jan 2023 16:16:11 -0600","guid":"https:\/\/tomaugspurger.net\/posts\/cloud-optimized-quandary\/","description":"<p>Over on the <a href=\"http:\/\/planetarycomputer.microsoft.com\/\">Planetary Computer<\/a> team, we get to have a lot of fun discussions about doing geospatial data analysis on the cloud. This post summarizes some work we did, and the (I think) interesting conversations that came out of it.<\/p>\n<h2 id=\"background-goes-glm\">Background: GOES-GLM<\/h2>\n<p>The instigator in this case was onboarding a new dataset to the Planetary Computer, <a href=\"https:\/\/planetarycomputer.microsoft.com\/dataset\/goes-glm\">GOES-GLM<\/a>. GOES is a set of geostationary weather satellites operated by NOAA, and GLM is the Geostationary Lightning Mapper, an instrument on the satellites that&rsquo;s used to monitor lightning. It produces some really neat (and valuable) data.<\/p>"},{"title":"Queues in the News","link":"https:\/\/tomaugspurger.net\/posts\/queues\/","pubDate":"Mon, 26 Dec 2022 13:35:24 -0600","guid":"https:\/\/tomaugspurger.net\/posts\/queues\/","description":"<p>I came across a couple of new (to me) uses of queues recently. When I came up with the title to this article I knew I had to write them up together.<\/p>\n<h2 id=\"queues-in-dask\">Queues in Dask<\/h2>\n<p>Over at the <a href=\"https:\/\/www.coiled.io\/blog\/reducing-dask-memory-usage\">Coiled Blog<\/a>, Gabe Joseph has a nice post summarizing a huge amount of effort addressing a problem that&rsquo;s been vexing demanding Dask users for years. The main symptom of the problem was unexpectedly high memory usage on workers, leading to crashing workers (which in turn caused even more network communication, and so more memory usage, and more crashing workers). This is actually a problem I worked on a bit back in 2019, and I made very little progress.<\/p>"},{"title":"My 2022 Year in Books","link":"https:\/\/tomaugspurger.net\/posts\/books-2022\/","pubDate":"Wed, 21 Dec 2022 07:25:47 -0600","guid":"https:\/\/tomaugspurger.net\/posts\/books-2022\/","description":"<p>It&rsquo;s &ldquo;Year in X&rdquo; time, and here&rsquo;s my <a href=\"https:\/\/www.goodreads.com\/user\/year_in_books\/2022\/82176424\">2022 Year in Books<\/a> on GoodReads. I&rsquo;ll cover some highlights here.<\/p>\n<p>Many of these recommendations came from the <a href=\"https:\/\/www.theincomparable.com\/theincomparable\/bookclub\/\">Incomparable&rsquo;s Book Club<\/a>, part of the main Incomparable podcast. In particular, episode 600 <a href=\"https:\/\/www.theincomparable.com\/theincomparable\/600\/\">The Machine was a Vampire<\/a> which is a roundup of their favorites from the 2010s.<\/p>\n<h2 id=\"bookended-by-murderbot-diaries\">Bookended by Murderbot Diaries<\/h2>\n<img src=\"https:\/\/images-na.ssl-images-amazon.com\/images\/S\/compressed.photo.goodreads.com\/books\/1505589896i\/36223859.jpg\" width=\"200px\"\/>\n<p>I started and ended this year (so far) with a couple installments in the <a href=\"https:\/\/bookshop.org\/p\/books\/the-murderbot-diaries-all-systems-red-artificial-condition-rogue-protocol-exit-strategy-martha-wells\/14469574?ean=9781250784278\">Murderbot Diaries<\/a>. These follow a robotic \/ organic &ldquo;Security Unit&rdquo; that&rsquo;s responsible for taking care of humans in dangerous situations. We pick up after an unfortunate incident where it seems to have gone rouge and murdered her clients (hence, the murderbot) and hacked its governor module to essentially become &ldquo;free&rdquo;.<\/p>"},{"title":"Podcast: Revolutions","link":"https:\/\/tomaugspurger.net\/posts\/revolutions\/","pubDate":"Tue, 20 Dec 2022 16:56:57 -0600","guid":"https:\/\/tomaugspurger.net\/posts\/revolutions\/","description":"<p>Mike Duncan is wrapping up his excellent <a href=\"https:\/\/thehistoryofrome.typepad.com\/revolutions_podcast\/\">Revolutions<\/a> podcast. If you&rsquo;re at all interested in history then now is a great time to pick it up. He takes the concept of &ldquo;a revolution&rdquo; and looks at it through the lens of a bunch of revolutions throughout history. The appendix episodes from the last few weeks have really tied things together, looking at whats common (and not) across all the revolutions covered in the series.<\/p>"},{"title":"Rebooting","link":"https:\/\/tomaugspurger.net\/posts\/rebooting\/","pubDate":"Sun, 18 Dec 2022 16:51:46 -0600","guid":"https:\/\/tomaugspurger.net\/posts\/rebooting\/","description":"<p>Like <a href=\"http:\/\/www.gregreda.com\/2022\/11\/18\/reviving-this-space\/\">some others<\/a>, I&rsquo;m getting back into blogging.<\/p>\n<p>I&rsquo;ll be &ldquo;straying from my lane&rdquo; and won&rsquo;t just be writing about Python data libraries (though there will still be some of that).\nIf you too would like to blog more, I&rsquo;d encourge you to read Simon Willison&rsquo;s <a href=\"https:\/\/simonwillison.net\/2022\/Nov\/6\/what-to-blog-about\/\">What to blog About<\/a> and Matt Rocklin&rsquo;s <a href=\"https:\/\/matthewrocklin.com\/blog\/work\/2019\/06\/25\/write-short-blogposts\">Write Short Blogposts<\/a>.<\/p>\n<p>Because I&rsquo;m me, I couldn&rsquo;t just make a new post. I also had to switch static site generators, just becauase. All the old links, including my <a href=\"https:\/\/tomaugspurger.net\/index.xml\">RSS feed<\/a>, should continue to work. If you spot any issues, <a href=\"mailto:tom.w.augspurger@gmail.com\">let me know<\/a> (I think I&rsquo;ve fixed at least one bug in the RSS feed, apologies for any spurious updates. But just in case, you might want to update your RSS links to <a href=\"http:\/\/tomaugspurger.net\/index.xml\">http:\/\/tomaugspurger.net\/index.xml<\/a>).<\/p>"},{"title":"What's Next?","link":"https:\/\/tomaugspurger.net\/posts\/whats-next\/","pubDate":"Wed, 11 Nov 2020 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/whats-next\/","description":"<p>Some personal news: Last Friday was my last day at <a href=\"https:\/\/www.anaconda.com\">Anaconda<\/a>.\nNext week, I&rsquo;m joining Microsoft&rsquo;s <a href=\"https:\/\/www.microsoft.com\/en-us\/ai\/ai-for-earth\">AI for Earth<\/a> team. This is a very bittersweet transition. While I loved working at Anaconda and all the great people there, I&rsquo;m extremely excited about what I&rsquo;ll be working on at Microsoft.<\/p>\n<h2 id=\"reflections\">Reflections<\/h2>\n<p>I was inspired to write this section by Jim Crist&rsquo;s post on a similar topic: <a href=\"https:\/\/jcristharif.com\/farewell-to-anaconda.html\">https:\/\/jcristharif.com\/farewell-to-anaconda.html<\/a>.\nI&rsquo;ll highlight some of the projects I worked on while at Anaconda. If you want to skip the navel gazing, skip down to <a href=\"#whats-next\">what&rsquo;s next<\/a>.<\/p>"},{"title":"Maintaining Performance","link":"https:\/\/tomaugspurger.net\/posts\/performance-regressions\/","pubDate":"Wed, 01 Apr 2020 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/performance-regressions\/","description":"<p>As pandas&rsquo; <a href=\"https:\/\/pandas.pydata.org\/docs\/\">documentation<\/a> claims: pandas\nprovides <em>high-performance<\/em> data structures. But how do we verify that the claim\nis correct? And how do we ensure that it <em>stays<\/em> correct over many releases.\nThis post describes<\/p>\n<ol>\n<li>pandas&rsquo; current setup for monitoring performance<\/li>\n<li>My personal debugging strategy for understanding and fixing performance\nregressions when they occur.<\/li>\n<\/ol>\n<p>I hope that the first section topic is useful for library maintainers and the\nsecond topic is generally useful for people writing performance-sensitive code.<\/p>"},{"title":"Compatibility Code","link":"https:\/\/tomaugspurger.net\/posts\/compatibility\/","pubDate":"Thu, 12 Dec 2019 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/compatibility\/","description":"<h1 id=\"compatibility-code\">Compatibility Code<\/h1>\n<p>Most libraries with dependencies will want to support multiple versions\nof that dependency. But supporting old version is a pain: it requires <em>compatibility code<\/em>,\ncode that is around solely to get the same output from versions of a library. This post\ngives some advice on writing compatibility code.<\/p>\n<ol>\n<li>Don&rsquo;t write your own version parser<\/li>\n<li>Centralize all version parsing<\/li>\n<li>Use consistent version comparisons<\/li>\n<li>Use Python&rsquo;s argument unpacking<\/li>\n<li>Clean up unused compatibility code<\/li>\n<\/ol>\n<h2 id=\"1-dont-write-your-own-version-parser\">1. Don&rsquo;t write your own version parser<\/h2>\n<p>It can be tempting just do something like<\/p>"},{"title":"Dask Workshop","link":"https:\/\/tomaugspurger.net\/posts\/dask-workshop\/","pubDate":"Thu, 12 Dec 2019 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/dask-workshop\/","description":"<p>Dask Summit Recap<\/p>\n<p>Last week was the first Dask Developer Workshop. This brought together many of\nthe core Dask developers and its heavy users to discuss the project. I want to\nshare some of the experience with those who weren&rsquo;t able to attend.<\/p>\n<p>This was a great event. Aside from any technical discussions, it was ncie to\nmeet all the people. From new acquaintences to people you&rsquo;re on weekly calls\nwith, it was great to interact with everyone.<\/p>"},{"title":"pandas + binder","link":"https:\/\/tomaugspurger.net\/posts\/pandas-binder\/","pubDate":"Sun, 21 Jul 2019 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/pandas-binder\/","description":"<p>This post describes the start of a journey to get pandas&rsquo; documentation running\non Binder. The end result is this nice button:<\/p>\n<p><a href=\"https:\/\/mybinder.org\/v2\/gh\/TomAugspurger\/pandas-binder\/master?filepath=build%2Fjupyter%2Fgetting_started%2F10min.ipynb\"><img alt=\"Binder\" loading=\"lazy\" src=\"https:\/\/mybinder.org\/badge_logo.svg\"><\/a><\/p>\n<hr>\n<p>For a while now I&rsquo;ve been jealous of <a href=\"https:\/\/github.com\/dask\/dask-examples\">Dask&rsquo;s examples\nrepository<\/a>. That&rsquo;s a repository containing a\ncollection of Jupyter notebooks demonstrating Dask in action. It stitches\ntogether some tools to present a set of documentation that is both viewable\nas a static site at <a href=\"https:\/\/examples.dask.org\">examples.dask.org<\/a>, and as a executable notebooks\non <a href=\"https:\/\/mybinder.org\/v2\/gh\/dask\/dask-examples\/master?urlpath=lab\">mybinder<\/a>.<\/p>"},{"title":"A Confluence of Extension","link":"https:\/\/tomaugspurger.net\/posts\/confluence-extension\/","pubDate":"Tue, 18 Jun 2019 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/confluence-extension\/","description":"<p>This post describes a few protocols taking shape in the scientific Python\ncommunity. On their own, each is powerful. Together, I think they enable for an\nexplosion of creativity in the community.<\/p>\n<p>Each of the protocols \/ interfaces we&rsquo;ll consider deal with extending.<\/p>\n<ul>\n<li><a href=\"https:\/\/www.numpy.org\/neps\/nep-0013-ufunc-overrides.html\">NEP-13: NumPy <code>__array_ufunc__<\/code><\/a><\/li>\n<li><a href=\"https:\/\/www.numpy.org\/neps\/nep-0018-array-function-protocol.html\">NEP-18: NumPy <code>__array_function__<\/code><\/a><\/li>\n<li><a href=\"http:\/\/pandas.pydata.org\/pandas-docs\/stable\/development\/extending.html#extension-types\">Pandas Extension types<\/a><\/li>\n<li><a href=\"https:\/\/docs.dask.org\/en\/latest\/custom-collections.html\">Custom Dask Collections<\/a><\/li>\n<\/ul>\n<hr>\n<p>First, a bit of brief background on each.<\/p>\n<p>NEP-13 and NEP-18, each deal with using the NumPy API on non-NumPy ndarray\nobjects. For example, you might want to apply a ufunc like <code>np.log<\/code> to a Dask\narray.<\/p>"},{"title":"Tabular Data in Scikit-Learn and Dask-ML","link":"https:\/\/tomaugspurger.net\/posts\/sklearn-dask-tabular\/","pubDate":"Mon, 17 Sep 2018 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/sklearn-dask-tabular\/","description":"<p>Scikit-Learn 0.20.0 will contain some nice new features for working with tabular data.\nThis blogpost will introduce those improvements with a small demo.\nWe&rsquo;ll then see how Dask-ML was able to piggyback on the work done by scikit-learn to offer a version that works well with Dask Arrays and DataFrames.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"><code class=\"language-python\" data-lang=\"python\"><span style=\"display:flex;\"><span><span style=\"color:#f92672\">import<\/span> dask\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#f92672\">import<\/span> dask.array <span style=\"color:#66d9ef\">as<\/span> da\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#f92672\">import<\/span> dask.dataframe <span style=\"color:#66d9ef\">as<\/span> dd\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#f92672\">import<\/span> numpy <span style=\"color:#66d9ef\">as<\/span> np\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#f92672\">import<\/span> pandas <span style=\"color:#66d9ef\">as<\/span> pd\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#f92672\">import<\/span> seaborn <span style=\"color:#66d9ef\">as<\/span> sns\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#f92672\">import<\/span> fastparquet\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#f92672\">from<\/span> distributed <span style=\"color:#f92672\">import<\/span> Client\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#f92672\">from<\/span> distributed.utils <span style=\"color:#f92672\">import<\/span> format_bytes\n<\/span><\/span><\/code><\/pre><\/div><h2 id=\"background\">Background<\/h2>\n<p>For the most part, Scikit-Learn uses NumPy ndarrays or SciPy sparse matricies for its in-memory data structures.\nThis is great for many reasons, but one major drawback is that you can&rsquo;t store <em>heterogenous<\/em> (AKA <em>tabular<\/em>) data in these containers. These are datasets where different columns of the table have different data types (some ints, some floats, some strings, etc.).<\/p>"},{"title":"Distributed Auto-ML with TPOT with Dask","link":"https:\/\/tomaugspurger.net\/posts\/distributed-tpot\/","pubDate":"Thu, 30 Aug 2018 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/distributed-tpot\/","description":"<p><em>This work is supported by <a href=\"https:\/\/www.anaconda.com\/\">Anaconda Inc<\/a>.<\/em><\/p>\n<p>This post describes a recent improvement made to <a href=\"https:\/\/epistasislab.github.io\/tpot\/\">TPOT<\/a>. TPOT is an\n<a href=\"https:\/\/en.wikipedia.org\/wiki\/Automated_machine_learning\">automated machine learning<\/a> library for Python. It does some feature\nengineering and hyper-parameter optimization for you. TPOT uses <a href=\"https:\/\/en.wikipedia.org\/wiki\/Genetic_programming\">genetic\nalgorithms<\/a> to evaluate which models are performing well and how to choose\nnew models to try out in the next generation.<\/p>\n<h2 id=\"parallelizing-tpot\">Parallelizing TPOT<\/h2>\n<p>In <a href=\"https:\/\/github.com\/EpistasisLab\/tpot\/pull\/730\">TPOT-730<\/a>, we made some modifications to TPOT to support\ndistributed training. As a TPOT user, the only changes you need to make to your\ncode are<\/p>"},{"title":"Moral Philosophy for pandas or: What is `.values`?","link":"https:\/\/tomaugspurger.net\/posts\/pandas-moral-philosophy\/","pubDate":"Tue, 14 Aug 2018 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/pandas-moral-philosophy\/","description":"<p>The other day, I put up a <a href=\"https:\/\/twitter.com\/TomAugspurger\/status\/1026578613389455360\">Twitter poll<\/a> asking a simple question: What&rsquo;s the type of <code>series.values<\/code>?<\/p>\n<blockquote class=\"twitter-tweet\" data-lang=\"en\"><p lang=\"en\" dir=\"ltr\">Pop Quiz! What are the possible results for the following:<br><br>&gt;&gt;&gt; type(pandas.Series.values)<\/p>&mdash; Tom Augspurger (@TomAugspurger) <a href=\"https:\/\/twitter.com\/TomAugspurger\/status\/1026578613389455360?ref_src=twsrc%5Etfw\">August 6, 2018<\/a><\/blockquote> <script async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script>\n<p>I was a bit limited for space, so I&rsquo;ll expand on the options here. Choose as many as you want.<\/p>\n<ol>\n<li>NumPy ndarray<\/li>\n<li>pandas Categorical (or all of the above)<\/li>\n<li>An Index or any of it&rsquo;s subclasses (DatetimeIndex, CategoricalIndex, RangeIndex, etc.) (or all of the above)<\/li>\n<li>None or all of the above<\/li>\n<\/ol>\n<p>I was prompted to write this post because <em>a.)<\/em> this is an (unfortunately) confusing topic and <em>b.)<\/em> it&rsquo;s undergoing a lot of change right now (and, <em>c.)<\/em> I had this awesome title in my head).<\/p>"},{"title":"Modern Pandas (Part 8): Scaling","link":"https:\/\/tomaugspurger.net\/posts\/modern-8-scaling\/","pubDate":"Mon, 23 Apr 2018 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/modern-8-scaling\/","description":"<hr>\n<p>This is part 1 in my series on writing modern idiomatic pandas.<\/p>\n<ul>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-1-intro\">Modern Pandas<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/method-chaining\">Method Chaining<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-3-indexes\">Indexes<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-4-performance\">Fast Pandas<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-5-tidy\">Tidy Data<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-6-visualization\">Visualization<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-7-timeseries\">Time Series<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-8-scaling\">Scaling<\/a><\/li>\n<\/ul>\n<hr>\n<p>As I sit down to write this, the third-most popular pandas question on StackOverflow covers <a href=\"https:\/\/stackoverflow.com\/q\/14262433\/1889400\">how to use pandas for large datasets<\/a>. This is in tension with the fact that a pandas DataFrame is an in memory container. <em>You can&rsquo;t have a <code>DataFrame<\/code> larger than your machine&rsquo;s RAM<\/em>. In practice, your available RAM should be several times the size of your dataset, as you or pandas will have to make intermediate copies as part of the analysis.<\/p>"},{"title":"dask-ml 0.4.1 Released","link":"https:\/\/tomaugspurger.net\/posts\/dask-ml-041\/","pubDate":"Tue, 13 Feb 2018 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/dask-ml-041\/","description":"<p><em>This work is supported by <a href=\"http:\/\/anaconda.com\/\">Anaconda Inc<\/a> and the Data\nDriven Discovery Initiative from the <a href=\"https:\/\/www.moore.org\/\">Moore\nFoundation<\/a>.<\/em><\/p>\n<p><a href=\"http:\/\/dask-ml.readthedocs.io\/en\/latest\/\">dask-ml<\/a> 0.4.1 was released today with a few enhancements. See the\n<a href=\"http:\/\/dask-ml.readthedocs.io\/en\/latest\/changelog.html\">changelog<\/a> for all the changes from 0.4.0.<\/p>\n<p>Conda packages are available on conda-forge<\/p>\n<pre><code>$ conda install -c conda-forge dask-ml\n<\/code><\/pre>\n<p>and wheels and the source are available on PyPI<\/p>\n<pre><code>$ pip install dask-ml\n<\/code><\/pre>\n<p>I wanted to highlight one change, that touches on a topic I mentioned in my\nfirst post on <a href=\"scalable-ml-01\">scalable Machine Learning<\/a>. I discussed how, in\nmy limited experience, a common workflow was to train on a small batch of data\nand predict for a much larger set of data. The training data easily fits in\nmemory on a single machine, but the full dataset does not.<\/p>"},{"title":"Extension Arrays for Pandas","link":"https:\/\/tomaugspurger.net\/posts\/pandas-extension-arrays\/","pubDate":"Mon, 12 Feb 2018 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/pandas-extension-arrays\/","description":"<p>This is a status update on some enhancements for pandas. The goal of the work\nis to store things that are sufficiently array-like in a pandas <code>DataFrame<\/code>,\neven if they aren&rsquo;t a regular NumPy array. Pandas already does this in a few\nplaces for some blessed types (like <code>Categorical<\/code>); we&rsquo;d like to open that up to\nanybody.<\/p>\n<p>A couple months ago, a client came to <a href=\"https:\/\/www.anaconda.com\/\">Anaconda<\/a> with a problem: they\nhave a bunch of IP Address data that they&rsquo;d like to work with in pandas. They\ndidn&rsquo;t just want to make a NumPy array of IP addresses for a few reasons:<\/p>"},{"title":"Easy distributed training with Joblib and dask","link":"https:\/\/tomaugspurger.net\/posts\/distributed-joblib\/","pubDate":"Mon, 05 Feb 2018 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/distributed-joblib\/","description":"<p><em>This work is supported by <a href=\"http:\/\/anaconda.com\/\">Anaconda Inc<\/a> and the Data\nDriven Discovery Initiative from the <a href=\"https:\/\/www.moore.org\/\">Moore\nFoundation<\/a>.<\/em><\/p>\n<p>This past week, I had a chance to visit some of the scikit-learn developers at\nInria in Paris. It was a fun and productive week, and I&rsquo;m thankful to them for\nhosting me and Anaconda for sending me there. This article will talk about some\nimprovements we made to improve training scikit-learn models using a cluster.<\/p>"},{"title":"Rewriting scikit-learn for big data, in under 9 hours.","link":"https:\/\/tomaugspurger.net\/posts\/dask-ml-iid\/","pubDate":"Sun, 28 Jan 2018 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/dask-ml-iid\/","description":"<p>This past week, I had a chance to visit some of the scikit-learn developers at\nInria in Paris. It was a fun and productive week, and I&rsquo;m thankful to them for\nhosting me and Anaconda for sending me there.<\/p>\n<p>Towards the end of our week, Gael threw out the observation that for many\napplications, you don&rsquo;t need to <em>train<\/em> on the entire dataset, a sample is often\nsufficient. But it&rsquo;d be nice if the trained estimator would be able to\n<em>transform<\/em> and <em>predict<\/em> for dask arrays, getting all the nice distributed\nparallelism and memory management dask brings.<\/p>"},{"title":"dask-ml","link":"https:\/\/tomaugspurger.net\/posts\/dask-ml-announce\/","pubDate":"Thu, 26 Oct 2017 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/dask-ml-announce\/","description":"<p>Today we released the first version of <code>dask-ml<\/code>, a library for parallel and\ndistributed machine learning. Read the <a href=\"http:\/\/dask-ml.readthedocs.io\/en\/latest\/\">documentation<\/a> or install it with<\/p>\n<pre tabindex=\"0\"><code>pip install dask-ml\n<\/code><\/pre><p>Packages are currently building for conda-forge, and will be up later today.<\/p>\n<pre tabindex=\"0\"><code>conda install -c conda-forge dask-ml\n<\/code><\/pre><h2 id=\"the-goals\">The Goals<\/h2>\n<p><a href=\"http:\/\/dask.pydata.org\/en\/latest\/\">dask<\/a> is, to quote the docs, &ldquo;a flexible parallel computing library for\nanalytic computing.&rdquo; <code>dask.array<\/code> and <code>dask.dataframe<\/code> have done a great job\nscaling NumPy arrays and pandas dataframes; <code>dask-ml<\/code> hopes to do the same in\nthe machine learning domain.<\/p>"},{"title":"Scalable Machine Learning (Part 3): Parallel","link":"https:\/\/tomaugspurger.net\/posts\/scalable-ml-03\/","pubDate":"Sat, 16 Sep 2017 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/scalable-ml-03\/","description":"<p><em>This work is supported by <a href=\"https:\/\/www.anaconda.com\/\">Anaconda, Inc.<\/a> and the\nData Driven Discovery Initiative from the <a href=\"https:\/\/www.moore.org\/\">Moore Foundation<\/a>.<\/em><\/p>\n<p>This is part three of my series on scalable machine learning.<\/p>\n<ul>\n<li><a href=\"scalable-ml-01\">Small Fit, Big Predict<\/a><\/li>\n<li><a href=\"scalable-ml-02\">Scikit-Learn Partial Fit<\/a><\/li>\n<li><a href=\"scalable-ml-03\">Parallel Machine Learning<\/a><\/li>\n<\/ul>\n<p>You can download a notebook of this post [here][notebook].<\/p>\n<hr>\n<p>In <a href=\"scalable-ml-01\">part one<\/a>, I talked about the type of constraints that push\nus to parallelize or distribute a machine learning workload. Today, we&rsquo;ll be\ntalking about the second constraint, &ldquo;I&rsquo;m constrained by time, and would like to\nfit more models at once, by using all the cores of my laptop, or all the\nmachines in my cluster&rdquo;.<\/p>"},{"title":"Scalable Machine Learning (Part 2): Partial Fit","link":"https:\/\/tomaugspurger.net\/posts\/scalable-ml-02\/","pubDate":"Fri, 15 Sep 2017 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/scalable-ml-02\/","description":"<p><em>This work is supported by <a href=\"https:\/\/www.anaconda.com\/\">Anaconda, Inc.<\/a> and the\nData Driven Discovery Initiative from the <a href=\"https:\/\/www.moore.org\/\">Moore Foundation<\/a>.<\/em><\/p>\n<p>This is part two of my series on scalable machine learning.<\/p>\n<ul>\n<li><a href=\"scalable-ml-01\">Small Fit, Big Predict<\/a><\/li>\n<li><a href=\"scalable-ml-02\">Scikit-Learn Partial Fit<\/a><\/li>\n<\/ul>\n<p>You can download a notebook of this post <a href=\"http:\/\/nbviewer.jupyter.org\/github\/TomAugspurger\/scalable-ml\/blob\/master\/partial.ipynb\">here<\/a>.<\/p>\n<hr>\n<p>Scikit-learn supports out-of-core learning (fitting a model on a dataset that\ndoesn&rsquo;t fit in RAM), through it&rsquo;s <code>partial_fit<\/code> API. See\n<a href=\"http:\/\/scikit-learn.org\/stable\/modules\/scaling_strategies.html#scaling-with-instances-using-out-of-core-learning\">here<\/a>.<\/p>\n<p>The basic idea is that, <em>for certain estimators<\/em>, learning can be done in\nbatches. The estimator will see a batch, and then incrementally update whatever\nit&rsquo;s learning (the coefficients, for example). <a href=\"http:\/\/scikit-learn.org\/stable\/modules\/scaling_strategies.html#incremental-learning\">This\nlink<\/a>\nhas a list of the algorithms that implement <code>partial_fit<\/code>.<\/p>"},{"title":"Scalable Machine Learning (Part 1)","link":"https:\/\/tomaugspurger.net\/posts\/scalable-ml-01\/","pubDate":"Mon, 11 Sep 2017 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/scalable-ml-01\/","description":"<p><em>This work is supported by <a href=\"https:\/\/www.anaconda.com\/\">Anaconda Inc.<\/a> and the Data Driven Discovery\nInitiative from the <a href=\"https:\/\/www.moore.org\/\">Moore Foundation<\/a>.<\/em><\/p>\n<p>Anaconda is interested in scaling the scientific python ecosystem. My current\nfocus is on out-of-core, parallel, and distributed machine learning. This series\nof posts will introduce those concepts, explore what we have available today,\nand track the community&rsquo;s efforts to push the boundaries.<\/p>\n<p><em>You can download a Jupyter notebook demonstrating the analysis <a href=\"https:\/\/nbviewer.jupyter.org\/gist\/TomAugspurger\/94ee62127bbc8e20223f97ebd7d29191\">here<\/a>.<\/em><\/p>\n<h2 id=\"constraints\">Constraints<\/h2>\n<p>I am (or was, anyway) an economist, and economists like to think in terms of\nconstraints. How are we constrained by scale? The two main ones I can think of\nare<\/p>"},{"title":"Dask Performace Trip","link":"https:\/\/tomaugspurger.net\/posts\/dask-performance-story\/","pubDate":"Tue, 06 Sep 2016 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/dask-performance-story\/","description":"<p>I&rsquo;m faced with a fairly specific problem: Compute the pairwise distances between\ntwo matrices $X$ and $Y$ as quickly as possible. We&rsquo;ll assume that $Y$ is fairly\nsmall, but $X$ may not fit in memory. This post tracks my progress.<\/p>"},{"title":"Introducing Stitch","link":"https:\/\/tomaugspurger.net\/posts\/intro-stitch\/","pubDate":"Tue, 30 Aug 2016 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/intro-stitch\/","description":"<p>Today I released <a href=\"https:\/\/github.com\/pystitch\/stitch\"><code>stitch<\/code><\/a> into the\nwild. If you haven&rsquo;t yet, check out the <a href=\"https:\/\/pystitch.github.io\">examples\npage<\/a> to see an example of what stitch does,\nand the <a href=\"https:\/\/github.com\/pystitch\/stitch\">Github repo<\/a> for how to\ninstall. I&rsquo;m using this post to explain why I wrote stitch, and some\nissues it tries to solve.<\/p>\n<h2 id=\"why-knitr--knitpy--stitch--rmarkdown\">Why <a href=\"http:\/\/yihui.name\/knitr\/\">knitr<\/a> \/ <a href=\"https:\/\/github.com\/janschulz\/knitpy\">knitpy<\/a> \/ stitch \/ <a href=\"http:\/\/rmarkdown.rstudio.com\">RMarkdown<\/a>?<\/h2>\n<p>Each of these tools or formats have the same high-level goal: produce\nreproducible, dynamic (to changes in the data) reports. They take some\nsource document (typically markdown) that&rsquo;s a mixture of text and code\nand convert it to a destination output (HTML, PDF, docx, etc.).<\/p>"},{"title":"Modern Pandas (Part 7): Timeseries","link":"https:\/\/tomaugspurger.net\/posts\/modern-7-timeseries\/","pubDate":"Fri, 13 May 2016 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/modern-7-timeseries\/","description":"<hr>\n<p>This is part 7 in my series on writing modern idiomatic pandas.<\/p>\n<ul>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-1-intro\">Modern Pandas<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/method-chaining\">Method Chaining<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-3-indexes\">Indexes<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-4-performance\">Fast Pandas<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-5-tidy\">Tidy Data<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-6-visualization\">Visualization<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-7-timeseries\">Time Series<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-8-scaling\">Scaling<\/a><\/li>\n<\/ul>\n<hr>\n<h1 id=\"timeseries\">Timeseries<\/h1>\n<p>Pandas started out in the financial world, so naturally it has strong timeseries support.<\/p>\n<p>The first half of this post will look at pandas&rsquo; capabilities for manipulating time series data.\nThe second half will discuss modelling time series data with statsmodels.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"><code class=\"language-python\" data-lang=\"python\"><span style=\"display:flex;\"><span><span style=\"color:#f92672\">%<\/span>matplotlib inline\n<\/span><\/span><span style=\"display:flex;\"><span>\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#f92672\">import<\/span> os\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#f92672\">import<\/span> numpy <span style=\"color:#66d9ef\">as<\/span> np\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#f92672\">import<\/span> pandas <span style=\"color:#66d9ef\">as<\/span> pd\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#f92672\">import<\/span> pandas_datareader.data <span style=\"color:#66d9ef\">as<\/span> web\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#f92672\">import<\/span> seaborn <span style=\"color:#66d9ef\">as<\/span> sns\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#f92672\">import<\/span> matplotlib.pyplot <span style=\"color:#66d9ef\">as<\/span> plt\n<\/span><\/span><span style=\"display:flex;\"><span>sns<span style=\"color:#f92672\">.<\/span>set(style<span style=\"color:#f92672\">=<\/span><span style=\"color:#e6db74\">&#39;ticks&#39;<\/span>, context<span style=\"color:#f92672\">=<\/span><span style=\"color:#e6db74\">&#39;talk&#39;<\/span>)\n<\/span><\/span><span style=\"display:flex;\"><span>\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#66d9ef\">if<\/span> int(os<span style=\"color:#f92672\">.<\/span>environ<span style=\"color:#f92672\">.<\/span>get(<span style=\"color:#e6db74\">&#34;MODERN_PANDAS_EPUB&#34;<\/span>, <span style=\"color:#ae81ff\">0<\/span>)):\n<\/span><\/span><span style=\"display:flex;\"><span> <span style=\"color:#f92672\">import<\/span> prep <span style=\"color:#75715e\"># noqa<\/span>\n<\/span><\/span><\/code><\/pre><\/div><p>Let&rsquo;s grab some stock data for Goldman Sachs using the <a href=\"http:\/\/pandas-datareader.readthedocs.io\/en\/latest\/\"><code>pandas-datareader<\/code><\/a> package, which spun off of pandas:<\/p>"},{"title":"Modern Pandas (Part 6): Visualization","link":"https:\/\/tomaugspurger.net\/posts\/modern-6-visualization\/","pubDate":"Thu, 28 Apr 2016 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/modern-6-visualization\/","description":"<hr>\n<p>This is part 6 in my series on writing modern idiomatic pandas.<\/p>\n<ul>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-1-intro\">Modern Pandas<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/method-chaining\">Method Chaining<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-3-indexes\">Indexes<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-4-performance\">Fast Pandas<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-5-tidy\">Tidy Data<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-6-visualization\">Visualization<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-7-timeseries\">Time Series<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-8-scaling\">Scaling<\/a><\/li>\n<\/ul>\n<hr>\n<h1 id=\"visualization-and-exploratory-analysis\">Visualization and Exploratory Analysis<\/h1>\n<p>A few weeks ago, the R community went through some hand-wringing about plotting packages.\nFor outsiders (like me) the details aren&rsquo;t that important, but some brief background might be useful so we can transfer the takeaways to Python.\nThe competing systems are &ldquo;base R&rdquo;, which is the plotting system built into the language, and ggplot2, Hadley Wickham&rsquo;s implementation of the grammar of graphics.\nFor those interested in more details, start with<\/p>"},{"title":"Modern Pandas (Part 5): Tidy Data","link":"https:\/\/tomaugspurger.net\/posts\/modern-5-tidy\/","pubDate":"Fri, 22 Apr 2016 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/modern-5-tidy\/","description":"<hr>\n<p>This is part 5 in my series on writing modern idiomatic pandas.<\/p>\n<ul>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-1-intro\">Modern Pandas<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/method-chaining\">Method Chaining<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-3-indexes\">Indexes<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-4-performance\">Fast Pandas<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-5-tidy\">Tidy Data<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-6-visualization\">Visualization<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-7-timeseries\">Time Series<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-8-scaling\">Scaling<\/a><\/li>\n<\/ul>\n<hr>\n<h1 id=\"reshaping--tidy-data\">Reshaping &amp; Tidy Data<\/h1>\n<blockquote>\n<p>Structuring datasets to facilitate analysis <a href=\"http:\/\/www.jstatsoft.org\/v59\/i10\/paper\">(Wickham 2014)<\/a><\/p><\/blockquote>\n<p>So, you&rsquo;ve sat down to analyze a new dataset.\nWhat do you do first?<\/p>\n<p>In episode 11 of <a href=\"https:\/\/www.patreon.com\/NSSDeviations?ty=h\">Not So Standard Deviations<\/a>, Hilary and Roger discussed their typical approaches.\nI&rsquo;m with Hilary on this one, you should make sure your data is tidy.\nBefore you do any plots, filtering, transformations, summary statistics, regressions&hellip;\nWithout a tidy dataset, you&rsquo;ll be fighting your tools to get the result you need.\nWith a tidy dataset, it&rsquo;s relatively easy to do all of those.<\/p>"},{"title":"Modern Panadas (Part 3): Indexes","link":"https:\/\/tomaugspurger.net\/posts\/modern-3-indexes\/","pubDate":"Mon, 11 Apr 2016 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/modern-3-indexes\/","description":"<hr>\n<p>This is part 3 in my series on writing modern idiomatic pandas.<\/p>\n<ul>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-1-intro\">Modern Pandas<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/method-chaining\">Method Chaining<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-3-indexes\">Indexes<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-4-performance\">Fast Pandas<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-5-tidy\">Tidy Data<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-6-visualization\">Visualization<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-7-timeseries\">Time Series<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-8-scaling\">Scaling<\/a><\/li>\n<\/ul>\n<hr>\n<p><code>Indexes<\/code> can be a difficult concept to grasp at first.\nI suspect this is partly becuase they&rsquo;re somewhat peculiar to pandas.\nThese aren&rsquo;t like the indexes put on relational database tables for performance optimizations.\nRather, they&rsquo;re more like the <code>row_labels<\/code> of an R DataFrame, but much more capable.<\/p>"},{"title":"Modern Pandas (Part 4): Performance","link":"https:\/\/tomaugspurger.net\/posts\/modern-4-performance\/","pubDate":"Fri, 08 Apr 2016 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/modern-4-performance\/","description":"<hr>\n<p>This is part 4 in my series on writing modern idiomatic pandas.<\/p>\n<ul>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-1-intro\">Modern Pandas<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/method-chaining\">Method Chaining<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-3-indexes\">Indexes<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-4-performance\">Fast Pandas<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-5-tidy\">Tidy Data<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-6-visualization\">Visualization<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-7-timeseries\">Time Series<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-8-scaling\">Scaling<\/a><\/li>\n<\/ul>\n<hr>\n<p><a href=\"https:\/\/twitter.com\/wesmckinn\">Wes McKinney<\/a>, the creator of pandas, is kind of obsessed with performance. From micro-optimizations for element access, to <a href=\"https:\/\/github.com\/pydata\/pandas\/tree\/master\/pandas\/src\/klib\">embedding<\/a> a fast hash table inside pandas, we all benefit from his and others&rsquo; hard work.\nThis post will focus mainly on making efficient use of pandas and NumPy.<\/p>"},{"title":"Modern Pandas (Part 2): Method Chaining","link":"https:\/\/tomaugspurger.net\/posts\/method-chaining\/","pubDate":"Mon, 04 Apr 2016 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/method-chaining\/","description":"<hr>\n<p>This is part 2 in my series on writing modern idiomatic pandas.<\/p>\n<ul>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-1-intro\">Modern Pandas<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/method-chaining\">Method Chaining<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-3-indexes\">Indexes<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-4-performance\">Fast Pandas<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-5-tidy\">Tidy Data<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-6-visualization\">Visualization<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-7-timeseries\">Time Series<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-8-scaling\">Scaling<\/a><\/li>\n<\/ul>\n<hr>\n<h1 id=\"method-chaining\">Method Chaining<\/h1>\n<p>Method chaining, where you call methods on an object one after another, is in vogue at the moment.\nIt&rsquo;s always been a style of programming that&rsquo;s been possible with pandas,\nand over the past several releases, we&rsquo;ve added methods that enable even more chaining.<\/p>"},{"title":"Modern Pandas (Part 1)","link":"https:\/\/tomaugspurger.net\/posts\/modern-1-intro\/","pubDate":"Mon, 21 Mar 2016 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/modern-1-intro\/","description":"<hr>\n<p>This is part 1 in my series on writing modern idiomatic pandas.<\/p>\n<ul>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-1-intro\">Modern Pandas<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/method-chaining\">Method Chaining<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-3-indexes\">Indexes<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-4-performance\">Fast Pandas<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-5-tidy\">Tidy Data<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-6-visualization\">Visualization<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-7-timeseries\">Time Series<\/a><\/li>\n<li><a href=\"https:\/\/tomaugspurger.net\/posts\/modern-8-scaling\">Scaling<\/a><\/li>\n<\/ul>\n<hr>\n<h1 id=\"effective-pandas\">Effective Pandas<\/h1>\n<h2 id=\"introduction\">Introduction<\/h2>\n<p>This series is about how to make effective use of <a href=\"http:\/\/pandas.pydata.org\">pandas<\/a>, a data analysis library for the Python programming language.\nIt&rsquo;s targeted at an intermediate level: people who have some experience with pandas, but are looking to improve.<\/p>\n<h2 id=\"prior-art\">Prior Art<\/h2>\n<p>There are many great resources for learning pandas; this is not one of them.\nFor beginners, I typically recommend <a href=\"https:\/\/twitter.com\/gjreda\">Greg Reda&rsquo;s<\/a> <a href=\"http:\/\/gregreda.com\/2013\/10\/26\/intro-to-pandas-data-structures\/\">3-part introduction<\/a>, especially if they&rsquo;re familiar with SQL. Of course, there&rsquo;s the pandas <a href=\"http:\/\/pandas.pydata.org\/\">documentation<\/a> itself. I gave <a href=\"https:\/\/www.youtube.com\/watch?v=otCriSKVV_8\">a talk<\/a> at PyData Seattle targeted as an introduction if you prefer video form. Wes McKinney&rsquo;s <a href=\"http:\/\/shop.oreilly.com\/product\/0636920023784.do\">Python for Data Analysis<\/a> is still the goto book (and is also a really good introduction to NumPy as well). Jake VanderPlas&rsquo;s <a href=\"http:\/\/shop.oreilly.com\/product\/0636920034919.do\">Python Data Science Handbook<\/a>, in early release, is great too.\nKevin Markham has a <a href=\"http:\/\/www.dataschool.io\/easier-data-analysis-with-pandas\/\">video series<\/a> for beginners learning pandas.<\/p>"},{"title":"dplyr and pandas","link":"https:\/\/tomaugspurger.net\/posts\/dplyr-pandas\/","pubDate":"Thu, 16 Oct 2014 07:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/dplyr-pandas\/","description":"<p>This notebook compares <a href=\"http:\/\/pandas.pydata.org\">pandas<\/a>\nand <a href=\"http:\/\/cran.r-project.org\/web\/packages\/dplyr\/index.html\">dplyr<\/a>.\nThe comparison is just on syntax (verbage), not performance. Whether you&rsquo;re an R user looking to switch to pandas (or the other way around), I hope this guide will help ease the transition.<\/p>\n<p>We&rsquo;ll work through the <a href=\"http:\/\/cran.r-project.org\/web\/packages\/dplyr\/vignettes\/introduction.html\">introductory dplyr vignette<\/a> to analyze some flight data.<\/p>\n<p>I&rsquo;m working on a better layout to show the two packages side by side.\nBut for now I&rsquo;m just putting the <code>dplyr<\/code> code in a comment above each python call.<\/p>"},{"title":"Practical Pandas Part 3 - Exploratory Data Analysis","link":"https:\/\/tomaugspurger.net\/posts\/pp03\/","pubDate":"Tue, 16 Sep 2014 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/pp03\/","description":"<p>Welcome back. As a reminder:<\/p>\n<ul>\n<li>In <a href=\"http:\/\/tomaugspurger.net\/blog\/2014\/08\/26\/practical-pandas-part-1-reading-the-data\/\">part 1<\/a> we got dataset with my cycling data from last year merged and stored in an HDF5 store<\/li>\n<li>In <a href=\"http:\/\/tomaugspurger.net\/blog\/2014\/09\/04\/practical-pandas-part-2-more-tidying-more-data-and-merging\/\">part 2<\/a> we did some cleaning and augmented the cycling data with data from <a href=\"http:\/\/forecast.io\">http:\/\/forecast.io<\/a>.<\/li>\n<\/ul>\n<p>You can find the full source code and data at this project&rsquo;s <a href=\"https:\/\/github.com\/tomaugspurger\/practicalpandas\">GitHub repo<\/a>.<\/p>\n<p>Today we&rsquo;ll use pandas, seaborn, and\nmatplotlib to do some exploratory data analysis.\nFor fun, we&rsquo;ll make some maps at the end using <a href=\"https:\/\/folium.readthedocs.org\/en\/latest\/\">folium<\/a>.<\/p>"},{"title":"Practical Pandas Part 2 - More Tidying, More Data, and Merging","link":"https:\/\/tomaugspurger.net\/posts\/pp02\/","pubDate":"Thu, 04 Sep 2014 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/pp02\/","description":"<p><em>This is Part 2 in the Practical Pandas Series, where I work through a data analysis problem from start to finish.<\/em><\/p>\n<p>It&rsquo;s a misconception that we can cleanly separate the data analysis pipeline into a linear\nsequence of steps from<\/p>\n<ol>\n<li>data acqusition<\/li>\n<li>data tidying<\/li>\n<li>exploratory analysis<\/li>\n<li>model building<\/li>\n<li>production<\/li>\n<\/ol>\n<p>As you work through a problem you&rsquo;ll realize, &ldquo;I need this other bit of data&rdquo;, or &ldquo;this would be easier if I stored the data this way&rdquo;, or more commonly &ldquo;strange, that&rsquo;s not supposed to happen&rdquo;.<\/p>"},{"title":"Practical Pandas Part 1 - Reading the Data","link":"https:\/\/tomaugspurger.net\/posts\/pp01\/","pubDate":"Tue, 26 Aug 2014 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/pp01\/","description":"<p>This is the first post in a series where I&rsquo;ll show how I use pandas on real-world datasets.<\/p>\n<p>For this post, we&rsquo;ll look at data I collected with <a href=\"http:\/\/abvio.com\/cyclemeter\/\">Cyclemeter<\/a> on\nmy daily bike ride to and from school last year.\nI had to manually start and stop the tracking at the beginning and end of each ride. There may\nhave been times where I forgot to do that, so we&rsquo;ll see if we can find those.<\/p>"},{"title":"Using Python to tackle the CPS (Part 4)","link":"https:\/\/tomaugspurger.net\/posts\/tackling-the-cps-4\/","pubDate":"Mon, 19 May 2014 12:01:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/tackling-the-cps-4\/","description":"<p>Last time, we got to where we&rsquo;d like to have started: One file per month, with each month laid out the same.<\/p>\n<p>As a reminder, the CPS interviews households 8 times over the course of 16 months. They&rsquo;re interviewed for 4 months, take 8 months off, and are interviewed four more times. So if your first interview was in month $m$, you&rsquo;re also interviewed in months $$m + 1, m + 2, m + 3, m + 12, m + 13, m + 14, m + 15$$.<\/p>"},{"title":"Using Python to tackle the CPS (Part 3)","link":"https:\/\/tomaugspurger.net\/posts\/tackling-the-cps-3\/","pubDate":"Mon, 19 May 2014 12:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/tackling-the-cps-3\/","description":"<p>In <a href=\"http:\/\/tomaugspurger.net\/blog\/2014\/02\/04\/tackling%20the%20cps%20(part%202)\/\">part 2<\/a> of this series, we set the stage to parse the data files themselves.<\/p>\n<p>As a reminder, we have a dictionary that looks like<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"><code class=\"language-python\" data-lang=\"python\"><span style=\"display:flex;\"><span>\n<\/span><\/span><span style=\"display:flex;\"><span> id length start end\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#ae81ff\">0<\/span> HRHHID <span style=\"color:#ae81ff\">15<\/span> <span style=\"color:#ae81ff\">1<\/span> <span style=\"color:#ae81ff\">15<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#ae81ff\">1<\/span> HRMONTH <span style=\"color:#ae81ff\">2<\/span> <span style=\"color:#ae81ff\">16<\/span> <span style=\"color:#ae81ff\">17<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#ae81ff\">2<\/span> HRYEAR4 <span style=\"color:#ae81ff\">4<\/span> <span style=\"color:#ae81ff\">18<\/span> <span style=\"color:#ae81ff\">21<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#ae81ff\">3<\/span> HURESPLI <span style=\"color:#ae81ff\">2<\/span> <span style=\"color:#ae81ff\">22<\/span> <span style=\"color:#ae81ff\">23<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span><span style=\"color:#ae81ff\">4<\/span> HUFINAL <span style=\"color:#ae81ff\">3<\/span> <span style=\"color:#ae81ff\">24<\/span> <span style=\"color:#ae81ff\">26<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span> <span style=\"color:#f92672\">...<\/span> <span style=\"color:#f92672\">...<\/span> <span style=\"color:#f92672\">...<\/span> <span style=\"color:#f92672\">...<\/span>\n<\/span><\/span><\/code><\/pre><\/div><p>giving the columns of the raw CPS data files. This post (or two) will describe the reading of the actual data files, and the somewhat tricky process of matching individuals across the different files. After that we can (finally) get into analyzing the data. The old joke is that statisticians spend 80% of their time munging their data, and 20% of their time complaining about munging their data. So 4 posts about data cleaning seems reasonable.<\/p>"},{"title":"Tidy Data in Action","link":"https:\/\/tomaugspurger.net\/posts\/tidy-data-in-action\/","pubDate":"Thu, 27 Mar 2014 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/tidy-data-in-action\/","description":"<p><a href=\"http:\/\/had.co.nz\">Hadley Whickham<\/a> wrote a famous paper (for a certain definition of famous) about the importance of <a href=\"http:\/\/vita.had.co.nz\/papers\/tidy-data.pdf\">tidy data<\/a> when doing data analysis.\nI want to talk a bit about that, using an example from a StackOverflow post, with a solution using <a href=\"http:\/\/pandas.pydata.org\">pandas<\/a>. The principles of tidy data aren&rsquo;t language specific.<\/p>\n<p>A tidy dataset must satisfy three criteria (page 4 in <a href=\"http:\/\/vita.had.co.nz\/papers\/tidy-data.pdf\">Whickham&rsquo;s paper<\/a>):<\/p>\n<ol>\n<li>Each variable forms a column.<\/li>\n<li>Each observation forms a row.<\/li>\n<li>Each type of observational unit forms a table.<\/li>\n<\/ol>\n<p>In this <a href=\"http:\/\/stackoverflow.com\/questions\/22695680\/python-pandas-timedelta-specific-rows\">StackOverflow post<\/a>, the asker had some data NBA games, and wanted to know the number of days since a team last played. Here&rsquo;s the example data:<\/p>"},{"title":"Organizing Papers","link":"https:\/\/tomaugspurger.net\/posts\/organizing-papers\/","pubDate":"Thu, 13 Feb 2014 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/organizing-papers\/","description":"<p>As a graduate student, you read a lot of journal articles&hellip; <em>a lot<\/em>.\nWith the material in the articles being as difficult as it is, I didn&rsquo;t want to worry about organizing everything as well.\nThat&rsquo;s why I wrote <a href=\"https:\/\/gist.github.com\/TomAugspurger\/8976751\">this script<\/a> to help (I may have also been procrastinating from studying for my qualifiers). This was one of my earliest little projects, so I&rsquo;m not claiming that this is the best way to do anything.<\/p>"},{"title":"Using Python to tackle the CPS (Part 2)","link":"https:\/\/tomaugspurger.net\/posts\/tackling-the-cps-2\/","pubDate":"Tue, 04 Feb 2014 12:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/tackling-the-cps-2\/","description":"<p><a href=\"http:\/\/tomaugspurger.net\/blog\/2014\/01\/27\/tackling%20the%20cps\/\">Last time<\/a>, we used Python to fetch some data from the <a href=\"http:\/\/www.census.gov\/cps\/\">Current Population Survey<\/a>. Today, we&rsquo;ll work on parsing the files we just downloaded.<\/p>\n<hr>\n<p>We downloaded two types of files last time:<\/p>\n<ul>\n<li>CPS monthly tables: a fixed-width format text file with the actual data<\/li>\n<li>Data Dictionaries: a text file describing the layout of the monthly tables<\/li>\n<\/ul>\n<p>Our goal is to parse the monthly tables. Here&rsquo;s the first two lines from the unzipped January 1994 file:<\/p>"},{"title":"Using Python to tackle the CPS","link":"https:\/\/tomaugspurger.net\/posts\/tackling-the-cps\/","pubDate":"Mon, 27 Jan 2014 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/posts\/tackling-the-cps\/","description":"<p>The <a href=\"http:\/\/www.census.gov\/cps\/\">Current Population Survey<\/a> is an important source of data for economists. It&rsquo;s modern form took shape in the 70&rsquo;s and unfortunately the data format and distribution shows its age. Some centers like <a href=\"https:\/\/cps.ipums.org\/cps\/\">IPUMS<\/a> have attempted to put a nicer face on accessing the data, but they haven&rsquo;t done everything yet. In this series I&rsquo;ll describe methods I used to fetch, parse, and analyze CPS data for my second year paper. Today I&rsquo;ll describe fetching the data. Everything is available at the paper&rsquo;s <a href=\"https:\/\/github.com\/TomAugspurger\/dnwr-zlb\">GitHub Repository<\/a>.<\/p>"},{"title":"About","link":"https:\/\/tomaugspurger.net\/about\/","pubDate":"Mon, 01 Jan 0001 00:00:00 +0000","guid":"https:\/\/tomaugspurger.net\/about\/","description":"<p>Hi, I&rsquo;m Tom. I&rsquo;m a programmer living in Des Moines, IA.<\/p>\n<h2 id=\"talks\">Talks<\/h2>\n<ul>\n<li>GPU-Accelerated Zarr | <a href=\"https:\/\/youtu.be\/dYt_fabaK60\">video<\/a> | <a href=\"https:\/\/assets.tomaugspurger.net\/tomaugspurger\/posts\/gpu-accelerated-zarr\/GPU%20Acceleterated%20Zarr.pdf\">slides<\/a><\/li>\n<li>GPU-Accelerated Cloud-Native Geospatial | <a href=\"https:\/\/youtu.be\/BFFHXNBj7nA\">video<\/a> | <a href=\"https:\/\/tomaugspurger.net\/assets\/gpu-accelerated-cng.pdf\">slides<\/a><\/li>\n<li>Pandas: <code>.head() to .tail()<\/code> | <a href=\"https:\/\/www.youtube.com\/watch?v=7vuO9QXDN50\">video<\/a> | <a href=\"https:\/\/github.com\/tomaugspurger\/pydata-chi-h2t\">materials<\/a><\/li>\n<li>Mind the Gap! Bridging the scikit-learn - pandas dtype divide | <a href=\"https:\/\/www.youtube.com\/watch?v=KLPtEBokqQ0\">video<\/a> | <a href=\"https:\/\/github.com\/tomaugspurger\/mtg\">materials<\/a><\/li>\n<li>Pandas: <code>.head() to .tail()<\/code> | <a href=\"https:\/\/www.youtube.com\/watch?v=otCriSKVV_8\">video<\/a> | <a href=\"https:\/\/github.com\/tomaugspurger\/pydataSeattle\">materials<\/a><\/li>\n<li>Scalable Sustainability with the Planetary Computer (PyData Global) | <a href=\"https:\/\/www.youtube.com\/watch?v=FzZY9pEl8GU&amp;pp=ygUOdG9tIGF1Z3NwdXJnZXI%3D\">video<\/a> | <a href=\"https:\/\/github.com\/TomAugspurger\/scalable-sustainability-pydata-global\">materials<\/a><\/li>\n<li>Scalable Sustainability Tutorial (Cloud Native Geospatial Day 2022) | <a href=\"https:\/\/youtu.be\/o3FvOKdfR_c?si=ECHBW8v6FihYti3U\">video<\/a> | <a href=\"https:\/\/github.com\/TomAugspurger\/pc-cng-outreach-2022\">materials<\/a><\/li>\n<li>Scalable Geospatial Analysis | <a href=\"https:\/\/youtu.be\/84VNWk_zFTM?si=eceXbNlv7oZn3FhH\">video<\/a><\/li>\n<li>Planetary Computer overview at NASA&rsquo;s Data and Computing Architecture Study (with Bruno) | <a href=\"https:\/\/youtu.be\/8eudm6tRUsU?si=sUnJKreMV6WE6u08&amp;t=548\">video<\/a><\/li>\n<\/ul>\n<h2 id=\"podcasts\">Podcasts<\/h2>\n<ul>\n<li><a href=\"https:\/\/talkpython.fm\/episodes\/show\/334\/microsoft-planetary-computer\">Microsoft Planetary Computer<\/a> on Talk Python<\/li>\n<li><a href=\"https:\/\/www.pythonpodcast.com\/pandas-extension-arrays-with-tom-augspurger-episode-164\/\">Pandas Extension Arrays<\/a> on <code>Podcast.__init__<\/code>.<\/li>\n<\/ul>\n<h2 id=\"writing\">Writing<\/h2>\n<ul>\n<li><a href=\"https:\/\/leanpub.com\/effective-pandas\">Effective Pandas<\/a>: A series on writing effective, idiomatic pandas.<\/li>\n<li>A few posts on <a href=\"https:\/\/medium.com\/@tom.augspurger88\">Medium<\/a> with various co-authors.\n<ul>\n<li><a href=\"https:\/\/medium.com\/pangeo\/managing-environments-5604d848367a\">Managing Pangeo Environments for Distributed Computing<\/a><\/li>\n<li><a href=\"https:\/\/medium.com\/pangeo\/pangeo-with-dask-gateway-4b638825f105\">Pangeo with Dask Gateway<\/a><\/li>\n<li><a href=\"https:\/\/medium.com\/pangeo\/rechunker-the-missing-link-for-chunked-array-analytics-5b2359e9dc11\">Rechunker: The missing link for chunked array analytics<\/a><\/li>\n<\/ul>\n<\/li>\n<li>This Blog<\/li>\n<\/ul>\n<h2 id=\"contact\">Contact<\/h2>\n<p>Either on Mastodon <a href=\"https:\/\/mastodon.social\/@TomAugspurger\">@TomAugspurger@mastodon.social<\/a> or by email\nat <a href=\"mailto:tom.w.augspurger@gmail.com\">tom.w.augspurger@gmail.com<\/a>.<\/p>"}]}}