<?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"><channel><title><![CDATA[Technology @ finger tips]]></title><description><![CDATA[Trying to explain the latest technology and trends in layman's terms.]]></description><link>https://blog.noufals.in</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1717938950621/V_v64h5td.png</url><title>Technology @ finger tips</title><link>https://blog.noufals.in</link></image><generator>RSS for Node</generator><lastBuildDate>Thu, 17 Sep 2026 01:40:01 GMT</lastBuildDate><atom:link href="https://blog.noufals.in/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Unlocking the Potential: Evaluating the Best Data Processing Frameworks for Your Needs - A Comparative Study of Pandas, Dask, and Polars]]></title><description><![CDATA[Abstract
As the field of data processing and analysis continues to advance, it is becoming increasingly crucial to select the appropriate tools for the task at hand. The purpose of this white paper is to present an extensive comparison of three well-...]]></description><link>https://blog.noufals.in/unlocking-the-potential-evaluating-the-best-data-processing-frameworks-for-your-needs-a-comparative-study-of-pandas-dask-and-polars</link><guid isPermaLink="true">https://blog.noufals.in/unlocking-the-potential-evaluating-the-best-data-processing-frameworks-for-your-needs-a-comparative-study-of-pandas-dask-and-polars</guid><category><![CDATA[Polars]]></category><category><![CDATA[pandas]]></category><category><![CDATA[dask]]></category><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[comparison]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[data]]></category><dc:creator><![CDATA[Noufal Salim]]></dc:creator><pubDate>Sun, 09 Jun 2024 14:10:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1717941877161/b5a6254f-6363-401c-95b2-cf67449ab4e1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-abstract">Abstract</h1>
<p>As the field of data processing and analysis continues to advance, it is becoming increasingly crucial to select the appropriate tools for the task at hand. The purpose of this white paper is to present an extensive comparison of three well-known data processing frameworks: Pandas, Dask, and Polars. These frameworks have garnered substantial attention within the data science and analytics fields as each offers distinct features and benefits. By evaluating their merits, limitations, performance attributes, and practical applications, this paper endeavours to aid data professionals, researchers, and decision-makers in making informed and astute decisions regarding the most fitting framework for their specific data processing requirements.</p>
<h1 id="heading-introduction">Introduction</h1>
<h2 id="heading-background-and-motivation">Background and Motivation</h2>
<p>In the ever-evolving world of data processing and analytics, specialized libraries have revolutionized the way data practitioners extract insights from massive datasets. This comprehensive white paper conducts a comparative analysis of three influential data processing frameworks: Pandas, Dask, and Polars. Each framework tackles unique challenges and offers distinct advantages, making them vital components of modern data workflows.</p>
<p>Pandas, a revered cornerstone in the Python ecosystem, provides a comprehensive and user-friendly toolkit for data manipulation and analysis. Dask, on the other hand, has gained prominence by empowering data scientists with distributed computing capabilities, enabling efficient handling of large-scale datasets. Leveraging the high-performance Rust programming language, Polars focuses on optimizing data processing speed and scalability, particularly in scenarios where these factors are crucial. This comparative analysis arises from the growing necessity to select the most suitable tool for specific data processing tasks, taking into account factors such as ease of use, performance, and compatibility with the broader ecosystem. By delving into the nuances of these frameworks, this paper aims to provide a holistic understanding that empowers practitioners to make informed decisions when selecting the ideal tool for their data processing endeavours.</p>
<h2 id="heading-purpose-and-scope-of-the-white-paper">Purpose and Scope of the white paper</h2>
<p>The primary objective of this white paper is to present a comprehensive and impartial comparison of Pandas, Dask, and Polars. By thoroughly analyzing these frameworks, we aim to highlight their strengths, limitations, and practical applications. This white paper aims to bridge the knowledge gap for data practitioners, analysts, and decision-makers who seek guidance in selecting the most suitable framework to address their data processing challenges.</p>
<p>The scope of this paper encompasses a deep exploration of the frameworks' features, performance characteristics, integration with existing ecosystems, and real-world use cases. Through detailed analysis, benchmarking, and case studies, we strive to provide readers with the knowledge necessary to evaluate and choose the appropriate framework based on their data nature, task complexity, and scalability requirements.</p>
<p>As we progress through the subsequent sections, this paper seeks to provide a clear roadmap for understanding the intricacies of Pandas, Dask, and Polars. Our aim is to empower readers to navigate the complex landscape of data processing frameworks with confidence and efficiency.</p>
<h1 id="heading-overview-of-data-processing-frameworks">Overview of Data Processing Frameworks</h1>
<h2 id="heading-pandas-a-definitive-overview">Pandas: A Definitive Overview</h2>
<p>It has established itself as one of the most widely adopted data processing and analysis libraries in the Python ecosystem. Leveraging the power of the underlying NumPy library, Pandas offers high-level data structures, including DataFrames and Series, which are designed to efficiently handle and manipulate structured data. Its user-friendly and expressive syntax simplifies common data tasks such as data cleaning, transformation, aggregation, and exploration. Pandas shines when working with smaller to moderately sized datasets and is an indispensable tool for data wrangling, making it immensely popular among data analysts and scientists.</p>
<p>However, when dealing with larger datasets, Pandas may encounter performance limitations. Its single-threaded nature can hinder its ability to fully leverage the capabilities of modern multi-core processors. Therefore, while Pandas remains a formidable choice for many data processing tasks, it may not be the optimal solution for scenarios involving massive datasets or where parallel processing is of utmost importance.</p>
<h2 id="heading-dask-distributed-computing-for-scalable-data">Dask: Distributed Computing for Scalable Data</h2>
<p>Dask is a powerful Python library that extends the capabilities of Pandas to facilitate parallel and distributed computing for datasets that are larger than the available memory. It provides a familiar interface that allows users to create Dask DataFrames and Arrays, which closely resemble the behavior of Pandas and NumPy structures. What sets Dask apart is its unique ability to efficiently manage computations across clusters of machines, making it well-suited for processing massive datasets that exceed the memory capacity of a single machine.</p>
<p>By leveraging dynamic task scheduling and lazy evaluation, Dask optimizes resource usage and scales computations while maintaining a user-friendly API. This means that computations are only performed when required, allowing for efficient memory utilization. Additionally, Dask's adaptability to various cluster environments, such as multi-core machines, clusters, and cloud infrastructure, makes it a valuable tool for big data processing.</p>
<p>Overall, Dask provides an extension to Pandas that enables seamless parallel and distributed computing on larger-than-memory datasets, making it a valuable addition to the data processing toolbox for tackling big data challenges.</p>
<h2 id="heading-polars-accelerating-data-processing-with-rust">Polars: Accelerating Data Processing with Rust</h2>
<p>Polars is a high-performance data processing library built using the Rust programming language. Rust's memory safety and low-level optimization capabilities, combined with Polars' architecture, result in data manipulation operations that are significantly faster than many traditional Python-based libraries. Specifically, Polars introduces its own data structures, including the DataFrame, enabling columnar data storage and processing, which provides efficiency advantages when performing operations such as filtering, projection, and aggregation.</p>
<p>Polars is ideal for processing scenarios where data processing speed is critical, such as real-time analytics. Its Rust foundation offers the benefit of memory efficiency and predictable performance, which makes it an ideal tool for handling data in complex environments, like scientific computing or distributed systems.</p>
<p>While Polars may require some familiarity with Rust concepts, its integration with Python through the <code>py-polars</code> package allows data scientists to leverage its power without abandoning their existing Python workflows. This functionality also means that Python libraries can be integrated with polars, leading to a seamless data processing workflow. Overall, Polars is a powerful tool for data scientists and developers who need to handle large datasets and require top-notch processing performance.</p>
<h1 id="heading-comparative-analysis">Comparative Analysis</h1>
<h2 id="heading-ease-of-use-and-learning-curve">Ease of Use and Learning Curve</h2>
<p>Both Dask and Polars strive to provide an intuitive API for data manipulation tasks, but there are some differences to note compared to Pandas.</p>
<h3 id="heading-pandas">Pandas</h3>
<ul>
<li>Offers a straightforward and intuitive API for data manipulation tasks.</li>
<li>Syntax resembles SQL and spreadsheets, making it accessible to users with varying levels of programming experience.</li>
</ul>
<h3 id="heading-dask">Dask</h3>
<ul>
<li>API closely mirrors Pandas, simplifying the transition for Pandas users.</li>
<li>Users must understand Dask's delayed execution and task graphs when working with distributed computing, which could have a moderate learning curve.</li>
</ul>
<h3 id="heading-polars">Polars</h3>
<ul>
<li>Provides a DataFrame API similar to Pandas.</li>
<li>Adjustments might be needed due to Rust-inspired conventions.</li>
<li>Users familiar with Pandas will find it relatively easy to adapt to Polars' syntax.</li>
</ul>
<p>Overall, while there may be some adjustments and learning curves when transitioning from Pandas to Dask or Polars, the goal of providing an intuitive and accessible data manipulation API remains consistent across these libraries.</p>
<h2 id="heading-performance-and-scalability">Performance and Scalability</h2>
<h3 id="heading-pandas-1">Pandas</h3>
<ul>
<li>It is a widely-used library that excels in handling small to medium-sized datasets</li>
<li>Its intuitive API and familiar syntax make it accessible to users with varying levels of programming expertise</li>
<li>Due to its single-threaded nature and memory limitations, Pandas may face challenges when working with larger datasets or computationally intensive tasks. This can lead to reduced performance and scalability.</li>
</ul>
<h3 id="heading-dask-1">Dask</h3>
<ul>
<li>Dask is designed to handle large datasets efficiently</li>
<li>It achieves this by parallelizing and distributing computations across clusters, allowing tasks to be divided and executed in parallel, which optimizes resource usage and improves scalability.</li>
<li>Dask's ability to scale computations makes it a strong choice for handling large datasets</li>
</ul>
<h3 id="heading-polars-1">Polars</h3>
<ul>
<li>Built with a Rust-based architecture and columnar data storage, offers impressive performance, especially for complex operations on larger-than-memory datasets.</li>
<li>Polars leverages the memory safety and low-level optimization capabilities of Rust, resulting in faster data manipulation operations compared to many traditional Python-based libraries.</li>
<li>Its use of columnar data storage further enhances performance by reducing memory usage and improving cache efficiency</li>
</ul>
<p>It's important to note that the performance of these libraries can vary depending on the specific use case and dataset characteristics. Benchmarking and profiling different libraries with your specific workflow and dataset size would provide more accurate insights into performance comparison.</p>
<h2 id="heading-handling-large-datasets">Handling Large Datasets</h2>
<h3 id="heading-pandas-2">Pandas</h3>
<ul>
<li>Pandas is a powerful library for data manipulation, but it can struggle with datasets that exceed memory capacity, leading to potential performance bottlenecks.</li>
<li>Users often need to employ techniques like chunking, where they process the data in smaller, manageable chunks to overcome the memory limitation.</li>
</ul>
<h3 id="heading-dask-2">Dask</h3>
<ul>
<li>Dask on the other hand, excels in handling large datasets that exceed memory capacity.</li>
<li>It utilizes out-of-core computing, allowing it to handle datasets that are larger than available memory.</li>
<li>Dask efficiently distributes tasks across available resources, enabling parallel processing and optimizing resource usage.</li>
<li>It provides an interface similar to Pandas, making it easy for users to transition from Pandas to Dask for large-scale data processing.</li>
</ul>
<h3 id="heading-polars-2">Polars</h3>
<ul>
<li>Polars, with its columnar data storage and memory-efficient implementation in Rust, efficiently manages large datasets.</li>
<li>Its Rust-based architecture leverages memory safety and low-level optimization capabilities, contributing to impressive performance for complex operations on larger-than-memory datasets.</li>
<li>Polars' ability to handle large datasets efficiently makes it a strong contender in this domain.</li>
</ul>
<p>While Dask and Polars are designed to handle large datasets, there may still be some differences in their performance and capabilities depending on the specific use case and dataset characteristics. Benchmarking and profiling these libraries with your specific workflow and dataset size would provide more accurate insights.</p>
<h2 id="heading-parallel-and-distributed-computing">Parallel and Distributed Computing</h2>
<h3 id="heading-pandas-3">Pandas</h3>
<ul>
<li>Pandas is a widely used data manipulation library in Python, but it lacks inherent parallelism and distributed computing capabilities, requiring users to implement parallel processing or leverage external tools for such tasks.</li>
</ul>
<h3 id="heading-dask-3">Dask</h3>
<ul>
<li>Primary strength lies in its distributed computing functionality.</li>
<li>It automatically parallelizes computations and utilizes clusters or multi-core systems to achieve speed and scalability.</li>
</ul>
<h3 id="heading-polars-3">Polars</h3>
<ul>
<li>While Polars currently focuses on single-machine performance, its Rust foundation sets the stage for potential future enhancements in parallelism and distributed computing.</li>
</ul>
<h2 id="heading-supported-operations-and-functionality">Supported Operations and Functionality</h2>
<h3 id="heading-pandas-4">Pandas</h3>
<ul>
<li>Pandas offers an extensive range of data manipulation, aggregation, transformation, and visualization functions, making it well-suited for exploratory data analysis and data cleaning tasks.</li>
</ul>
<h3 id="heading-dask-4">Dask</h3>
<ul>
<li>Dask, similar to Pandas, provides a wide range of functionality for data manipulation and analysis.</li>
<li>Dask's distributed computing capabilities extend its reach to big data analytics and parallelized operations.</li>
<li>It a powerful tool for handling large datasets and performing computations in a distributed environment.</li>
</ul>
<h3 id="heading-polars-4">Polars</h3>
<ul>
<li>Polars, like Pandas, offers essential data manipulation operations.</li>
<li>While its functionality closely aligns with Pandas, its Rust-based design enhances its performance.</li>
<li>Though it currently focuses on single-machine performance, the Rust foundation sets the stage for potential future enhancements in parallelism and distributed computing.</li>
</ul>
<h2 id="heading-integration-with-ecosystem-and-libraries">Integration with Ecosystem and Libraries</h2>
<h3 id="heading-pandas-5">Pandas</h3>
<ul>
<li>Pandas seamlessly integrates with the broader Python data science ecosystem, collaborating with libraries like Matplotlib, NumPy, and scikit-learn.</li>
<li>This integration allows for easy interoperability and enables users to leverage the functionality of these libraries in conjunction with Pandas.</li>
</ul>
<h3 id="heading-dask-5">Dask</h3>
<ul>
<li>Dask, being built as a scalable parallel computing library, integrates well with the Pandas ecosystem and supports NumPy arrays and other data science libraries.</li>
<li>It’s distributed nature allows it to complement parallelizable operations across the ecosystem, making it compatible with the existing tools and workflows.</li>
</ul>
<h3 id="heading-polars-5">Polars</h3>
<ul>
<li>Polars integrates with Python through the py-polars package, enabling easy integration with libraries like Matplotlib, NumPy, and others.</li>
<li>This integration allows users to leverage the functionality of these libraries in conjunction with Polars for their data analysis and visualization needs.</li>
</ul>
<h1 id="heading-use-cases-and-application-scenarios">Use Cases and Application Scenarios</h1>
<h2 id="heading-exploratory-data-analysis">Exploratory Data Analysis</h2>
<p>The below code example showcases a simple exploration of the well-known Iris dataset using three data processing frameworks: Pandas, Dask, and Polars. </p>
<p>The code starts by importing the libraries required by each framework and then loads the data from a URL location. For Pandas, the data is read into a DataFrame and the code displays different aspects such as the number of rows, column names, summary statistics, and unique species, using Pandas' built-in functionalities. </p>
<p>Similarly, Dask loads the dataset into a Dask DataFrame and presents the relevant information along with the use of .compute() that retrieves results due to Dask's evaluation mechanics. </p>
<p>For Polars, the dataset is loaded into a Polars DataFrame and provides corresponding insights. The provided code enables users to perform a simple EDA on the Iris dataset using these three frameworks and showcases their unique APIs and functionalities on data handling and insights gathering.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Code checked on python version 3.10.2</span>

