<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Tirthajyoti Sarkar on Medium]]></title>
        <description><![CDATA[Stories by Tirthajyoti Sarkar on Medium]]></description>
        <link>https://medium.com/@tirthajyoti?source=rss-cb9d97d4b61a------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*pTSc_QyLcIFUlwBBsQnsiA.jpeg</url>
            <title>Stories by Tirthajyoti Sarkar on Medium</title>
            <link>https://medium.com/@tirthajyoti?source=rss-cb9d97d4b61a------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 06:32:14 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@tirthajyoti/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[How to Write Test Code for Data Science Pipeline]]></title>
            <link>https://heartbeat.comet.ml/how-to-write-test-code-for-data-science-pipeline-4ee35956c513?source=rss-cb9d97d4b61a------2</link>
            <guid isPermaLink="false">https://medium.com/p/4ee35956c513</guid>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[heartbeat]]></category>
            <dc:creator><![CDATA[Tirthajyoti Sarkar]]></dc:creator>
            <pubDate>Mon, 14 Feb 2022 14:31:48 GMT</pubDate>
            <atom:updated>2022-02-14T14:31:48.692Z</atom:updated>
            <content:encoded><![CDATA[<h3>How to Write Test Code for a Data Science Pipeline</h3><h4>How to write Pytest code for reliably testing your data science pipeline</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AmS8XNM4YxY8AAm5gL1OgA.jpeg" /><figcaption>Image source: <a href="https://pixabay.com/photos/board-school-university-to-learn-2450236/">Pixabay free image</a></figcaption></figure><p>Testing software modules enhances robustness and trust in the final product/ service. The importance of high-quality testing cannot be emphasized enough in any software development.</p><p>The same argument goes for your data science pipeline too. Even if you are developing a data science codebase mainly for prototyping and research, it’s a good idea to know how to write basic testing modules to check if the functions and classes you are developing are working as they are expected to.</p><p>In fact, I discussed this in detail in one of my previous articles. There I showed that it’s not about checking the input data type. It’s about checking whether your data science pipeline can handle that. It’s not just randomly throwing out-of-range variables at the function. It’s about checking whether the response is as expected.</p><p><a href="https://towardsdatascience.com/pytest-for-machine-learning-a-simple-example-based-tutorial-a3df3c58cf8">PyTest for Machine Learning — a simple example-based tutorial</a></p><p>In this short article, we will look at an example of a typical data science pipeline (consisting of small dedicated functions), instead of a monolith (as shown in the article above), and see how to write a Pytest module for that. We will also look at why writing test modules for data science can be slightly different from that what software engineers or Quality Assurance (QA) folks do every day.</p><h4>The Data Science Pipeline</h4><p>Our pipeline is going to be short and sweet.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NTZWzFAQnIY1ozjjv8Vs8Q.png" /><figcaption>Image source: Created by the author using <a href="https://excalidraw.com/">Excalidraw</a></figcaption></figure><h4>Preprocess</h4><p>Here is the code for preprocessing. It just takes in a Pandas DataFrame and returns training features and targets as Numpy arrays extracted from that DataFrame. We assume that the last column of the DataFrame contains the target values and the rest of the columns are features.</p><pre>def preprocess(df, <br>               test_size=0.25,<br>               random_state=101):<br>    &quot;&quot;&quot;<br>    Precrocesses data<br>    Loads from a dataframe, test/train split<br>    Returns as Numpy arrays<br>    &quot;&quot;&quot;<br>    X = df[df.columns[:-1]]<br>    y = df[df.columns[-1]]<br>    <br>    X_train, X_test, y_train, y_test = train_test_split(X, y, <br>                         test_size=test_size, <br>                         random_state=random_state)<br>    <br>    X_train = np.array(X_train)<br>    y_train = np.array(y_train)<br>    X_test = np.array(X_test)<br>    y_test = np.array(y_test)<br>    return (X_train, X_test, y_train, y_test)</pre><h4>Model Fit</h4><p>The model fitting code is even shorter. But it does have a try-except block and a couple of assertion checks to make sure that the input type is a Numpy array. We will see how Pytest uses these checks.</p><pre>def training(X_train,y_train):<br>    &quot;&quot;&quot;<br>    Trains a model<br>    &quot;&quot;&quot;<br>    try:<br>        assert isinstance(X_train,np.ndarray),&quot;Features must be a Numpy array&quot;<br>        assert isinstance(y_train,np.ndarray),&quot;Targets must be a Numpy array&quot;<br>        lm = LinearRegression()<br>        lm.fit(X_train,y_train)<br>        return lm<br>    except AssertionError as msg:<br>        return msg</pre><h4>Model Save</h4><p>Then we have a model-saving code that saves the fitted model to a file using the joblib module. It also adds date-time versioning to the filename.</p><pre>def save_model(model, fname = &#39;linear-model&#39;):<br>    &quot;&quot;&quot;<br>    Saves the model with datetime adder (versioning)<br>    &quot;&quot;&quot;<br>    try:<br>        now = datetime.datetime.now()<br>        dt_adder = str(now.month)+str(now.day)+str(now.year)+&#39;_&#39;+\<br>            str(now.hour)+str(now.minute)<br>        fname = fname+&#39;_&#39;+dt_adder+&#39;.sav&#39;<br>        dump(model, fname)<br>        return 1<br>    except:<br>        return 0</pre><h4>Load and Predict</h4><p>Finally, we have a short function for loading the joblib object (from a given filename) and making predictions for some given data. It checks the data dimension to make sure that the model can work with that i.e. the dimensions are compatible.</p><pre>def predict(model,data):<br>    &quot;&quot;&quot;<br>    Predicts for some data using the model (give as the filename)<br>    &quot;&quot;&quot;<br>    try:<br>        lm = load(model)<br>    except:<br>        return 0<br>    assert len(lm.coef_) == data.shape[1],&quot;Data dimension is not suitable for this model&quot;<br>    preds = lm.predict(data)<br>    <br>    return preds</pre><p>That’s it for the actual pipeline code. We put all of these functions into a single file called <strong>pipeline.py</strong> and move on to write the actual test code.</p><blockquote>Existing ML applications may surprise you — <a href="http://go.comet.ml/webinar-Machine-Learning-Vignesh-ShettyGE-Healthcare.html">watch our interview with GE Healthcare’s Vignesh Shetty</a> to learn how his team is using ML in the healthcare setting.</blockquote><h3>The Test Code for the Pipeline</h3><p>We will use a lightweight but powerful Python testing library, Pytest, for this demo. You can <a href="https://docs.pytest.org/en/6.2.x/"><strong>read more about it here</strong></a>.</p><p>The way Pytest works is that we create a test script (a Python file) and run it with the following command:</p><pre>pytest test_pipeline.py</pre><p>Here, we assumed that our test script is named test_pipeline.py for the obvious reason that it is testing the code in pipeline.py.</p><p>The types and variety of the test are only limited by your imagination and business needs. We just show some simple examples with the first two modules of the data pipeline here. An illustration is shown below:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RWfxSiaa8_GQYpXvUvCSjw.png" /><figcaption>Image source: Created by the author using <a href="https://excalidraw.com/">Exclidraw</a>.</figcaption></figure><p>The fundamental principle to remember is that you should write test code only for the specific function that you want to test i.e. test what that function is supposed to do. This means for the preprocess function — as it is written today — do not try to check its input data type yet. That should be handled by the function code and not the external test code.</p><p>So, our test_pipeline.py starts by loading the main script and pytest, and then it imports other libraries as needed.</p><pre>from pipeline import *<br>import pytest<br>import...</pre><h4>Testing the Preprocess Function</h4><p>Here is the code for testing the preprocess function only. Note that the test functions must have a name starting with test_.</p><p>We start by generating some random data and using the preprocess function on this data. We also have a test case for a specific test-set (related to test/train split, not Pytest) fraction of 0.5.</p><pre>def test_preprocess():<br>    &quot;&quot;&quot;<br>    Tests the returned object from preprocessing<br>    &quot;&quot;&quot;<br>    # Generate a random dataset<br>    df = random_data_constructor()<br>    # Use the preprocess function and get the returned object<br>    preprocess_return = preprocess(df)<br>    # Same as above with a specific test_size of 0.5<br>    preprocess_return_test_size = preprocess(df,test_size=0.5)</pre><p>Then, we write the actual check code. It checks</p><ul><li>That the returned data type is a tuple</li><li>The tuple has 4 objects</li><li>Each of those objects is NumPy array type</li></ul><pre># Type check<br>assert isinstance(preprocess_return, tuple)<br># Length check<br>assert len(preprocess_return) == 4<br># Tuple element type check<br>assert isinstance(preprocess_return[0],np.ndarray)<br>assert isinstance(preprocess_return[1],np.ndarray)<br>assert isinstance(preprocess_return[2],np.ndarray)<br>assert isinstance(preprocess_return[3],np.ndarray)</pre><p>We also check if the test/train splits dimensions match up properly.</p><pre># Test size fraction check<br>    preprocess_return_test_size[0].shape == preprocess_return_test_size[2].shape<br>    preprocess_return_test_size[1].shape == preprocess_return_test_size[3].shape</pre><p>The next step is interesting. Pytest provides context managers that can accept exceptions like ValueError or ZeroDiviosnError and check if the function actually raised that. In this case, we pass invalid test set fractions (-0.5 or 1.5) and expect the Scikit-learn function to raise a ValueError. We test for that.</p><pre># (Invalid) test size exception check<br>    <strong>with pytest.raises(ValueError)</strong>:<br>        preprocess_return_invalid_test_size = preprocess(df,test_size=-0.5)<br>        preprocess_return_invalid_test_size = preprocess(df,test_size=1.5)</pre><p><strong>This is where testing for data science code needs data science knowledge</strong>. As a data scientist, you need to know how to break the function and also what specific kind of exception/error will be generated. To pass the Pytest screen, you have to incorporate that in the test code.</p><h4>Testing the Model Training Function</h4><p>Again, we start by generating fresh random data, preprocessing it, and getting a trained model back by passing the preprocessed data into the training function.</p><pre>def test_training():<br>    &quot;&quot;&quot;<br>    Tests the training function<br>    &quot;&quot;&quot;<br>    # Generate a random dataset<br>    df = random_data_constructor()<br>    # Use the preprocess function<br>    X_train, X_test, y_train, y_test = preprocess(df)<br>    # Get back the trained model<br>    trained_model = training(X_train,y_train)</pre><p>Then, the primary tests we do are type checking. First, type check for the returned object.</p><pre># Type check for the returned object<br>assert isinstance(trained_model, <strong>sklearn.linear_model._base.LinearRegression</strong>)</pre><p>Then, we pass on an invalid data type for the <em>X</em> input. The function is supposed to check this internally and return a specific AssertionError as message. Note how we are checking the content of that message here using Pytest.</p><pre># AssertionError check for wrong input type<br>msg = training(&#39;X&#39;,y_train)<br>assert isinstance(msg, AssertionError)<br>assert msg.args[0] == &quot;Features must be a Numpy array&quot;</pre><p>We do the exact same thing for the <em>y</em> vector.</p><pre>msg = training(X_train,&#39;y&#39;)<br>assert isinstance(msg, AssertionError)<br>assert msg.args[0] == &quot;Targets must be a Numpy array&quot;</pre><p>One thing is to be noted with care: Pytest did not check for the <em>X</em> or <em>y</em> data type, the main training function did. Pytest is only checking whether the training function is doing its job properly by checking the returned message.</p><h3>Running the Tests and Next Steps</h3><p>As we said before, we run these tests on the CLI.</p><pre>pytest test_pipeline.py</pre><p>And, if everything goes well, we may get this. There were two functions starting with test_</p><ul><li>test_preprocess</li><li>test_training</li></ul><p>And they passed — all the assert statements inside them yielded True.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zjFlFZgtsyQ5bylplrL62A.png" /><figcaption>Image source: Result and snapshot created by the author</figcaption></figure><h4>The Rest is Up to You</h4><p><strong>You may be tempted to test the training function for all kinds of predictions with all kinds of data. Don’t do that here</strong>. Do those tests in the predict function, because that’s where the prediction is coming into the picture. This is how you maintain the modularity and compartmentalization of your code and software.</p><p>Loved the article? Become a <a href="https://medium.com/@tirthajyoti/membership"><strong>Medium member</strong></a> to continue <strong>learning without limits</strong>. I’ll receive a portion of your membership fee if you use the following link, <strong>with no extra cost to you</strong><em>.</em></p><p><a href="https://medium.com/@tirthajyoti/membership">Join Medium with my referral link - Tirthajyoti Sarkar</a></p><p><em>Editor’s Note: </em><a href="https://heartbeat.comet.ml/"><em>Heartbeat</em></a><em> is a contributor-driven online publication and community dedicated to providing premier educational resources for data science, machine learning, and deep learning practitioners. We’re committed to supporting and inspiring developers and engineers from all walks of life.</em></p><p><em>Editorially independent, Heartbeat is sponsored and published by </em><a href="http://comet.ml/?utm_campaign=heartbeat-statement&amp;utm_source=blog&amp;utm_medium=medium"><em>Comet</em></a><em>, an MLOps platform that enables data scientists &amp; ML teams to track, compare, explain, &amp; optimize their experiments. We pay our contributors, and we don’t sell ads.</em></p><p><em>If you’d like to contribute, head on over to our</em><a href="https://heartbeat.fritz.ai/call-for-contributors-october-2018-update-fee7f5b80f3e"><em> call for contributors</em></a><em>. You can also sign up to receive our weekly newsletters (</em><a href="https://www.deeplearningweekly.com/"><em>Deep Learning Weekly</em></a><em> and the </em><a href="https://info.comet.ml/newsletter-signup/"><em>Comet Newsletter</em></a><em>), join us on</em><a href="https://join.slack.com/t/fritz-ai-community/shared_invite/enQtNTY5NDM2MTQwMTgwLWU4ZDEwNTAxYWE2YjIxZDllMTcxMWE4MGFhNDk5Y2QwNTcxYzEyNWZmZWEwMzE4NTFkOWY2NTM0OGQwYjM5Y2U"><em> </em></a><a href="https://join.slack.com/t/cometml/shared_invite/zt-49v4zxxz-qHcTeyrMEzqZc5lQb9hgvw"><em>Slack</em></a><em>, and follow Comet on </em><a href="https://twitter.com/Cometml"><em>Twitter</em></a><em> and </em><a href="https://www.linkedin.com/company/comet-ml/"><em>LinkedIn</em></a><em> for resources, events, and much more that will help you build better ML models, faster.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4ee35956c513" width="1" height="1" alt=""><hr><p><a href="https://heartbeat.comet.ml/how-to-write-test-code-for-data-science-pipeline-4ee35956c513">How to Write Test Code for Data Science Pipeline</a> was originally published in <a href="https://heartbeat.comet.ml/">Heartbeat</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Time-Profiling Data Science Code]]></title>
            <link>https://heartbeat.comet.ml/time-profiling-data-science-code-9b893fe67cd9?source=rss-cb9d97d4b61a------2</link>
            <guid isPermaLink="false">https://medium.com/p/9b893fe67cd9</guid>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[heartbeat]]></category>
            <dc:creator><![CDATA[Tirthajyoti Sarkar]]></dc:creator>
            <pubDate>Thu, 03 Feb 2022 13:57:14 GMT</pubDate>
            <atom:updated>2022-02-03T13:57:14.054Z</atom:updated>
            <content:encoded><![CDATA[<h4>Why and how to profile your data science code</h4><p>As a data scientist, a common question to expect from your engineering/ platform team is “<strong>how much memory footprint </strong>does your model/code have?” or “<strong>what is the execution time of the various data science (DS) modules </strong>when running with some given data load?”</p><p>This is quite a natural query and there could be a number of reasons behind it:</p><ul><li>Hardware resources may be limited.</li><li>A single ML or DS module should not hog all the memory or CPU resources of the system.</li><li>The stability of the overall platform may depend on how the individual DS modules are using the CPU resources.</li><li>Input data characteristics may change frequently that may render DS modules less performant e.g., a simple data cleaning routine scaling badly when the data velocity goes from gigabytes/hour to terabytes/hour.</li></ul><p>Some of these concerns are particularly critical for <strong>edge computing</strong> scenarios where the ML app may be running inside a <strong>virtualized container</strong> on an <strong>industrial PC</strong> (and with no cloud-supported auto-scaling of memory or dynamic allocation).</p><p>Also, your model may just be <strong>one of the hundreds of ML models</strong> running on that piece of hardware or platform. Therefore, you must have some idea about the peak memory/ CPU usage of the model because if multiple models peak in their usage at the same time, that can crash the whole system.</p><p>All of these models do not necessarily come from the same data scientist either. Various teams might have developed them over time. It makes sense to have a <strong>common mechanism of measuring</strong> or gauging the memory usage (peak and average) and CPU execution profile of all those models (and data science code in general).</p><p>Therefore, in this article, we will learn how to time-profile a typical piece of data science code using a built-in Python module cProfile. This knowledge will help data scientists in all sorts of projects and tasks where they have to measure the computational load of their code or modules. For a team, such a tool can help <strong>compare and benchmark the optimal code/function</strong> that satisfies some timing requirements and find out inefficiencies along the way.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*UUSyEatwoLtdtarChsCxAg.png" /><figcaption>Image source: Created by the author</figcaption></figure><h3>Memory Profile Using “Scalene”</h3><p>In a previous article, I discussed in detail memory profiling a typical ML workflow code using a nifty little library called Scalene.</p><p><a href="https://towardsdatascience.com/how-much-memory-is-your-ml-code-consuming-98df64074c8f">How Much Memory is your ML Code Consuming?</a></p><p>In that article, I showed <strong>how the memory profile may vary widely between ML model types and how they scale with data size</strong>. It was shown that external I/O may take up more memory than the ML model if the parametric size of the model is modest. In the current article, we focus on basic CPU time profiles (as taken up by individual functions or even lines of code) and how they can be gauged using a built-in Python profiler.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LWbIE5EYHBszPSXyRHsYOw.png" /><figcaption>Image source: Created by the author</figcaption></figure><h3>Timing Profile with cProfile</h3><p>In one of my <a href="https://medium.com/r?url=https%3A%2F%2Ftowardsdatascience.com%2Foptimize-ml-modeling-using-a-timing-decorator-2b113c6b60d9">previous articles</a>, I showed basic tricks and techniques to measure the execution time of simple code blocks or a function with a timing decorator.</p><p>Now we will discuss a built-in Python library cProfile that can give us a detailed timing profile about the various parts of our data science code with a simple command. The advantage is that we don’t have to insert code snippets like time.time() in various places and track them manually.</p><h4>Basic Usage</h4><p>The cProfile library comes with the default Python installation so there is nothing to install. Let us see the basic usage with a simple code where we are adding two Numpy arrays.</p><pre>import numpy as np<br>import cProfile</pre><pre># Two Numpy arrays<br>SIZE = 10_000_000<br>a = np.arange(SIZE)<br>b = np.random.normal(size=SIZE)</pre><pre># Profling array addition<br>cProfile.run(&#39;a+b&#39;)</pre><p>So, the main thing to notice is that we have to wrap the code within a string and pass it on to the cProfile.run function. Here the code is simply ‘a+b’. The output may look something like the following (the exact time will vary, of course, depending on the underlying hardware).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/835/1*GWilL5twBiUhoe8_zNQgrw.png" /><figcaption>Image source: Result generated by the author</figcaption></figure><p>The interesting thing to remember is that the only piece of code that was measured for timing is the snippet — “a+b”. The array creation is not being measured here, only the addition.</p><p>If we wanted to measure the timing profile of all the steps, we could write:</p><pre>code = <br>&quot;&quot;&quot;<br>SIZE = 10_000_000<br>a = np.arange(SIZE)<br>b = np.random.normal(size=SIZE)<br>a+b<br>&quot;&quot;&quot;</pre><pre>cProfile.run(code)</pre><p>Here we put all the code inside the string variable code and then pass that on to the cProfile.run function. The output looks different, as expected.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/967/1*22kMhpx0IHQh326kmoyjPw.png" /><figcaption>Image source: Result generated by the author</figcaption></figure><p>Note the extra array creation operations resulted in a total of five function calls, as opposed to three for the basic addition code.</p><h4>With a Function as the Argument</h4><p>We could, of course, create a standalone function and pass the name of that object to cProfile.run function for the same task.</p><pre>def add():<br>    SIZE = 10_000_000<br>    a = np.arange(SIZE)<br>    b = np.random.normal(size=SIZE)<br>    c=a+b</pre><pre>cProfile.run(&#39;add()&#39;)</pre><p>The output is similar to the figure above, but an additional function call is registered that comes from the construction of the add function itself.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/954/1*iiwCGX8Ok5gPoQAEeu3flw.png" /></figure><p>The function that is passed on to cProfile can have any arguments as well. In many cases, we can change the arguments and see the impact on the profile results. This is one of the most obvious use-cases of the library. We rewrite the add function to accept a size argument.</p><pre>def add(size):<br>    a = np.arange(size)<br>    b = np.random.normal(size=size)<br>    c=a+b</pre><blockquote>Siloed workflows no longer cut it. An MLOps strategy can bring your team together and get models out the door faster. <a href="https://www.comet.ml/site/on-demand-panel-defining-the-mlops-stack/">Watch our webinar with industry experts to learn more about the power of MLOps</a>.</blockquote><p>Then, we can use that to profile the array operations with 10-million elements.</p><pre>SIZE = 10_000_000<br>cProfile.run(&#39;add(SIZE)&#39;)</pre><p>We get this as the output:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/552/1*7mJrnBZG16SAINKrKdMnRg.png" /></figure><p>When we change the number of elements to 20 million, it reflects immediately:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/550/1*cVw7zIeHNXksmU7bvedoUw.png" /></figure><h4>Using the Profiler Class</h4><p>cProfile has a special Profiler class that stores all the important information and it can be enabled/disabled programmatically. We can also use the pstats library and pass this Profiler object to it for printing and extracting data. Here is the code to measure and print the total execution time:</p><pre>import cProfile, pstats</pre><pre>profiler = cProfile.Profile()</pre><pre># Enable profiler<br>profiler.enable()</pre><pre># Function execution<br>add(SIZE)</pre><pre># Disable profiler<br>profiler.disable()</pre><pre># pstats<br>stats = pstats.Stats(profiler)</pre><pre># Print the total time and function calls<br>print(&quot;Total function calls:&quot;, stats.total_calls)<br>print(&quot;Total time (seconds):&quot;, stats.total_tt)</pre><p>The result will look something like this:</p><pre>&gt;&gt; Total function calls: 48<br>&gt;&gt; Total time (seconds): 1.1797575999999999</pre><p>Here we get the execution time from the total_tt attribute of the stats object and the number of calls from the total_calls attribute.</p><p>Consequently, this opens up the possibility to <strong>programmatically control the profiling and storing of the information</strong> as needed. For example, we can profile the execution of the same add function over a range of array sizes.</p><pre>size = [int(i*1e6) for i in range(5,26,5)]<br>total_tt = []</pre><pre>for s in size:<br>    profiler = cProfile.Profile()<br>    profiler.enable()<br>    add(s)<br>    profiler.disable()<br>    stats = pstats.Stats(profiler)<br>    total_tt.append(round(stats.total_tt,3))</pre><p>So, the timings are stored in the total_tt array. When plotted, it shows the expected pattern.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/979/1*vzPDnEG2MlTQ5n2oW42G4g.png" /><figcaption>Image source: Result generated by the author</figcaption></figure><h3>Considerations for DS Workflow</h3><p>While measuring the execution time of these small standalone functions serves as a basic demonstration of the usage of these profilers, the real utility is realized when they are used in a large-scale data science workflow.</p><h4>Final Validation can be Useful</h4><p>For low-resource situations, it could be a good idea to host a validation environment/server which will accept a given modeling code (when developed) and run it through such a memory profiler to create runtime statistics. If it passes pre-determined criteria of memory footprint, only then the modeling code will be accepted for further deployment.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/0*rSvYUzuUiuAgzzKW.png" /><figcaption>Image source: Created by the author produced (also used <a href="https://towardsdatascience.com/how-much-memory-is-your-ml-code-consuming-98df64074c8f">here</a>)</figcaption></figure><h4>Measure all Modules</h4><p>Such a workflow has a variety of modules and functions and we can set up profiling for all of them if necessary. The output may be <strong>logged into a database</strong> or even be fed into a <strong>monitoring system</strong> that will track the performance of the modules over time and take action if needed (e.g., a function has poorly performed and took too much time in a certain run or for a certain input data).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4gy-dbBJoreEjlfJuoXsOA.png" /><figcaption>Image source: Created by the author produced</figcaption></figure><h3>Summary</h3><p>In this article we discussed the importance of memory and time profiling your data science/machine learning code for smooth and easy interfacing with the platform/engineering team. This is expected to ease the deployment of the code on a service/machine.</p><p>We showed the basic usage of the built-in Python timing profiler cProfile and how it can be used with raw code or function modules. We demonstrated how to extract the total execution time or the number of function calls using this library for Numpy operations. The idea can be extended to any data science workflow that consists of many stages and modules.</p><p><strong><em>Note</em></strong>: The basic code is contained in this <a href="https://github.com/tirthajyoti/Machine-Learning-with-Python/blob/master/Time-profiling/cProfile.ipynb"><strong>Jupyter Notebook</strong></a> on my Github repo.</p><p>Every data science team or organization may have its own style for measuring code and module efficiency and memory footprint. The motivation for this article was to introduce the readers to their importance and show some hands-on examples so that they can explore further to be ready for such implementation.</p><p><em>Loved the article? Become a </em><a href="https://medium.com/@tirthajyoti/membership"><strong><em>Medium member</em></strong></a><em> to continue </em><strong><em>learning without limits</em></strong><em>. I’ll receive a portion of your membership fee if you use the following link, </em><strong><em>with no extra cost to you</em></strong><em>.</em></p><p><a href="https://medium.com/@tirthajyoti/membership">Join Medium with my referral link - Tirthajyoti Sarkar</a></p><p><em>Editor’s Note: </em><a href="https://heartbeat.comet.ml/"><em>Heartbeat</em></a><em> is a contributor-driven online publication and community dedicated to providing premier educational resources for data science, machine learning, and deep learning practitioners. We’re committed to supporting and inspiring developers and engineers from all walks of life.</em></p><p><em>Editorially independent, Heartbeat is sponsored and published by </em><a href="http://comet.ml/?utm_campaign=heartbeat-statement&amp;utm_source=blog&amp;utm_medium=medium"><em>Comet</em></a><em>, an MLOps platform that enables data scientists &amp; ML teams to track, compare, explain, &amp; optimize their experiments. We pay our contributors, and we don’t sell ads.</em></p><p><em>If you’d like to contribute, head on over to our</em><a href="https://heartbeat.fritz.ai/call-for-contributors-october-2018-update-fee7f5b80f3e"><em> call for contributors</em></a><em>. You can also sign up to receive our weekly newsletters (</em><a href="https://www.deeplearningweekly.com/"><em>Deep Learning Weekly</em></a><em> and the </em><a href="https://info.comet.ml/newsletter-signup/"><em>Comet Newsletter</em></a><em>), join us on</em><a href="https://join.slack.com/t/fritz-ai-community/shared_invite/enQtNTY5NDM2MTQwMTgwLWU4ZDEwNTAxYWE2YjIxZDllMTcxMWE4MGFhNDk5Y2QwNTcxYzEyNWZmZWEwMzE4NTFkOWY2NTM0OGQwYjM5Y2U"><em> </em></a><a href="https://join.slack.com/t/cometml/shared_invite/zt-49v4zxxz-qHcTeyrMEzqZc5lQb9hgvw"><em>Slack</em></a><em>, and follow Comet on </em><a href="https://twitter.com/Cometml"><em>Twitter</em></a><em> and </em><a href="https://www.linkedin.com/company/comet-ml/"><em>LinkedIn</em></a><em> for resources, events, and much more that will help you build better ML models, faster.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9b893fe67cd9" width="1" height="1" alt=""><hr><p><a href="https://heartbeat.comet.ml/time-profiling-data-science-code-9b893fe67cd9">Time-Profiling Data Science Code</a> was originally published in <a href="https://heartbeat.comet.ml/">Heartbeat</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Explainable AI and the Focus on Human Curiosity]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/data-science/explainable-ai-and-the-focus-on-human-curiosity-aa816aaf3caa?source=rss-cb9d97d4b61a------2"><img src="https://cdn-images-1.medium.com/max/1720/1*A0_5e9Z5bvKZZl8TE1Qkqg.png" width="1720"></a></p><p class="medium-feed-snippet">and concentrating on the top few factors and counterfactuals</p><p class="medium-feed-link"><a href="https://medium.com/data-science/explainable-ai-and-the-focus-on-human-curiosity-aa816aaf3caa?source=rss-cb9d97d4b61a------2">Continue reading on TDS Archive »</a></p></div>]]></description>
            <link>https://medium.com/data-science/explainable-ai-and-the-focus-on-human-curiosity-aa816aaf3caa?source=rss-cb9d97d4b61a------2</link>
            <guid isPermaLink="false">https://medium.com/p/aa816aaf3caa</guid>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[explainable-ai]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[data-science]]></category>
            <dc:creator><![CDATA[Tirthajyoti Sarkar]]></dc:creator>
            <pubDate>Mon, 24 Jan 2022 08:31:37 GMT</pubDate>
            <atom:updated>2022-01-25T08:59:22.051Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Data drift: It can come at you from anywhere]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/data-science/data-drift-it-can-come-at-you-from-anywhere-b78eb186855?source=rss-cb9d97d4b61a------2"><img src="https://cdn-images-1.medium.com/max/1383/1*TnU7qZ0SUvvjCMM7E6e91g.png" width="1383"></a></p><p class="medium-feed-snippet">The concept of data drift is illustrated visually in various shapes and forms.</p><p class="medium-feed-link"><a href="https://medium.com/data-science/data-drift-it-can-come-at-you-from-anywhere-b78eb186855?source=rss-cb9d97d4b61a------2">Continue reading on TDS Archive »</a></p></div>]]></description>
            <link>https://medium.com/data-science/data-drift-it-can-come-at-you-from-anywhere-b78eb186855?source=rss-cb9d97d4b61a------2</link>
            <guid isPermaLink="false">https://medium.com/p/b78eb186855</guid>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <dc:creator><![CDATA[Tirthajyoti Sarkar]]></dc:creator>
            <pubDate>Wed, 19 Jan 2022 19:31:36 GMT</pubDate>
            <atom:updated>2022-01-20T08:49:43.784Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[The Right Hardware for your AI workload —Unusual Considerations]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/data-science/the-right-hardware-for-your-ai-workload-unusual-considerations-84e072bb8a30?source=rss-cb9d97d4b61a------2"><img src="https://cdn-images-1.medium.com/max/1275/1*l0QA1rPy8VoNdgohCLZKHw.png" width="1275"></a></p><p class="medium-feed-snippet">We point out a few less-mentioned and underrated features and inter-relationships to keep in mind while designing the best hardware&#x2026;</p><p class="medium-feed-link"><a href="https://medium.com/data-science/the-right-hardware-for-your-ai-workload-unusual-considerations-84e072bb8a30?source=rss-cb9d97d4b61a------2">Continue reading on TDS Archive »</a></p></div>]]></description>
            <link>https://medium.com/data-science/the-right-hardware-for-your-ai-workload-unusual-considerations-84e072bb8a30?source=rss-cb9d97d4b61a------2</link>
            <guid isPermaLink="false">https://medium.com/p/84e072bb8a30</guid>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[cloud-computing]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <dc:creator><![CDATA[Tirthajyoti Sarkar]]></dc:creator>
            <pubDate>Mon, 17 Jan 2022 20:00:05 GMT</pubDate>
            <atom:updated>2022-01-19T19:06:09.801Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Don’t just fit data, gain insights too]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/data-science/dont-just-fit-data-gain-insights-too-1dba73d3cf8e?source=rss-cb9d97d4b61a------2"><img src="https://cdn-images-1.medium.com/max/845/0*wPcQLnpGELMdIBvW.PNG" width="845"></a></p><p class="medium-feed-snippet">A lightweight Python package can give you a lot of insights into your regression problems.</p><p class="medium-feed-link"><a href="https://medium.com/data-science/dont-just-fit-data-gain-insights-too-1dba73d3cf8e?source=rss-cb9d97d4b61a------2">Continue reading on TDS Archive »</a></p></div>]]></description>
            <link>https://medium.com/data-science/dont-just-fit-data-gain-insights-too-1dba73d3cf8e?source=rss-cb9d97d4b61a------2</link>
            <guid isPermaLink="false">https://medium.com/p/1dba73d3cf8e</guid>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[python]]></category>
            <dc:creator><![CDATA[Tirthajyoti Sarkar]]></dc:creator>
            <pubDate>Thu, 13 Jan 2022 22:02:40 GMT</pubDate>
            <atom:updated>2022-01-14T05:32:45.155Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[How AI can help smart city initiatives]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/data-science/how-ai-can-help-smart-city-initiatives-f83484891343?source=rss-cb9d97d4b61a------2"><img src="https://cdn-images-1.medium.com/max/1373/1*eHy8rE608d2V7ANfTcrHQQ.png" width="1373"></a></p><p class="medium-feed-snippet">Some ideas for helping smart city initiatives, based on AI perception and citizen data sourcing.</p><p class="medium-feed-link"><a href="https://medium.com/data-science/how-ai-can-help-smart-city-initiatives-f83484891343?source=rss-cb9d97d4b61a------2">Continue reading on TDS Archive »</a></p></div>]]></description>
            <link>https://medium.com/data-science/how-ai-can-help-smart-city-initiatives-f83484891343?source=rss-cb9d97d4b61a------2</link>
            <guid isPermaLink="false">https://medium.com/p/f83484891343</guid>
            <category><![CDATA[smart-cities]]></category>
            <category><![CDATA[digital-transformation]]></category>
            <category><![CDATA[artifical-intellegence]]></category>
            <category><![CDATA[data-science]]></category>
            <dc:creator><![CDATA[Tirthajyoti Sarkar]]></dc:creator>
            <pubDate>Mon, 10 Jan 2022 14:37:36 GMT</pubDate>
            <atom:updated>2022-01-10T14:37:36.418Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[“Digital Twin” with Python: A hands-on example]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/data-science/digital-twin-with-python-a-hands-on-example-2a3036124b61?source=rss-cb9d97d4b61a------2"><img src="https://cdn-images-1.medium.com/max/2600/1*fUzLf-B6LQ1Y_E35pGZpWQ.png" width="3821"></a></p><p class="medium-feed-snippet">A step-by-step guide to building a digital twin example of an electronic switch (transistor) with Python.</p><p class="medium-feed-link"><a href="https://medium.com/data-science/digital-twin-with-python-a-hands-on-example-2a3036124b61?source=rss-cb9d97d4b61a------2">Continue reading on TDS Archive »</a></p></div>]]></description>
            <link>https://medium.com/data-science/digital-twin-with-python-a-hands-on-example-2a3036124b61?source=rss-cb9d97d4b61a------2</link>
            <guid isPermaLink="false">https://medium.com/p/2a3036124b61</guid>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[digital-transformation]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[tech]]></category>
            <dc:creator><![CDATA[Tirthajyoti Sarkar]]></dc:creator>
            <pubDate>Wed, 15 Dec 2021 14:04:08 GMT</pubDate>
            <atom:updated>2021-12-15T17:19:55.032Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Regression in the face of messy outliers? Try Huber regressor]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/data-science/regression-in-the-face-of-messy-outliers-try-huber-regressor-3a54ddc12516?source=rss-cb9d97d4b61a------2"><img src="https://cdn-images-1.medium.com/max/2600/1*X8YMmvAynEf7nbF5LzHvig.png" width="3458"></a></p><p class="medium-feed-snippet">Outliers in the data are ubiquitous, and they can mess up your regression problem. Try Hubber regressor to tackle this problem.</p><p class="medium-feed-link"><a href="https://medium.com/data-science/regression-in-the-face-of-messy-outliers-try-huber-regressor-3a54ddc12516?source=rss-cb9d97d4b61a------2">Continue reading on TDS Archive »</a></p></div>]]></description>
            <link>https://medium.com/data-science/regression-in-the-face-of-messy-outliers-try-huber-regressor-3a54ddc12516?source=rss-cb9d97d4b61a------2</link>
            <guid isPermaLink="false">https://medium.com/p/3a54ddc12516</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Tirthajyoti Sarkar]]></dc:creator>
            <pubDate>Thu, 04 Nov 2021 12:23:36 GMT</pubDate>
            <atom:updated>2021-11-04T12:23:36.216Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Spearman coefficient: Tool for a generalized correlation analysis]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/data-science/spearman-coefficient-tool-for-a-generalized-correlation-analysis-d15b70d4ff1e?source=rss-cb9d97d4b61a------2"><img src="https://cdn-images-1.medium.com/max/669/1*YT0Mb5FueEa3gnFHfhG2rQ.png" width="669"></a></p><p class="medium-feed-snippet">Linear relationships are not all a correlation analysis can reveal. We discuss rank-based correlation that is more generalized and&#x2026;</p><p class="medium-feed-link"><a href="https://medium.com/data-science/spearman-coefficient-tool-for-a-generalized-correlation-analysis-d15b70d4ff1e?source=rss-cb9d97d4b61a------2">Continue reading on TDS Archive »</a></p></div>]]></description>
            <link>https://medium.com/data-science/spearman-coefficient-tool-for-a-generalized-correlation-analysis-d15b70d4ff1e?source=rss-cb9d97d4b61a------2</link>
            <guid isPermaLink="false">https://medium.com/p/d15b70d4ff1e</guid>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[analytics]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[technology]]></category>
            <dc:creator><![CDATA[Tirthajyoti Sarkar]]></dc:creator>
            <pubDate>Mon, 01 Nov 2021 04:25:27 GMT</pubDate>
            <atom:updated>2022-01-10T15:01:33.909Z</atom:updated>
        </item>
    </channel>
</rss>