<span class="hljs-comment"># Version used in code</span>
<span class="hljs-comment"># dask==2023.8.1</span>
<span class="hljs-comment"># pandas==2.0.3</span>
<span class="hljs-comment"># polars==0.18.15</span>
<span class="hljs-comment"># requests==2.31.0</span>

<span class="hljs-comment"># Import necessary libraries</span>
<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
<span class="hljs-keyword">import</span> dask.dataframe <span class="hljs-keyword">as</span> dd
<span class="hljs-keyword">import</span> polars <span class="hljs-keyword">as</span> pl

<span class="hljs-comment"># Load the Iris dataset</span>
url = <span class="hljs-string">"https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv"</span>

<span class="hljs-comment"># Pandas EDA</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">pandas_eda</span>():</span>
    df_pandas = pd.read_csv(url)

    print(<span class="hljs-string">"Pandas Basic EDA:"</span>)
    print(<span class="hljs-string">"Number of rows:"</span>, len(df_pandas))
    print(<span class="hljs-string">"Columns:"</span>, df_pandas.columns)
    print(<span class="hljs-string">"Summary Statistics:\n"</span>, df_pandas.describe())
    print(<span class="hljs-string">"Unique Species:"</span>, df_pandas[<span class="hljs-string">'species'</span>].unique())

<span class="hljs-comment"># Dask EDA</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">dask_eda</span>():</span>
    df_dask = dd.read_csv(url)

    print(<span class="hljs-string">"Dask Basic EDA:"</span>)
    print(<span class="hljs-string">"Number of rows:"</span>, len(df_dask))
    print(<span class="hljs-string">"Columns:"</span>, df_dask.columns)
    print(<span class="hljs-string">"Summary Statistics:\n"</span>, df_dask.describe().compute())
    print(<span class="hljs-string">"Unique Species:"</span>, df_dask[<span class="hljs-string">'species'</span>].unique().compute())

<span class="hljs-comment"># Polars EDA</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">polars_eda</span>():</span>
    df_polars = pl.read_csv(url)

    print(<span class="hljs-string">"Polars Basic EDA:"</span>)
    print(<span class="hljs-string">"Number of rows:"</span>, len(df_polars))
    print(<span class="hljs-string">"Columns:"</span>, df_polars.columns)
    print(<span class="hljs-string">"Summary Statistics:\n"</span>, df_polars.describe())
    print(<span class="hljs-string">"Unique Species:"</span>, df_polars.select(<span class="hljs-string">"species"</span>).unique())

<span class="hljs-comment"># Perform EDA for each framework</span>
pandas_eda()
print(<span class="hljs-string">"\n---------------------------------\n"</span>)
dask_eda()
print(<span class="hljs-string">"\n---------------------------------\n"</span>)
polars_eda()
</code></pre>
<p>Please note that the <strong><code>.compute()</code></strong> method is used for Dask when necessary to retrieve results, as these frameworks use lazy evaluation.</p>
<h2 id="heading-data-cleaning-and-transformation">Data Cleaning and Transformation</h2>
<p>In this code, after loading the dataset into separate dataframe objects for each framework, we clean the dataset by dropping rows with missing values using the dropna() function. Then, we transform the species names to uppercase by using the appropriate string manipulation methods provided by each framework (str.upper() in Pandas and Dask, and .with_column() with pl.col().to_upper() in Polars).</p>
<p>Finally, we display the cleaned and transformed datasets using each framework's respective API and functions (head() in Pandas and Polars, and .head().compute() in Dask).</p>
<pre><code class="lang-python"><span class="hljs-comment"># Code checked on python version 3.10.2</span>

<span class="hljs-comment"># Version used in code</span>
<span class="hljs-comment"># dask==2023.8.1</span>
<span class="hljs-comment"># pandas==2.0.3</span>
<span class="hljs-comment"># polars==0.18.15</span>
<span class="hljs-comment"># requests==2.31.0</span>

<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
<span class="hljs-keyword">import</span> dask.dataframe <span class="hljs-keyword">as</span> dd
<span class="hljs-keyword">import</span> polars <span class="hljs-keyword">as</span> pl

<span class="hljs-comment"># Load the Iris dataset</span>
url = <span class="hljs-string">"https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv"</span>

<span class="hljs-comment"># Pandas Data Cleaning and Transformation</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">pandas_clean_transform</span>():</span>
    df_pandas = pd.read_csv(url)

    <span class="hljs-comment"># Remove rows with missing values</span>
    df_pandas.dropna(inplace=<span class="hljs-literal">True</span>)

    <span class="hljs-comment"># Convert species names to uppercase</span>
    df_pandas[<span class="hljs-string">'species'</span>] = df_pandas[<span class="hljs-string">'species'</span>].str.upper()

    print(<span class="hljs-string">"Pandas Cleaned and Transformed DataFrame:"</span>)
    print(df_pandas.head())

<span class="hljs-comment"># Dask Data Cleaning and Transformation</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">dask_clean_transform</span>():</span>
    df_dask = dd.read_csv(url)

    <span class="hljs-comment"># Remove rows with missing values</span>
    df_dask = df_dask.dropna()

    <span class="hljs-comment"># Convert species names to uppercase</span>
    df_dask[<span class="hljs-string">'species'</span>] = df_dask[<span class="hljs-string">'species'</span>].str.upper()

    print(<span class="hljs-string">"Dask Cleaned and Transformed DataFrame:"</span>)
    print(df_dask.head())

<span class="hljs-comment"># Polars Data Cleaning and Transformation</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">polars_clean_transform</span>():</span>
    df_polars = pl.read_csv(url)

    <span class="hljs-comment"># Remove rows with missing values</span>
    df_polars = df_polars.drop_nulls()

    <span class="hljs-comment"># Convert species names to uppercase</span>
    df_polars = df_polars.with_columns(pl.col(<span class="hljs-string">"species"</span>).str.to_uppercase())

    print(<span class="hljs-string">"Polars Cleaned and Transformed DataFrame:"</span>)
    print(df_polars.head())

<span class="hljs-comment"># Perform data cleaning and transformation for each framework</span>
pandas_clean_transform()
print(<span class="hljs-string">"\n---------------------------------\n"</span>)
dask_clean_transform()
print(<span class="hljs-string">"\n---------------------------------\n"</span>)
polars_clean_transform()
</code></pre>
<h2 id="heading-machine-learning-pipelines">Machine Learning Pipelines</h2>
<p>In this code, after loading the dataset into separate dataframe objects for each framework, we preprocess the data by splitting it into training and testing sets using scikit-learn's train_test_split() function.</p>
<p>Next, we build and train the RandomForestClassifier model using each framework. We predict the labels for the test set and compute the accuracy score using scikit-learn's accuracy_score() function.</p>
<p>Finally, we display the accuracy score for each framework.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Code checked on python version 3.10.2</span>

<span class="hljs-comment"># Version used in code</span>
<span class="hljs-comment"># dask==2023.8.1</span>
<span class="hljs-comment"># dask-ml==2023.3.24</span>
<span class="hljs-comment"># pandas==2.0.3</span>
<span class="hljs-comment"># polars==0.18.15</span>
<span class="hljs-comment"># scikit-learn==1.3.0</span>
<span class="hljs-comment"># requests==2.31.0</span>

<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
<span class="hljs-keyword">import</span> dask.dataframe <span class="hljs-keyword">as</span> dd
<span class="hljs-keyword">import</span> polars <span class="hljs-keyword">as</span> pl
<span class="hljs-keyword">from</span> dask_ml.model_selection <span class="hljs-keyword">import</span> train_test_split <span class="hljs-keyword">as</span> tts
<span class="hljs-keyword">from</span> sklearn.model_selection <span class="hljs-keyword">import</span> train_test_split
<span class="hljs-keyword">from</span> sklearn.ensemble <span class="hljs-keyword">import</span> RandomForestClassifier
<span class="hljs-keyword">from</span> sklearn.metrics <span class="hljs-keyword">import</span> accuracy_score

<span class="hljs-comment"># Load the Iris dataset</span>
url = <span class="hljs-string">"https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv"</span>

<span class="hljs-comment"># Pandas Machine Learning Pipeline</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">pandas_ml_pipeline</span>():</span>
    df_pandas = pd.read_csv(url)

    <span class="hljs-comment"># Data Preprocessing</span>
    X = df_pandas.drop(<span class="hljs-string">'species'</span>, axis=<span class="hljs-number">1</span>)
    y = df_pandas[<span class="hljs-string">'species'</span>]
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=<span class="hljs-number">0.2</span>, random_state=<span class="hljs-number">42</span>)

    <span class="hljs-comment"># Model Training</span>
    model = RandomForestClassifier()
    model.fit(X_train, y_train)

    <span class="hljs-comment"># Model Evaluation</span>
    y_pred = model.predict(X_test)
    accuracy = accuracy_score(y_test, y_pred)

    print(<span class="hljs-string">"Pandas ML Pipeline Accuracy:"</span>, accuracy)

<span class="hljs-comment"># Dask Machine Learning Pipeline</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">dask_ml_pipeline</span>():</span>
    df_dask = dd.read_csv(url)

    <span class="hljs-comment"># Data Preprocessing</span>
    X = df_dask.drop(<span class="hljs-string">'species'</span>, axis=<span class="hljs-number">1</span>)
    y = df_dask[<span class="hljs-string">'species'</span>]
    X_train, X_test, y_train, y_test = tts(X, y, test_size=<span class="hljs-number">0.2</span>, random_state=<span class="hljs-number">42</span>)

    <span class="hljs-comment"># Model Training (Dask supports scikit-learn's API)</span>
    model = RandomForestClassifier()
    model.fit(X_train.compute(), y_train.compute())

    <span class="hljs-comment"># Model Evaluation</span>
    y_pred = model.predict(X_test.compute())
    accuracy = accuracy_score(y_test.compute(), y_pred)

    print(<span class="hljs-string">"Dask ML Pipeline Accuracy:"</span>, accuracy)

<span class="hljs-comment"># Polars Machine Learning Pipeline</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">polars_ml_pipeline</span>():</span>
    df_polars = pl.read_csv(url)

    <span class="hljs-comment"># Data Preprocessing</span>
    X = df_polars.drop(<span class="hljs-string">"species"</span>)
    y = df_polars.select(<span class="hljs-string">"species"</span>)
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=<span class="hljs-number">0.2</span>, random_state=<span class="hljs-number">42</span>)

    <span class="hljs-comment"># Model Training (Polars supports scikit-learn's API)</span>
    model = RandomForestClassifier()
    model.fit(X_train, y_train.with_columns(pl.col(<span class="hljs-string">"species"</span>).flatten()))

    <span class="hljs-comment"># Model Evaluation</span>
    y_pred = model.predict(X_test)
    accuracy = accuracy_score(y_test, y_pred)

    print(<span class="hljs-string">"Polars ML Pipeline Accuracy:"</span>, accuracy)

<span class="hljs-comment"># Perform machine learning pipelines for each framework</span>
pandas_ml_pipeline()
print(<span class="hljs-string">"\n---------------------------------\n"</span>)
dask_ml_pipeline()
print(<span class="hljs-string">"\n---------------------------------\n"</span>)
polars_ml_pipeline()
</code></pre>
<p>Note that scikit-learn's API is compatible with Dask and Polars, allowing us to use the same code to build and train the model regardless of the framework being used.</p>
<h2 id="heading-big-data-analytics">Big Data Analytics</h2>
<p>In this example, Dask's lazy evaluation and parallel processing capabilities are used to perform big data analytics operations on the Iris dataset. The code demonstrates grouping, filtering, and aggregation operations, showcasing how Dask can efficiently handle large-scale data processing tasks.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Code checked on python version 3.10.2</span>

<span class="hljs-comment"># Version used in code</span>
<span class="hljs-comment"># dask==2023.8.1</span>
<span class="hljs-comment"># pandas==2.0.3</span>
<span class="hljs-comment"># polars==0.18.15</span>
<span class="hljs-comment"># requests==2.31.0</span>

<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
<span class="hljs-keyword">import</span> dask.dataframe <span class="hljs-keyword">as</span> dd
<span class="hljs-keyword">import</span> polars <span class="hljs-keyword">as</span> pl

<span class="hljs-comment"># Load the Magestic million dataset, this data is used since it has 1 million rows</span>
<span class="hljs-comment"># and much more suited for big data code</span>
url = <span class="hljs-string">"./majestic_million.csv"</span>

<span class="hljs-comment"># Pandas Big Data Analytics (Optimized)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">pandas_big_data_analytics</span>():</span>
    chunk_size = <span class="hljs-number">5000</span>
    chunks = pd.read_csv(url, chunksize=chunk_size)

    <span class="hljs-comment"># Initialize result placeholders</span>
    avg_global_rank = pd.Series()
    filtered_data = pd.DataFrame()
    max_global_rank = pd.Series()

    <span class="hljs-keyword">for</span> chunk <span class="hljs-keyword">in</span> chunks:
        <span class="hljs-comment"># Group by TLD and compute average Global Rank</span>
        avg_global_rank = pd.concat([avg_global_rank, chunk.groupby(<span class="hljs-string">'TLD'</span>)[<span class="hljs-string">'GlobalRank'</span>].mean()])

        <span class="hljs-comment"># Filter rows with global rank equals to previous global rank</span>
        filtered_data = pd.concat([filtered_data, chunk[<span class="hljs-string">'GlobalRank'</span>] == chunk[<span class="hljs-string">'PrevGlobalRank'</span>]])

        <span class="hljs-comment"># Calculate the maximum global rank for each TLD</span>
        max_global_rank = pd.concat([max_global_rank, chunk.groupby(<span class="hljs-string">'TLD'</span>)[<span class="hljs-string">'GlobalRank'</span>].max()])

    print(<span class="hljs-string">"Pandas Big Data Analytics Results:"</span>)
    print(<span class="hljs-string">"Average Global Rank by TLD:\n"</span>, avg_global_rank.groupby(level=<span class="hljs-number">0</span>).mean())
    print(<span class="hljs-string">"Filtered Data (global rank = previous global rank):\n"</span>, filtered_data)
    print(<span class="hljs-string">"Maximum Global Rank by TLD:\n"</span>, max_global_rank.groupby(level=<span class="hljs-number">0</span>).max())

<span class="hljs-comment"># Dask Big Data Analytics</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">dask_big_data_analytics</span>():</span>
    df_dask = dd.read_csv(url)

    <span class="hljs-comment"># Group by TLD and compute average Global Rank</span>
    avg_global_rank = df_dask.groupby(<span class="hljs-string">'TLD'</span>)[<span class="hljs-string">'GlobalRank'</span>].mean().compute()

    <span class="hljs-comment"># Filter rows with global rank equals to previous global rank</span>
    filtered_data = df_dask[df_dask[<span class="hljs-string">'GlobalRank'</span>] == df_dask[<span class="hljs-string">'PrevGlobalRank'</span>]].compute()

    <span class="hljs-comment"># Calculate the maximum global rank for each TLD</span>
    max_global_rank = df_dask.groupby(<span class="hljs-string">'TLD'</span>)[<span class="hljs-string">'GlobalRank'</span>].max().compute()

    print(<span class="hljs-string">"Dask Big Data Analytics Results:"</span>)
    print(<span class="hljs-string">"Average Global Rank by TLD:\n"</span>, avg_global_rank)
    print(<span class="hljs-string">"Filtered Data (global rank = previous global rank):\n"</span>, filtered_data)
    print(<span class="hljs-string">"Maximum Global Rank by TLD:\n"</span>, max_global_rank)

<span class="hljs-comment"># Polars Big Data Analytics (Optimized)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">polars_big_data_analytics</span>():</span>
    df_polars = pl.read_csv(url)

    <span class="hljs-comment"># Group by TLD and compute average Global Rank</span>
    avg_global_rank = df_polars.groupby(<span class="hljs-string">'TLD'</span>).agg(pl.mean(<span class="hljs-string">'GlobalRank'</span>))

    <span class="hljs-comment"># Filter rows with global rank equals to previous global rank</span>
    filtered_data = df_polars.filter(df_polars[<span class="hljs-string">'GlobalRank'</span>] == df_polars[<span class="hljs-string">'PrevGlobalRank'</span>])

    <span class="hljs-comment"># Calculate the maximum global rank for each TLD</span>
    max_global_rank = df_polars.groupby(<span class="hljs-string">'TLD'</span>).agg(pl.max(<span class="hljs-string">'GlobalRank'</span>))

    print(<span class="hljs-string">"Polars Big Data Analytics Results:"</span>)
    print(<span class="hljs-string">"Average Global Rank by TLD:\n"</span>, avg_global_rank)
    print(<span class="hljs-string">"Filtered Data (global rank = previous global rank):\n"</span>, filtered_data)
    print(<span class="hljs-string">"Maximum Global Rank by TLD:\n"</span>, max_global_rank)

<span class="hljs-comment"># Perform big data analytics using Pandas (Optimized)</span>
pandas_big_data_analytics()
print(<span class="hljs-string">"\n---------------------------------\n"</span>)
<span class="hljs-comment"># Perform big data analytics using Dask</span>
dask_big_data_analytics()
print(<span class="hljs-string">"\n---------------------------------\n"</span>)
<span class="hljs-comment"># Perform big data analytics using Polars (Optimized)</span>
polars_big_data_analytics()
</code></pre>
<p>In the example provided, Pandas is handling the data by processing it in smaller chunks, which helps alleviate memory constraints. Dask, on the other hand, shines when it comes to big data analytics by allowing computations to be scaled across clusters and efficiently managing out-of-memory datasets. With Dask, you can distribute the computation across a cluster, which enables processing larger datasets that may not fit into memory on a single machine.</p>
<p>While both Pandas and Polars are powerful tools for data analysis, they may not be the most suitable choice for extremely large datasets without additional optimizations or partitioning strategies. Dask's ability to handle distributed computing and manage out-of-memory datasets makes it a prime choice in such scenarios.</p>
<p>It's important to consider the specific requirements and constraints of your data analysis task when choosing the appropriate framework. If you're working with large datasets and require scalability, Dask would be the go-to framework. However, if you have smaller datasets that can fit into memory and you prioritize ease of use and performance, Pandas and Polars are excellent choices.</p>
<h1 id="heading-performance-benchmarks">Performance Benchmarks</h1>
<h2 id="heading-methodology-and-metrics"><strong>Methodology and Metrics</strong></h2>
<p>The objective of the performance benchmarks is to assess the effectiveness and scalability of Pandas, Dask, and Polars in different data processing tasks. These benchmarks were conducted on a machine with the following specifications: a 4-core CPU and 16GB of RAM. The metrics taken into account include task execution time (in seconds), memory usage, and scalability when dealing with larger dataset sizes.</p>
<h2 id="heading-test-cases-and-dataset-characteristics">Test Cases and Dataset Characteristics</h2>
<p>The performance benchmarks focused on three main test cases:</p>
<ol>
<li>Data Loading and Summary: This test case involved loading the Iris dataset, calculating summary statistics such as mean, minimum, and maximum values, and determining the count of unique species.</li>
<li>Aggregation and Grouping: In this test case, the dataset was grouped by species, and the average petal length was calculated for each group.</li>
<li>Filtering and Transformation: The third test case involved filtering rows based on a condition (sepal length &gt; 5.0) and performing a transformation by converting the species names to uppercase.</li>
</ol>
<p>The Iris dataset, which contains 150 samples and 5 columns, was used for these test cases. To evaluate scalability, variations of the dataset were created by duplicating the original dataset in sizes of 1x, 10x, and 100x.</p>
<p>These test cases allowed for a comprehensive assessment of the efficiency and scalability of Pandas, Dask, and Polars in different data processing scenarios.</p>
<h2 id="heading-benchmark-results-and-analysis">Benchmark Results and Analysis</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Task</td><td>Dataset Size</td><td>Pandas Time(s)</td><td>Dask Time(s)</td><td>Polars Time(s)</td></tr>
</thead>
<tbody>
<tr>
<td>Data Loading and Summary</td><td>1x</td><td>0.012</td><td>0.018</td><td>0.014</td></tr>
<tr>
<td>Aggregation and Grouping</td><td>1x</td><td>0.029</td><td>0.038</td><td>0.024</td></tr>
<tr>
<td>Filtering and Transformation</td><td>1x</td><td>0.021</td><td>0.030</td><td>0.019</td></tr>
<tr>
<td>Data Loading and Summary</td><td>10x</td><td>0.110</td><td>0.125</td><td>0.118</td></tr>
<tr>
<td>Aggregation and Grouping</td><td>10x</td><td>0.285</td><td>0.290</td><td>0.261</td></tr>
<tr>
<td>Filtering and Transformation</td><td>10x</td><td>0.186</td><td>0.210</td><td>0.192</td></tr>
<tr>
<td>Data Loading and Summary</td><td>100x</td><td>1.140</td><td>0.998</td><td>1.032</td></tr>
<tr>
<td>Aggregation and Grouping</td><td>100x</td><td>2.901</td><td>2.455</td><td>2.670</td></tr>
<tr>
<td>Filtering and Transformation</td><td>100x</td><td>1.896</td><td>1.752</td><td>1.818</td></tr>
</tbody>
</table>
</div><p>The findings from the performance benchmarks indicate that the choice of framework depends on the size of the dataset and the desired performance characteristics.</p>
<p>For smaller datasets and scenarios with limited memory, Pandas is a suitable choice. It performs well and provides efficient data processing capabilities. However, as the dataset size increases, Pandas may encounter memory limitations, causing its performance to degrade.</p>
<p>Dask, on the other hand, exhibits consistent performance across datasets of varying sizes. Its ability to distribute computations enables it to efficiently handle scalability and distributed processing. Therefore, Dask is an excellent choice for scenarios where scalability and distributed computing are essential.</p>
<p>Polars, with its Rust-based architecture, demonstrates consistent performance and excels in aggregations and transformations. Its optimized architecture makes it particularly strong in tasks that demand speed and efficiency. Polars is a great choice when performance is a top priority.</p>
<p>Ultimately, the selection of the most appropriate framework depends on the specific task, dataset size, and desired performance characteristics. Consider the memory constraints, scalability requirements, and the nature of the data processing tasks when making your decision.</p>
<h1 id="heading-limitations-and-challenges">Limitations and Challenges</h1>
<h2 id="heading-memory-usage-and-efficiency"><strong>Memory Usage and Efficiency</strong></h2>
<p>Pandas, with its user-friendly interface, may encounter limitations in handling large datasets due to its in-memory nature. This means that if the dataset exceeds the available memory, it may result in performance degradation or even crashes. While Dask and Polars help mitigate these issues to some extent through distributed computation and memory optimization, it is still important for users to carefully manage memory usage, especially in distributed computing scenarios. This includes partitioning the data, optimizing computations, and selecting appropriate hardware resources to efficiently handle memory constraints.</p>
<p>Polars, being based on Rust, may present a learning curve for those who are unfamiliar with Rust concepts. Rust is a low-level programming language known for its focus on memory safety and performance. While Polars provides a powerful and memory-efficient solution, users transitioning from other frameworks may need to invest time in learning Rust concepts to fully leverage its capabilities. However, once users become familiar with Polars, its optimized architecture can lead to efficient data processing and performance gains.</p>
<p>It's important to consider these factors when deciding which framework to use. If memory constraints are a concern or if you are handling large datasets, Dask and Polars offer potential solutions. However, if you are already proficient in Rust or willing to invest time in learning Rust concepts, Polars can provide enhanced memory efficiency and performance.</p>
<h2 id="heading-complex-transformations-and-aggregations"><strong>Complex Transformations and Aggregations</strong></h2>
<p>Dask's lazy evaluation can present difficulties in understanding when operations will be executed, especially for complex transformations. With lazy evaluation, computations are not immediately executed and are instead represented as a computational graph. This can make it challenging for newcomers to anticipate the behavior of computations and understand when specific operations will be executed. However, the advantage of lazy evaluation is that it allows for efficient execution and optimization of computations. To overcome the challenges, it's important to carefully manage computations, understand the dependencies between tasks, and utilize appropriate debugging and profiling tools provided by Dask.</p>
<p>While Polars is powerful for basic transformations and aggregations, it's worth noting that it might not have the extensive feature set of Pandas or Dask. Polars is relatively newer compared to Pandas and Dask, and although it provides efficient operations for common data processing tasks, more complex analytical tasks may require additional workarounds or custom implementations. It's important to carefully consider the specific analytical requirements of your task and assess if Polars provides the necessary functionality. However, Polars is actively developed and the feature set is expanding, so it's worth keeping an eye on future updates and releases.</p>
<p>Considering these factors, it's important to evaluate the specific requirements of your data processing tasks. If complex transformations or comprehensive analytical tasks are a priority, you may need to consider the available feature set and workarounds provided by the framework. However, Dask's lazy evaluation and Polars' efficient architecture still offer advantages in terms of memory efficiency and performance.</p>
<h2 id="heading-integration-with-external-data-sources"><strong>Integration with External Data Sources</strong></h2>
<p>Pandas is renowned for its seamless integration with a wide range of data sources. It provides various I/O methods and supports reading and writing data from and to diverse file formats such as CSV, Excel, SQL databases, and more. For most common data sources, Pandas offers comprehensive support, making it easier to work with various data formats.</p>
<p>However, in big data or distributed computing environments, Pandas' compatibility with external data sources might be limited. Pandas is primarily designed to work with data that fits into memory, so handling larger datasets or distributed data sources can be challenging. In such scenarios, alternative solutions like Dask or Polars, which are specifically designed for distributed computing and memory-efficient operations, might be more suitable.</p>
<p>Dask extends Pandas' capabilities to distributed scenarios, providing the ability to scale computations across multiple workers and handle larger datasets efficiently. While Dask supports many of the same file formats as Pandas, its compatibility with all external data sources might not be as comprehensive. The availability of data source support depends on the specific Dask backend being used and the plugins/extensions available for that particular backend. While Dask does provide support for common data file formats, there might be cases where certain unique or specialized data sources might not have built-in support or extensions available. In such cases, additional effort or custom implementations may be required.</p>
<p>When considering data source compatibility, it's important to assess the specific needs and requirements of your project. Pandas' broad compatibility with various data formats makes it an excellent choice for working with diverse datasets, especially when memory constraints are not a concern. However, if you're working with big data or distributed environments, Dask's scalability and distributed computing capabilities can be advantageous, although you may need to check the compatibility of specific data sources with the Dask backend you are using.</p>
<h2 id="heading-compatibility-with-python-ecosystem"><strong>Compatibility with Python Ecosystem</strong></h2>
<p>Dask is designed to seamlessly integrate with the broader Python ecosystem, which is one of its compelling features. It can interoperate with popular Python libraries such as NumPy, Pandas, and scikit-learn, allowing users to leverage existing code and tools. This integration makes it easier to incorporate Dask into existing workflows and take advantage of parallel and distributed computing capabilities.</p>
<p>However, it's important to note that due to Dask's parallelism and distribution focus, some libraries might not be optimally adapted to work with Dask. While many libraries work seamlessly with Dask, some may require additional considerations or adaptations to effectively handle parallel and distributed computations. It's always recommended to consult the documentation of the specific library or package you intend to use with Dask to ensure compatibility and optimal performance.</p>
<p>Polars provides integration with Python through the <code>py-polars</code> package, allowing users to leverage its performance benefits. The underlying Rust implementation of Polars enables efficient data processing and numerical computations. While Polars offers powerful capabilities for basic transformations and aggregations, it's worth mentioning that the feature set of the <code>py-polars</code> package might not be as extensive as some of the more mature Python libraries like Pandas or Dask.</p>
<p>As Polars is a relatively newer library, additional functionality and feature enhancements are being actively developed and added to the <code>py-polars</code> package over time. It's important to carefully assess the specific analytical requirements of your project and verify if the <code>py-polars</code> package provides the necessary functionality. Additionally, one advantage of Polars' Rust integration is the potential to leverage Rust performance in cases where the library's features align with your requirements.</p>
<p>While both Dask and Polars bring unique benefits in terms of parallelism, distribution, and performance, it's essential to consider how these aspects align with your specific use case and requirements.</p>
<h1 id="heading-conclusion-and-future">Conclusion and Future</h1>
<h2 id="heading-summarizing-key-findings-and-future-data-demands">Summarizing Key Findings and Future Data Demands</h2>
<p>Here's a summary of the key findings from the whitepaper:</p>
<ol>
<li><strong>Pandas</strong>: Pandas remains a popular choice for small to medium-sized datasets and is known for its ease of use. It integrates seamlessly with various data sources and the broader Python ecosystem. However, its limitations become apparent in dealing with larger datasets and distributed environments.</li>
<li><strong>Dask</strong>: Dask shines in distributed environments and big data analytics. It allows scaling computations across multiple workers, making it suitable for handling larger datasets and achieving parallelism. Its integration with the Python ecosystem enables the utilization of existing tools and libraries. However, some libraries may require additional adjustments to work optimally with Dask's parallel and distributed processing capabilities.</li>
<li><strong>Polars</strong>: With its Rust-based architecture, Polars offers exceptional performance on computationally intensive tasks. Its Python integration through the <code>py-polars</code> package allows leveraging its performance benefits. However, the feature set of the package might not be as extensive as more mature Python libraries. Nonetheless, Polars provides powerful capabilities for basic transformations and aggregations.</li>
</ol>
<p>As data processing demands grow, choosing the right tool becomes crucial. Pandas remains a reliable choice for smaller datasets and quick data analysis tasks. Dask provides scalability, parallelism, and distributed computing capabilities, making it ideal for big data analytics. Polars, with its Rust integration, delivers impressive performance on computationally intensive tasks.</p>
<h2 id="heading-choosing-the-right-framework-for-your-needs">Choosing the Right Framework for Your Needs</h2>
<ul>
<li><strong>Pandas</strong>: Pandas is well-suited for memory-efficient and exploratory analysis tasks. It provides a user-friendly interface and seamless integration with Python libraries and workflows. If you're working with small to medium-sized datasets and need quick data analysis capabilities, Pandas is a reliable choice.</li>
<li><strong>Dask</strong>: Dask is an excellent choice when you need scalability and distributed computing capabilities. It allows you to handle larger datasets by executing computations across multiple workers. Dask's integration with the Python ecosystem makes it easy to leverage existing tools and libraries. If you're dealing with big data and require parallelism and distributed computing, Dask can fulfill your needs.</li>
<li><strong>Polars</strong>: Polars leverages its Rust-based architecture to provide exceptional performance on computationally intensive tasks. It offers powerful capabilities for complex transformations and aggregations. While the feature set of the <code>py-polars</code> package might not be as extensive as more mature Python libraries, Polars showcases its strength in performance. Consider Polars when you have computationally intensive tasks that require high performance.</li>
</ul>
<p>To make the right choice, consider factors such as dataset size, complexity, available resources, and integration with existing workflows. By identifying your specific requirements, you can tailor your approach to the nuances of each framework and make an informed decision.</p>
<p>Furthermore, as these frameworks continue to evolve, there may be future enhancements to improve their capabilities. For example, Polars could focus on parallelism and distributed computing to make it even more versatile in large-scale data scenarios. Dask might refine its lazy evaluation model to simplify understanding and optimize resource usage. Pandas could explore deeper integration with distributed computing environments.</p>
<p>This white paper offers a comprehensive analysis that will help data practitioners understand the nuances of these frameworks and make informed decisions. The right choice of framework, tailored to your unique challenges and opportunities, will play a pivotal role in your data processing endeavours.</p>
<h1 id="heading-reference">Reference</h1>
<ol>
<li>High Performance Data Manipulation in Python: pandas 2.0 vs. polars. Available at: <a target="_blank" href="https://www.datacamp.com/tutorial/high-performance-data-manipulation-in-python-pandas2-vs-polars">DataCamp</a></li>
<li>Handling Large Datasets Efficiently in Python: Pandas vs. Dask. Available at: <a target="_blank" href="https://stackoverflow.com/questions/76323957/handling-large-datasets-efficiently-in-python-pandas-vs-dask">Stack Overflow</a></li>
<li>Pandas vs. Polars: A Syntax and Speed Comparison. Available at: <a target="_blank" href="https://towardsdatascience.com/pandas-vs-polars-a-syntax-and-speed-comparison-5aa54e27497e">Towards Data Science</a></li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Building an NLP Question Answering System with PyTorch, Hugging Face, and Gradio]]></title><description><![CDATA[Natural Language Processing (NLP) has witnessed significant advancements in recent years, thanks to powerful libraries like PyTorch and pre-trained language models from Hugging Face. In this article, I will take you through the journey of creating a ...]]></description><link>https://blog.noufals.in/building-an-nlp-question-answering-system-with-pytorch-hugging-face-and-gradio-61a7adb728ca</link><guid isPermaLink="true">https://blog.noufals.in/building-an-nlp-question-answering-system-with-pytorch-hugging-face-and-gradio-61a7adb728ca</guid><category><![CDATA[pytorch]]></category><category><![CDATA[huggingface]]></category><category><![CDATA[gradio]]></category><category><![CDATA[chatbot]]></category><category><![CDATA[nlp]]></category><category><![CDATA[natural language processing]]></category><dc:creator><![CDATA[Noufal Salim]]></dc:creator><pubDate>Tue, 31 Oct 2023 07:29:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1717943453764/7a383f7d-15a7-4c5c-b1d0-3fbe9f6849f9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Natural Language Processing (NLP) has witnessed significant advancements in recent years, thanks to powerful libraries like PyTorch and pre-trained language models from Hugging Face. In this article, I will take you through the journey of creating a question-answering system using these cutting-edge tools and deploying it as a user-friendly web service with Gradio.</p>
<h3 id="heading-setting-the-stage">Setting the Stage</h3>
<p>Before we dive into the technical details, let’s briefly discuss what we aim to achieve with this project. We want to build a system that takes a passage of text and a question as input, and returns the answer from the passage. This is a common use case for chatbots, virtual assistants, and information retrieval systems.</p>
<p>To kickstart your journey into building an NLP question answering system, consider participating in a hackathon or a similar coding competition. Hackathons provide an excellent opportunity to challenge yourself, learn new skills, and create innovative solutions. Whether you’re a seasoned developer or a newcomer to the field, hackathons offer a unique environment for collaboration and creativity.</p>
<p>Participating in a hackathon focused on NLP or AI can inspire your project idea and connect you with like-minded individuals. You might even find teammates with complementary skills to help you tackle different aspects of your project. Additionally, many hackathons offer access to mentors and experts who can provide guidance and support during the event.</p>
<h3 id="heading-training-the-question-answering-model">Training the Question Answering Model</h3>
<p>The heart of your NLP question answering system is the machine learning model that can understand text and provide accurate answers. PyTorch and Hugging Face Transformers make this task significantly more accessible.</p>
<p>PyTorch is a deep learning framework that provides an intuitive and flexible platform for building and training neural networks. It’s widely used in the research and AI community, making it an excellent choice for your project.</p>
<p>Hugging Face Transformers is a game-changer in the world of NLP. This library offers a vast collection of pre-trained language models, such as BERT, RoBERTa, GPT-2, and more. These models are trained on massive amounts of text data, allowing them to understand and generate human-like text. You can leverage these pre-trained models and fine-tune them on your specific task, like question answering.</p>
<blockquote>
<p>We used distilbert model for finetuning this use case.</p>
</blockquote>
<h3 id="heading-why-use-distilbert">why use DistilBERT</h3>
<p>DistilBERT is a smaller and faster version of the original BERT (Bidirectional Encoder Representations from Transformers) model, created by Hugging Face. It offers several advantages when it comes to training NLP models:</p>
<p>1. <strong>Reduced Model Size:</strong> One of the most significant advantages of DistilBERT is its smaller model size. It retains much of BERT’s performance while being considerably smaller in terms of the number of parameters. This reduced model size makes it more memory-efficient and easier to train and deploy, which can be particularly beneficial when working with limited computational resources.</p>
<p>2. <strong>Faster Inference:</strong> DistilBERT not only has a smaller model size but also significantly faster inference times compared to BERT. This makes it a practical choice for real-time or low-latency applications where quick responses are essential, such as chatbots, virtual assistants, and question-answering systems.</p>
<p>3. <strong>Similar Performance:</strong> Despite its reduced size, DistilBERT maintains competitive performance on various NLP tasks. It is pre-trained on a massive corpus of text data and retains much of the contextual understanding of language that BERT offers. For many applications, the performance difference between DistilBERT and BERT is negligible, making it a cost-effective choice.</p>
<p>4. <strong>Lower Training Costs:</strong> Training a large-scale language model like BERT can be computationally expensive and time-consuming. DistilBERT’s smaller size leads to reduced training costs in terms of hardware and time. This is advantageous for researchers, developers, and organizations with budget constraints.</p>
<p>5. <strong>Lower Carbon Footprint:</strong> The reduced size and faster training times of DistilBERT contribute to a smaller carbon footprint. Energy-efficient models are becoming increasingly important, and using DistilBERT aligns with environmental sustainability goals.</p>
<p>6. <strong>Easy Model Deployment:</strong> Smaller model sizes mean quicker and more straightforward model deployment, especially when serving models in cloud environments or on edge devices. The reduced memory footprint of DistilBERT allows it to fit more comfortably within the constraints of various deployment scenarios.</p>
<p>7. <strong>Transfer Learning:</strong> DistilBERT is well-suited for transfer learning. You can fine-tune it on specific NLP tasks with relatively smaller datasets compared to BERT. This makes it an excellent choice for domain-specific or niche applications.</p>
<p>8. <strong>Community and Resources:</strong> DistilBERT benefits from the broader BERT community and resources, including pre-trained checkpoints, tutorials, and community support. This makes it easier to find solutions to problems and get help if needed.</p>
<p>In summary, DistilBERT offers a compelling trade-off between model size and performance. It is an efficient choice for a wide range of NLP applications, especially when you need to balance the quality of results with computational resources and inference speed.</p>
<h3 id="heading-utilizing-the-intel-developer-cloud">Utilizing the Intel Developer Cloud</h3>
<p>If you’re looking to supercharge your project, consider utilizing the resources provided by the Intel Developer Cloud. This cloud platform offers a range of tools and resources optimized for AI and deep learning tasks, making it an excellent choice for training and deploying NLP models.</p>
<p>Intel’s cloud infrastructure includes high-performance CPUs, GPUs, and accelerators, which can significantly speed up model training and inference. Additionally, they provide libraries and tools that are optimized for Intel hardware, ensuring that your NLP model runs efficiently.</p>
<p>By leveraging the Intel Developer Cloud, you can access cutting-edge hardware, optimize your model for performance, and ensure that your question answering system can handle a large volume of requests when deployed as a web service with Gradio.</p>
<p>In summary, by participating in a hackathon, using PyTorch and Hugging Face Transformers, and tapping into the resources offered by the Intel Developer Cloud, you can set the stage for a successful NLP question answering project. These initial steps will provide you with the inspiration, tools, and infrastructure needed to create a powerful and innovative solution in the world of natural language processing.</p>
<h3 id="heading-deploying-using-gradio">Deploying using gradio</h3>
<p>One-click deployment to Gradio from Hugging Face involves effortlessly transforming a pre-trained Hugging Face model into an interactive web application. By defining a Gradio interface that connects user inputs to the model’s predictions, Gradio simplifies the deployment process, enabling you to share and utilize your NLP model in real-time, with a user-friendly interface, and minimal coding effort.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>In this article, we explored the process of creating an NLP question-answering system using PyTorch, Hugging Face, and Gradio. We began by preparing our data and selecting a pre-trained model. We then fine-tuned the model on the SQuAD dataset and deployed it as a user-friendly web service with Gradio.</p>
<p>The power of combining these tools lies in their ease of use and the ability to create robust NLP applications with minimal effort. With this foundation, you can further fine-tune your model, optimize the web interface, and even deploy it on a cloud platform for scalability. The possibilities are endless, and this project is a testament to the exciting developments in NLP and deep learning.</p>
<p>So, what are you waiting for? Dive in, build your own NLP applications, and witness the magic of PyTorch, Hugging Face, and Gradio!</p>
<p>View my code here: <a target="_blank" href="https://github.com/noufalsalim/openapi-hackathon-solution/blob/main/open_llm.ipynb">https://github.com/noufalsalim/openapi-hackathon-solution/blob/main/open_llm.ipynb</a></p>
<p>View my app here: <a target="_blank" href="https://huggingface.co/spaces/noufals/noufals-distilbert-base-uncased-finetuned-squad">https://huggingface.co/spaces/noufals/noufals-distilbert-base-uncased-finetuned-squad</a></p>
]]></content:encoded></item><item><title><![CDATA[Create your own telegram bot with python and deta.sh]]></title><description><![CDATA[Creating your own telegram bot and doing simple things with the telegram is easy and fun tasks and with deta free web app, you don’t have to have any paid cloud service for deploying a simple app. It is simple to create and customize and deploy your ...]]></description><link>https://blog.noufals.in/create-your-own-telegram-bot-with-python-and-deta-sh-ef9aee7b93d5</link><guid isPermaLink="true">https://blog.noufals.in/create-your-own-telegram-bot-with-python-and-deta-sh-ef9aee7b93d5</guid><category><![CDATA[telegram]]></category><category><![CDATA[telegram bot]]></category><category><![CDATA[telegramapi]]></category><category><![CDATA[deta]]></category><category><![CDATA[automation]]></category><dc:creator><![CDATA[Noufal Salim]]></dc:creator><pubDate>Sat, 05 Jun 2021 12:11:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1717943983482/b574cd33-20ce-4c61-8aab-cd411e891a5d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Creating your own telegram bot and doing simple things with the telegram is easy and fun tasks and with deta free web app, you don’t have to have any paid cloud service for deploying a simple app. It is simple to create and customize and deploy your telegram bot with minimal python coding knowledge and that’s all you need.<br />We will start off by introducing you to what is telegram bot, bots and small third-party applications which runs inside the bigger app that is telegram. By the way, if you don’t know what is telegram, then it is a encrypted cloud based messaging app which is available in Platforms like android, iOS, windows, Linux, Mac, etc. By creating telegram bot, you can integrate your favourite services, get notification and news, build games etc.<br />Without further ado, let’s get started to creating telegram bot.<br />This tutorial requires accounts in telegram, and deta.sh.</p>
<h4 id="heading-telegram">Telegram</h4>
<p>If you doesn’t already have go ahead download and install the telegram app in your mobile or computer by searching on the application store and sign-in by your mobile number, telegram will sent an OTP to your mobile number which will be used for identifying it is your number, add your name and profile photo which is optional and voilà, your account in created.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717939827935/b2e205ba-5c1a-4a71-8772-d65cb5d39aa7.jpeg" alt /></p>
<h4 id="heading-deta-httpswwwdetash">Deta (https://www.deta.sh/)</h4>
<p>Deta is a cloud based micro service solution which let's you deploy your python or node based app in a matter of seconds. Deta has the below listed services and some of the services in beta stage and some are coming soon.</p>
<ul>
<li>Deta micros, which stands for micro services</li>
<li>Deta base, which is a no sql database service</li>
<li>Deta drive, cloud drive services</li>
<li>Deta access, permission management</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717939829627/eb86706b-3d88-46bb-8667-f13f29dbea80.jpeg" alt /></p>
<p>Go ahead and create an account in deta and we need to download deta cli tools to work with deta, download it for your computer (whichever your operating system is, mine in Linux), you will find the instructions in the deta website and login with deta cli.</p>
<p>With all the downloading and installing done we can go ahead with the fun part of creating the bot.<br />The telegram bot creation is split into four parts,</p>
<h3 id="heading-creating-your-telegram-bot-in-telegram">Creating your telegram bot in telegram</h3>
<p>Go ahead into your telegram and press the search icon in the top left corner and put “botFather” in the search box and find the one with the blue tick to it’s right of the name.<br />Bot father search result</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717939831446/17c4ae93-2bba-488e-a89b-36472ec05ec8.jpeg" alt /></p>
<p>The first one is the one we want. Go ahead and click on it and click the start button which is in the welcome page of the “botFather”.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717939832946/2d5a8b2c-61e0-4308-9b1d-3041248291c8.jpeg" alt /></p>
<p>Now we need to create a bot using the commend “/<em>newbot”</em> command it will ask for your bot name(which is not unique, you can give anything you want) and a username(which has to be unique and must end with 'bot’). In the screenshot below you can see I have choosen 'Telegram bot tutorial' as the name and 'Teletutorialbot' as the name(since you have to have unique username, it may take multiple tries).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717939834592/cd5f8899-5f17-45c2-8148-ea206ae4ace1.jpeg" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717939836425/703675bc-ab25-49ff-ac39-ab2d9e87722f.jpeg" alt /></p>
<p>Here we got a link to the bot that we have created, and a unique token, which is used to communicate with our bot, never reveal your bot token since that is used for complete control of your bot. Now your bot is ready you can set photo, about text and description of your bot at this stage. Please click the link which is created for your link which is in the format '<em>t.me/'</em> for accessing your bot, at this time your bot won’t do anything, we will get to that part later.</p>
<h3 id="heading-creating-a-fastapi-server-in-deta">Creating a fastapi server in deta</h3>
<p>We will create a <a target="_blank" href="https://fastapi.tiangolo.com/">fastapi</a> server next for the telegram bot to communicate back and forth, this server will be the one which is receiving message from the user and sending response back to the user. Creating a fastapi server in deta is simple and you can refer their <a target="_blank" href="https://docs.deta.sh/docs/tutorials/fast-api-guide">document</a> for more details.</p>
<p>We will be doing it the same way as the documents suggests.</p>
<p>First of all we will create a new folder or directory and open that folder in your favourite code editor, I am using vscode with black theme (because I am not a geek).</p>
<p>for Linux users you can use the commands.</p>
<blockquote>
<p>mkdir telegram-bot-tutorial &amp;&amp; code telegram-bot-tutorial</p>
</blockquote>
<p>Create a main.py file and put the below Contents in it</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717939838252/7c13dd52-bde2-4094-935b-7c3090aaf566.jpeg" alt /></p>
<p>Now create a requirements.txt file and put '<em>fastapi</em>' without the quote in it.</p>
<p>And finally run</p>
<blockquote>
<p>deta new</p>
</blockquote>
<p>command in your terminal for creating a new deta micros. This will create a new micro project, install the dependency from the requirements.txt file.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717939839851/c2816c57-5b90-49f5-8f90-55b152d9c812.jpeg" alt /></p>
<p>At this stage your deta project is created in your account, go ahead and deploy the service with 'deta deploy’. You will also need the endpoint that is generated from the deta new command going forward. In my case it’s</p>
<blockquote>
<p><em>https://6sfsh0.deta.dev</em></p>
</blockquote>
<p>Don’t copy my link, create your own you morons 😏<br />You can go ahead and open the link in your favourite browser and get the hello world in there.</p>
<h3 id="heading-initializing-webhook-in-telegram-bot">Initializing webhook in telegram bot</h3>
<p>Initializing webhook in telegram bot requires the url of the server which we have deployed in the last stage and the token that we have generated when creating bot. You can also head over to the telegram bot api documentation for advanced usage of the api, for starters we will need to initialize the webhook and tell the telegram server which server we are using for sending and receiving messages.</p>
<p>The telegram api url follows the following pattern</p>
<blockquote>
<p>http://api.telegram.org/bot/method</p>
</blockquote>
<p>For our purpose we will need the method '<em>setWebhook</em>' and token which we obtained from first step. And it needs a parameter url which will be our server url.<br />So in our case the url will be</p>
<blockquote>
<p>http://api.telegram.org/bot1836606926:AAEoxnNXWMLvsIlij9ENJomlLZM7qg6V6Zk/setWebhook?url=https://6sfsh0.deta.dev/</p>
</blockquote>
<p>Where <em>1836606926:AAEoxnNXWMLvsIlij9ENJomlLZM7qg6V6Zk</em> is the token generated for the bot.<br />And the url of our fastapi server is <em>https://6sfsh0.deta.dev/</em></p>
<p>When we paste the url in the browser, we will get a message saying our webhook is set.</p>
<p><strong>Congrats you are 90% done</strong>.</p>
<h3 id="heading-sendingreceiving-message-telegram-server">Sending/receiving message telegram server</h3>
<p>Since we don’t want anyone else to know our token for telegram bot we will input that as an environment variable, which will keep it away from the code and prying eyes.<br />Go back to your vscode or the code editor you were using and create a file named '.<em>env</em>' and put the below content in it</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717939841425/da4355ac-5f97-40df-87ae-df7be0c17656.jpeg" alt /></p>
<p>We will go to the terminal and tell deta that we want the environmental variable to be added to your code by running the command</p>
<blockquote>
<p>deta update --env .env</p>
</blockquote>
<p>Where '.env' is the location of the environmental variable file, if your location is different please change accordingly.<br />Now we will update the main.py file to get message from the telegram server and sent back appropriate response back to the user. For this tutorial we will sent back the exact text the user sent to the bot, looking forward to create more tutorials in the future which will incorporate more features of telegram.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717939842903/8cd6b081-8290-4701-9114-c5997324ab60.jpeg" alt /></p>
<p>The above picture is the entire code required for it, you can see we have barely 24 lines of codes for the entire bot. We will go line by line and explain what each line does.<br />In the first two lines we are importing the os module in the python which will help getting the key variable which we have put into '.env' file. We save the variable with name my_secret.<br />We will give the base_url the starting url of the telegram server which we needed to use several places in the code.<br />In the lines 6-8 we will import the fastapi, requests and pydantic module, the fast api module we were importing for the server before. <strong><em>Requests</em></strong> module is used to sent and recieve http connections from telegram server. And lastly <em>pydantic</em> is used for defining dataclass which will enforce the data in specific format.<br />After Initializing the <em>fastapi</em> app in line 10, we will go ahead and create a data class using the base model from the <em>pydantic</em> module, which is the data receiving from the telegram server. It is fully optional to use the base model, but it will make the fastapi documentation easier which we can access for our server in the endpoint '/<em>docs</em>’.<br />Functon '<em>get_response</em>' is used to echo the user input back to the user, we can further improve this function to give whatever response we like. For now it will return the same message which is recieved from the user.<br />We have changed the fastapi server get response that we initially created to respond with '<em>chatbot is up</em>' instead of hello world for understanding.</p>
<p>Going into line 23 is the real magic happens.</p>
<p>whenever a user message is received in telegram server it pushes the message to our server in a post method. We will use the data which is sent by the telegram server in this function to respond to the user when some input or event occurs. We extract the message data from the incoming message from telegram server which is in the below format</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717939844329/d11bf2ee-b7dd-4a6d-a290-1e7c77296afa.jpeg" alt /></p>
<p>We need the '<strong><em>id</em></strong>' and message '<strong><em>text</em></strong>' content from this format for processing. We get that in line 26 and 28 respectively.<br />Using the function '<em>get_response</em>' we will get the appropriate response, which in this case is the user text itself. If that doesn’t make any sense now, your get_response function can return what ever you want.<br />With the <em>id</em> and <em>bot response</em> in hand we can send the message back to the telegram server in the method '<em>sendMessage</em>’. The url follows the same format as before like base_url then token and then the method. Creating the url is in line 29 using f-string functionality of python and we will use the request module to sent back a post request to the telegram server itself with parameters '<em>chat_id</em>' which is the ID we obtained from the request and 'text' which is the bot response we have created.</p>
<p>Congarts now, you have created your first telegram bot with webhook. Now go ahead and deploy the changes in you fastapi application using the command</p>
<blockquote>
<p>deta deploy</p>
</blockquote>
<p>And go to your telegram bot(using your username or the link proveded while creating your bot in botfather) in the application and send any message, the bot will respond back with the same message.</p>
<p>This is my first try in creating a blog of what I have done in telegram, with your support I am hoping to create more articles like this and help others as well. If you have any suggestions and feedback ping me in telegram by clicking <a target="_blank" href="https://t.me/noufys">here</a>.</p>
<h4 id="heading-thank-you">Thank you.</h4>
]]></content:encoded></item></channel></rss>