{
  "source_file": "0930",
  "source_platform": "Medium",
  "author": "Ibrahim Salami",
  "title_listed": "NumPy for Absolute Beginners: A Project-Based Approach to Data Analysis",
  "keywords": "",
  "domain": "数据处理",
  "content_type": "深度技术解析",
  "is_paid_flag": "否",
  "url": "https://towardsdatascience.com/numpy-for-absolute-beginners-a-project-based-approach-to-data-analysis/",
  "publish_date": "2025-11-04",
  "corpus_stage": "",
  "notes": "",
  "id": "51c06ef2bde2",
  "collected_at": "2026-10-02T12:12:13",
  "title": "NumPy for Absolute Beginners: A Project-Based Approach to Data Analysis | Towards Data Science",
  "body_markdown": "![Revisit consent button](../images/body-df29beacd7496220cc94.svg)\nWe value your privacy\nWe use cookies to enhance your browsing experience, serve personalised ads or content, and analyse our traffic. By clicking \"Accept All\", you consent to our use of cookies.\nCustomise Reject All Accept All\nCustomise Consent Preferences ![](../images/body-2159bb67f3de8ad870eb.svg)\nWe use cookies to help you navigate efficiently and perform certain functions. You will find detailed information about all cookies under each consent category below.\nThe cookies that are categorised as \"Necessary\" are stored on your browser as they are essential for enabling the basic functionalities of the site. ... Show more\nNecessaryAlways Active\nNecessary cookies are required to enable the basic features of this site, such as providing secure log-in or adjusting your consent preferences. These cookies do not store any personally identifiable data.\n  * Cookie\nBCTempID\n  * Duration\n10 minutes\n  * Description\nNo description available.\n\n\n  * Cookie\n__cf_bm\n  * Duration\n1 hour\n  * Description\nThis cookie, set by Cloudflare, is used to support Cloudflare Bot Management. \n\n\n  * Cookie\nAWSALBCORS\n  * Duration\n7 days\n  * Description\nAmazon Web Services set this cookie for load balancing.\n\n\n  * Cookie\n_cfuvid\n  * Duration\nsession\n  * Description\nCloudflare sets this cookie to track users across sessions to optimize user experience by maintaining session consistency and providing personalized services\n\n\n  * Cookie\nli_gc\n  * Duration\n6 months\n  * Description\nLinkedin set this cookie for storing visitor's consent regarding using cookies for non-essential purposes.\n\n\n  * Cookie\n__hssrc\n  * Duration\nsession\n  * Description\nThis cookie is set by Hubspot whenever it changes the session cookie. The __hssrc cookie set to 1 indicates that the user has restarted the browser, and if the cookie does not exist, it is assumed to be a new session.\n\n\n  * Cookie\n__hssc\n  * Duration\n1 hour\n  * Description\nHubSpot sets this cookie to keep track of sessions and to determine if HubSpot should increment the session number and timestamps in the __hstc cookie.\n\n\n  * Cookie\nwpEmojiSettingsSupports\n  * Duration\nsession\n  * Description\nWordPress sets this cookie when a user interacts with emojis on a WordPress site. It helps determine if the user's browser can display emojis properly.\n\n\n  * Cookie\nBCSessionID\n  * Duration\n1 year 1 month 4 days\n  * Description\nBlueconic sets this cookie as a unique identifier for the BlueConic profile.\n\n\n  * Cookie\n_octo\n  * Duration\n1 year\n  * Description\nNo description available.\n\n\n  * Cookie\nlogged_in\n  * Duration\n1 year\n  * Description\nNo description available.\n\n\n  * Cookie\n__Secure-YEC\n  * Duration\npast\n  * Description\nYouTube sets this cookie to stores the user's video player preferences using embedded YouTube video\n\n\n  * Cookie\n__eoi\n  * Duration\n6 months\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\nAWSALBTGCORS\n  * Duration\n7 days\n  * Description\nNo description available.\n\n\n  * Cookie\nlogin-status-p\n  * Duration\npast\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\nAWSALBTG\n  * Duration\n7 days\n  * Description\nNo description available.\n\n\n  * Cookie\ncsrf_token\n  * Duration\nsession\n  * Description\nNo description available.\n\n\n  * Cookie\ntoken_v2\n  * Duration\n1 day\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\nD\n  * Duration\n1 year\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\nPHPSESSID\n  * Duration\nsession\n  * Description\nThis cookie is native to PHP applications. The cookie stores and identifies a user's unique session ID to manage user sessions on the website. The cookie is a session cookie and will be deleted when all the browser windows are closed.\n\n\n  * Cookie\nVISITOR_PRIVACY_METADATA\n  * Duration\n6 months\n  * Description\nYouTube sets this cookie to store the user's cookie consent state for the current domain. \n\n\n  * Cookie\ncookietest\n  * Duration\nsession\n  * Description\nThe cookietest cookie is typically used to determine whether the user's browser accepts cookies, essential for website functionality and user experience.\n\n\n  * Cookie\n__Host-airtable-session\n  * Duration\n1 year\n  * Description\nThis cookie is used to enable us to integrate the services of Airtable.\n\n\n  * Cookie\n__Host-airtable-session.sig\n  * Duration\n1 year\n  * Description\nThis cookie is used to enable us to integrate the services of Airtable.\n\n\n  * Cookie\nm\n  * Duration\n1 year 1 month 4 days\n  * Description\nStripe sets this cookie for fraud prevention purposes. It identifies the device used to access the website, allowing the website to be formatted accordingly.\n\n\n  * Cookie\nBIGipServer*\n  * Duration\nsession\n  * Description\nMarketo sets this cookie to collect information about the user's online activity and build a profile about their interests to provide advertisements relevant to the user. \n\n\n  * Cookie\n__cfruid\n  * Duration\nsession\n  * Description\nCloudflare sets this cookie to identify trusted web traffic.\n\n\n  * Cookie\n_GRECAPTCHA\n  * Duration\n6 months\n  * Description\nGoogle Recaptcha service sets this cookie to identify bots to protect the website against malicious spam attacks.\n\n\n  * Cookie\n__Secure-YNID\n  * Duration\n6 months\n  * Description\nGoogle cookie used to protect user security and prevent fraud, especially during the login process.\n\n\n  * Cookie\ncookieyes-consent\n  * Duration\n1 year\n  * Description\nCookieYes sets this cookie to remember users' consent preferences so that their preferences are respected on subsequent visits to this site. It does not collect or store any personal information about the site visitors.\n\n\nFunctional\nFunctional cookies help perform certain functionalities like sharing the content of the website on social media platforms, collecting feedback, and other third-party features.\n  * Cookie\nlidc\n  * Duration\n1 day\n  * Description\nLinkedIn sets the lidc cookie to facilitate data center selection.\n\n\n  * Cookie\nbrw\n  * Duration\n1 year\n  * Description\nNo description available.\n\n\n  * Cookie\nbrwConsent\n  * Duration\n5 minutes\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\nWMF-Uniq\n  * Duration\n1 year\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\nloom_anon_comment\n  * Duration\n1 year\n  * Description\nNo description available.\n\n\n  * Cookie\nloom_referral_video\n  * Duration\nsession\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\nVISITOR_INFO1_LIVE\n  * Duration\n6 months\n  * Description\nA cookie set by YouTube to measure bandwidth that determines whether the user gets the new or old player interface.\n\n\n  * Cookie\nyt-remote-connected-devices\n  * Duration\nNever Expires\n  * Description\nYouTube sets this cookie to store the user's video preferences using embedded YouTube videos.\n\n\n  * Cookie\nytidb::LAST_RESULT_ENTRY_KEY\n  * Duration\nNever Expires\n  * Description\nThe cookie ytidb::LAST_RESULT_ENTRY_KEY is used by YouTube to store the last search result entry that was clicked by the user. This information is used to improve the user experience by providing more relevant search results in the future.\n\n\n  * Cookie\nyt-remote-device-id\n  * Duration\nNever Expires\n  * Description\nYouTube sets this cookie to store the user's video preferences using embedded YouTube videos.\n\n\n  * Cookie\nyt-remote-session-name\n  * Duration\nsession\n  * Description\nThe yt-remote-session-name cookie is used by YouTube to store the user's video player preferences using embedded YouTube video.\n\n\n  * Cookie\nyt-remote-fast-check-period\n  * Duration\nsession\n  * Description\nThe yt-remote-fast-check-period cookie is used by YouTube to store the user's video player preferences for embedded YouTube videos.\n\n\n  * Cookie\nyt-remote-session-app\n  * Duration\nsession\n  * Description\nThe yt-remote-session-app cookie is used by YouTube to store user preferences and information about the interface of the embedded YouTube video player.\n\n\n  * Cookie\nyt-remote-cast-available\n  * Duration\nsession\n  * Description\nThe yt-remote-cast-available cookie is used to store the user's preferences regarding whether casting is available on their YouTube video player.\n\n\n  * Cookie\nyt-remote-cast-installed\n  * Duration\nsession\n  * Description\nThe yt-remote-cast-installed cookie is used to store the user's video player preferences using embedded YouTube video.\n\n\n  * Cookie\ncp_session\n  * Duration\n3 months\n  * Description\nCodepen sets this cookie for Help systems found in the website.\n\n\n  * Cookie\nloid\n  * Duration\n1 year 1 month 4 days\n  * Description\nThis cookie is set by the Reddit. The cookie enables the sharing of content from the website onto the social media platform.\n\n\nAnalytics\nAnalytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics such as the number of visitors, bounce rate, traffic source, etc.\n  * Cookie\n__hstc\n  * Duration\n6 months\n  * Description\nHubspot set this main cookie for tracking visitors. It contains the domain, initial timestamp (first visit), last timestamp (last visit), current timestamp (this visit), and session number (increments for each subsequent session).\n\n\n  * Cookie\nhubspotutk\n  * Duration\n6 months\n  * Description\nHubSpot sets this cookie to keep track of the visitors to the website. This cookie is passed to HubSpot on form submission and used when deduplicating contacts.\n\n\n  * Cookie\n_ga\n  * Duration\n1 year 1 month 4 days\n  * Description\nGoogle Analytics sets this cookie to calculate visitor, session and campaign data and track site usage for the site's analytics report. The cookie stores information anonymously and assigns a randomly generated number to recognise unique visitors.\n\n\n  * Cookie\n_ga_*\n  * Duration\n1 year 1 month 4 days\n  * Description\nGoogle Analytics sets this cookie to store and count page views.\n\n\n  * Cookie\n__Host-psifi.analyticsTrace\n  * Duration\n6 hours\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\n__Host-psifi.analyticsTraceV2\n  * Duration\n6 hours\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\n_gh_sess\n  * Duration\nsession\n  * Description\nGitHub sets this cookie for temporary application and framework state between pages like what step the user is on in a multiple step form.\n\n\n  * Cookie\nYSC\n  * Duration\nsession\n  * Description\nYSC cookie is set by Youtube and is used to track the views of embedded videos on Youtube pages.\n\n\n  * Cookie\najs_anonymous_id\n  * Duration\n1 year\n  * Description\nThis cookie is set by Segment to count the number of people who visit a certain site by tracking if they have visited before.\n\n\n  * Cookie\nvuid\n  * Duration\n1 year 1 month 4 days\n  * Description\nVimeo installs this cookie to collect tracking information by setting a unique ID to embed videos on the website. \n\n\nPerformance\nPerformance cookies are used to understand and analyse the key performance indexes of the website which helps in delivering a better user experience for the visitors.\n  * Cookie\nAWSALB\n  * Duration\n7 days\n  * Description\nAWSALB is an application load balancer cookie set by Amazon Web Services to map the session to the target.\n\n\n  * Cookie\nacq\n  * Duration\npast\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\nacq.sig\n  * Duration\npast\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\nptc\n  * Duration\n2 years\n  * Description\nNo description available.\n\n\nAdvertisement\nAdvertisement cookies are used to provide visitors with customised advertisements based on the pages you visited previously and to analyse the effectiveness of the ad campaigns.\n  * Cookie\nmuc_ads\n  * Duration\n1 year 1 month 4 days\n  * Description\nTwitter sets this cookie to collect user behaviour and interaction data to optimize the website.\n\n\n  * Cookie\nguest_id_marketing\n  * Duration\n1 year 1 month 4 days\n  * Description\nTwitter sets this cookie to identify and track the website visitor.\n\n\n  * Cookie\nguest_id_ads\n  * Duration\n1 year 1 month 4 days\n  * Description\nTwitter sets this cookie to identify and track the website visitor.\n\n\n  * Cookie\npersonalization_id\n  * Duration\n1 year 1 month 4 days\n  * Description\nTwitter sets this cookie to integrate and share features for social media and also store information about how the user uses the website, for tracking and targeting.\n\n\n  * Cookie\nguest_id\n  * Duration\n1 year 1 month 4 days\n  * Description\nTwitter sets this cookie to identify and track the website visitor. It registers if a user is signed in to the Twitter platform and collects information about ad preferences.\n\n\n  * Cookie\nbcookie\n  * Duration\n1 year\n  * Description\nLinkedIn sets this cookie from LinkedIn share buttons and ad tags to recognize browser IDs.\n\n\n  * Cookie\n__Secure-ROLLOUT_TOKEN\n  * Duration\n6 months\n  * Description\nYouTube sets this cookie to manage feature rollout and experimentation. It helps Google control which new features or interface changes are shown to users as part of testing and staged rollouts, ensuring consistent experience for a given user during an experiment.\n\n\n  * Cookie\nyt.innertube::nextId\n  * Duration\nNever Expires\n  * Description\nYouTube sets this cookie to register a unique ID to store data on what videos from YouTube the user has seen.\n\n\n  * Cookie\nyt.innertube::requests\n  * Duration\nNever Expires\n  * Description\nYouTube sets this cookie to register a unique ID to store data on what videos from YouTube the user has seen.\n\n\n  * Cookie\nsession_tracker\n  * Duration\nsession\n  * Description\nThis cookie is set by the Reddit. This cookie is used to identify trusted web traffic. It also helps in adverstising on the website.\n\n\n  * Cookie\nedgebucket\n  * Duration\nsession\n  * Description\nReddit sets this cookie to save the information about a log-on Reddit user, for the purpose of advertisement recommendations and updating the content.\n\n\n  * Cookie\ndid\n  * Duration\n1 year\n  * Description\nArbor sets this cookie to show targeted ads to site visitors.This cookie expires after 2 months or 1 year.\n\n\nUncategorised\nOther uncategorised cookies are those that are being analysed and have not been classified into a category as yet.\nNo cookies to display.\nReject All Save My Preferences Accept All\nToggle Search[](https://towardsdatascience.com/)Toggle Mobile Navigation\n[](https://towardsdatascience.com/)\nPublish AI, ML & data-science insights to a global community of data professionals.\nSign in[Submit an Article](https://write.insightmediagroup.io)\n[Latest](https://towardsdatascience.com/latest/)[Editor's Picks](https://towardsdatascience.com/tag/editors-pick/)[Newsletter](https://towardsdatascience.com/tag/the-variable/)[ShipAI](https://towardsdatascience.com/shipai/)\n* * *\n[Write For TDS](https://towardsdatascience.com/submissions/)\n[LinkedIn](https://www.linkedin.com/company/towards-data-science/)[X](https://x.com/TDataScience)Toggle Search\n[Data Science](https://towardsdatascience.com/category/data-science/)\n# NumPy for Absolute Beginners: A Project-Based Approach to Data Analysis\nBuild a high-performance sensor data pipeline from scratch and unlock the true speed of Python's scientific computing core\n[Ibrahim Salami](https://towardsdatascience.com/author/ibrahim.salami/)\nNovember 4, 202513 min read\n![](../images/000.jpg)\nTo learn NumPy, I’ve been running a series where I build mini projects. I’ve built a [Personal Habit](https://towardsdatascience.com/using-numpy-to-analyze-my-daily-habits-sleep-screen-time-mood/) and [Weather Analysis](https://towardsdatascience.com/hidden-gems-in-numpy-7-functions-every-data-scientist-should-know/) project. But I haven’t really gotten the chance to explore the full power and capability of NumPy. I want to try to understand why NumPy is so useful in data analysis. To wrap up this series, I’m going to be showcasing this in real time.\nI’ll be using a fictional client or company to make things interactive. In this case, our client is going to be**EnviroTech Dynamics** , a global operator of industrial sensor networks.\nCurrently, EnviroTech relies on outdated, loop-based Python scripts to process over **1 million sensor readings daily**. This process is agonizingly slow, delaying critical maintenance decisions and impacting operational efficiency. They need a modern, high-performance solution.\nI’ve been tasked with creating a NumPy-based proof-of-concept to demonstrate how to **turbocharge their data pipeline**.\nLearn this step by step with the interactive [AI and Data Scientist](https://roadmap.sh/ai-data-scientist) roadmap.\n## The Dataset: Simulated Sensor Readings\nTo prove the concept, I’ll be working with a large, simulated dataset generated using NumPy‘s random module, featuring entries with the following key arrays:\n  * Temperature —Each data point represents how hot a machine or system component is running. These readings can quickly help us detect when a machine starts overheating — a sign of possible failure, inefficiency, or safety risk.\n  * Pressure — data showing how much pressure is building up inside the system, and if it is within a safe range\n  * Status codes — represent the health or state of each machine or system at a given moment. 0 (Normal), 1 (Warning), 2 (Critical), 3 (Faulty/Missing).  \n\n\n\n## Project Objectives\nThe core goal is to provide four clear, vectorised solutions to EnviroTech’s data challenges, demonstrating speed and power. So I’ll be showcasing all of these:\n  * Performance and efficiency benchmark\n  * Foundational statistical baseline\n  * Critical anomaly detection and\n  * Data cleaning and imputation\n\n\nBy the end of this article, you should be able to get a full grasp of NumPy and its usefulness in data analysis.\n## Objective 1: Performance and Efficiency Benchmark\nFirst, we need a massive dataset to make the speed difference obvious. I’ll be using the **1,000,000 temperature readings** we planned earlier.\npython\n\n```\nimport numpy as np\n# Set the size of our data\nNUM_READINGS = 1_000_000\n\n# Generate the Temperature array (1 million random floating-point numbers)\n# We use a seed so the results are the same every time you run the code\nnp.random.seed(42)\nmean_temp = 45.0\nstd_dev_temp = 12.0\ntemperature_data = np.random.normal(loc=mean_temp, scale=std_dev_temp, size=NUM_READINGS)\n\nprint(f”Data array size: {temperature_data.size} elements”)\nprint(f”First 5 temperatures: {temperature_data[:5]}”)\n```\n\n**Output:**\ntext\n\n```\nData array size: 1000000 elements\nFirst 5 temperatures: [50.96056984 43.34082839 52.77226246 63.27635828 42.1901595 ]\n```\n\nNow that we have our records. Let’s check out the effectiveness of NumPy.\nAssuming we wanted to calculate the average of all these elements using a standard Python loop, it’ll go something like this.\npython\n\n```\n# Function using a standard Python loop\ndef calculate_mean_loop(data):\ntotal = 0\ncount = 0\nfor value in data:\ntotal += value\ncount += 1\nreturn total / count\n\n# Let’s run it once to make sure it works\nloop_mean = calculate_mean_loop(temperature_data)\nprint(f”Mean (Loop method): {loop_mean:.4f}”)\n```\n\nThere’s nothing wrong with this method. But it’s quite slow, because the computer has to process each number one by one, constantly moving between the Python interpreter and the CPU.\nTo truly showcase the speed, I’ll be using the`%timeit` command. This runs the code hundreds of times to provide a reliable average execution time.\npython\n\n```\n# Time the standard Python loop (will be slow)\nprint(“ — — Timing the Python Loop — -”)\n%timeit -n 10 -r 5 calculate_mean_loop(temperature_data)\n```\n\n**Output**\nmarkup\n\n```\n--- Timing the Python Loop ---244 ms ± 51.5 ms per loop (mean ± std. dev. of 5 runs, 10 loops each)\n```\n\nUsing the` -n 10`, I’m basically running the code in the loop 10 times (to get a stable average), and using the` -r 5`, the whole process will be repeated 5 times (for even more stability).\nNow, let’s compare this with NumPy vectorisation. And by vectorisation, it means the entire operation (average in this case) will be performed on the entire array at once, using highly optimised C code in the background.   \n\nHere’s how the average will be calculated using NumPy\npython\n\n```\n# Using the built-in NumPy mean function\ndef calculate_mean_numpy(data):\nreturn np.mean(data)\n# Let’s run it once to make sure it works\nnumpy_mean = calculate_mean_numpy(temperature_data)\nprint(f”Mean (NumPy method): {numpy_mean:.4f}”)\n```\n\n**Output:**\nmarkup\n\n```\nMean (NumPy method): 44.9808\n```\n\nNow let’s time it.\npython\n\n```\n# Time the NumPy vectorized function (will be fast)\nprint(“ — — Timing the NumPy Vectorization — -”)\n%timeit -n 10 -r 5 calculate_mean_numpy(temperature_data)\n```\n\n**Output:**\nmarkup\n\n```\n--- Timing the NumPy Vectorization ---1.49 ms ± 114 μs per loop (mean ± std. dev. of 5 runs, 10 loops each)\n```\n\nNow, that’s a huge difference. That’s like almost non-existent. That’s the power of vectorisation.\nLet's present this speed difference to the client:  \n\n> “We compared two methods for performing the same calculation on one million temperature readings — a traditional Python for-loop and a NumPy vectorized operation.\n> The difference was dramatic: The pure Python loop took about **244 milliseconds** per run while the NumPy version completed the same task in just **1.49 milliseconds**.\n> That’s roughly a **160× speed improvement**.”\n## Objective 2: Foundational Statistical Baseline\nAnother cool feature NumPy offers is the ability to perform basic to advanced statistics — this way, you can get a good overview of what’s going on in your dataset. It offers operations like:\n  * np.mean() — to calculate the average\n  * np.median — the middle value of the data\n  * np.std() — shows how spread out your numbers are from the average\n  * np.percentile() — tells you the value below which a certain percentage of your data falls.\n\n\nNow that we’ve managed to provide an alternative and efficient solution to retrieve and perform summaries and calculations on their huge dataset, we can start playing around with it.\nWe already managed to generate our simulated temperature data. Let’s do the same for pressure. Calculating pressure is a great way to demonstrate the ability of NumPy to handle multiple massive arrays in no time at all.\nFor our client, it also allows me to showcase a health check on their industrial systems.\nAlso, temperature and pressure are often related. A sudden pressure drop might be the cause of a spike in temperature, or vice versa. Calculating baselines for both allows us to see if they are drifting together or independently  \n\npython\n\n```\n# Generate the Pressure array (Uniform distribution between 100.0 and 500.0)\nnp.random.seed(43) # Use a different seed for a new dataset\npressure_data = np.random.uniform(low=100.0, high=500.0, size=1_000_000)\nprint(“Data arrays ready.”)\n```\n\n**Output:**\nmarkup\n\n```\nData arrays ready.\n```\n\nAlright, let’s begin our calculations.\npython\n\n```\nprint(“\\n — — Temperature Statistics — -”)\n# 1. Mean and Median\ntemp_mean = np.mean(temperature_data)\ntemp_median = np.median(temperature_data)\n\n# 2. Standard Deviation\ntemp_std = np.std(temperature_data)\n\n# 3. Percentiles (Defining the 90% Normal Range)\ntemp_p5 = np.percentile(temperature_data, 5) # 5th percentile\ntemp_p95 = np.percentile(temperature_data, 95) # 95th percentile\n\n# Formating our results\nprint(f”Mean (Average): {temp_mean:.2f}°C”)\nprint(f”Median (Middle): {temp_median:.2f}°C”)\nprint(f”Std. Deviation (Spread): {temp_std:.2f}°C”)\nprint(f”90% Normal Range: {temp_p5:.2f}°C to {temp_p95:.2f}°C”)\n```\n\n**Here’s the output:**\nmarkup\n\n```\n--- Temperature Statistics ---Mean (Average): 44.98°CMedian (Middle): 44.99°CStd. Deviation (Spread): 12.00°C90% Normal Range: 25.24°C to 64.71°C\n```\n\nSo to explain what you’re seeing here\n**The Mean (Average): 44.98°C** basically gives us a central point around which most readings are expected to fall. This is pretty cool because we don’t have to scan through the entire large dataset. With this number, I’ve gotten a pretty good idea of where our temperature readings usually fall.\n**The Median (Middle): 44.99°C** is quite identical to the mean if you notice. This tells us that there aren’t extreme outliers dragging the average too high or too low.\n**The standard deviation of 12°C** means the temperatures vary quite a bit from the average. Basically, some days are much hotter or cooler than others. A lower value (say 3°C or 4°C) would have suggested more consistency, but 12°C indicates a highly variable pattern.\nFor the **percentile** , it basically means most days hover between 25°C and 65°C,  \nIf I were to present this to the client, I could put it like this:\n> “On average, the system (or environment) maintains a temperature around **45°C** , which serves as a reliable baseline for typical operating or environmental conditions. A deviation of 12°C indicates that temperature levels fluctuate significantly around the average. \n> To put it simply, the readings are not very stable. Lastly, 90% of all readings fall between 25°C and 65°C. This gives a realistic picture of what “normal” looks like, helping you define acceptable thresholds for alerts or maintenance. To improve performance or reliability, we could identify the causes of high fluctuations (e.g., external heat sources, ventilation patterns, system load).”\nLet’s calculate for pressure also.\npython\n\n```\nprint(“\\n — — Pressure Statistics — -”)\n# Calculate all 5 measures for Pressure\npressure_stats = {\n“Mean”: np.mean(pressure_data),\n“Median”: np.median(pressure_data),\n“Std. Dev”: np.std(pressure_data),\n“5th %tile”: np.percentile(pressure_data, 5),\n“95th %tile”: np.percentile(pressure_data, 95),\n}\nfor label, value in pressure_stats.items():\nprint(f”{label:<12}: {value:.2f} kPa”)\n```\n\nTo improve our codebase, I’m storing all the calculations performed in a dictionary called pressure stats, and I’m simply looping over the key-value pairs.\n**Here’s the output:**\nmarkup\n\n```\n--- Pressure Statistics ---Mean : 300.09 kPaMedian : 300.04 kPaStd. Dev : 115.47 kPa5th %tile : 120.11 kPa95th %tile : 480.09 kPa\n```\n\nIf I were to present this to the client. It’d go something like this:  \n\n> “Our **pressure readings average around** **300 kilopascals** , and the median — the middle value — is almost the same. That tells us the pressure distribution is quite balanced overall. However, the **standard deviation is about 115 kPa** , which means there’s a lot of variation between readings. In other words, some readings are much higher or lower than the typical 300 kPa level.  \n> Looking at the **percentiles** , 90% of our readings fall between **120 and 480 kPa**. That’s a wide range, suggesting that pressure conditions are not stable — possibly fluctuating between low and high states during operation. So while the average looks fine, the variability could point to **inconsistent performance** or **environmental factors** affecting the system.”\n## Objective 3: Critical Anomaly Identification\nOne of my favourite features of NumPy is the ability to quickly identify and filter out anomalies in your dataset. To demonstrate this, our fictional client, EnviroTech Dynamics, provided us with another helpful array that contains system status codes. This tells us how the machine is consistently operating. It’s simply a range of codes (0–3).\n  * **0** → Normal\n  * **1** → Warning\n  * **2** → Critical\n  * **3** → Sensor Error  \n\n\n\nThey receive millions of readings per day, and our job is to find every machine that’s both in a critical state and running dangerously hot.  \nDoing this manually, or even with a loop, would take ages. This is where Boolean Indexing (masking) comes in. It lets us filter huge datasets in milliseconds by applying logical conditions directly to arrays, without loops.\nEarlier, we generated our temperature and pressure data. Let’s do the same for the status codes.\npython\n\n```\n# Reusing 'temperature_data' from earlier\nimport numpy as np\n\nnp.random.seed(42) # For reproducibility\n\nstatus_codes = np.random.choice(\na=[0, 1, 2, 3],\nsize=len(temperature_data),\np=[0.85, 0.10, 0.03, 0.02] # 0=Normal, 1=Warning, 2=Critical, 3=Offline\n)\n\n# Let’s preview our data\nprint(status_codes[:5])\n```\n\n**Output:**\nmarkup\n\n```\n[0 2 0 0 0]\n```\n\nEach temperature reading now has a matching status code. This allows us to pinpoint _which_ sensors report problems and _how severe_ they are.\nNext, we’ll need some sort of threshold or anomaly criteria. In most scenarios, anything above **mean + 3 × standard deviation** is considered a severe outlier, the kind of reading you don’t want in your system. To compute that\npython\n\n```\ntemp_mean = np.mean(temperature_data)\ntemp_std = np.std(temperature_data)\nSEVERITY_THRESHOLD = temp_mean + (3 * temp_std)\nprint(f”Severe Outlier Threshold: {SEVERITY_THRESHOLD:.2f}°C”)\n```\n\n**Output:**\nmarkup\n\n```\nSevere Outlier Threshold: 80.99°C\n```\n\nNext, we’ll create two filters (masks) to isolate data that meets our conditions. One for readings where the system status is Critical (code 2) and another for readings where the temperature exceeds the threshold.\npython\n\n```\n# Mask 1 — Readings where system status = Critical (code 2)\ncritical_status_mask = (status_codes == 2)\n\n# Mask 2 — Readings where temperature exceeds threshold\nhigh_temp_outlier_mask = (temperature_data > SEVERITY_THRESHOLD)\n\nprint(f”Critical status readings: {critical_status_mask.sum()}”)\nprint(f”High-temp outliers: {high_temp_outlier_mask.sum()}”)\n```\n\nHere’s what's going on behind the scenes. NumPy creates two arrays filled with True or False. Every True marks a reading that satisfies the condition. True will be represented as 1, and False will be represented as 0. Summing them quickly counts how many match.\nHere’s the output:\nmarkup\n\n```\nCritical status readings: 30178High-temp outliers: 1333\n```\n\nLet’s combine both anomalies before printing our final result. We want readings that are both critical and too hot. NumPy allows us to filter on multiple conditions using logical operators. In this case, we’ll be using the AND function represented as `&.`\npython\n\n```\n# Combine both conditions with a logical AND\ncritical_anomaly_mask = critical_status_mask & high_temp_outlier_mask\n\n# Extract actual temperatures of those anomalies\nextracted_anomalies = temperature_data[critical_anomaly_mask]\nanomaly_count = critical_anomaly_mask.sum()\n\nprint(“\\n — — Final Results — -”)\nprint(f”Total Critical Anomalies: {anomaly_count}”)\nprint(f”Sample Temperatures: {extracted_anomalies[:5]}”)\n```\n\n**Output:**\nmarkup\n\n```\n--- Final Results ---Total Critical Anomalies: 34Sample Temperatures: [81.9465697 81.11047892 82.23841531 86.65859372 81.146086 ]\n```\n\nLet’s present this to the client  \n\n> “After analyzing one million temperature readings, our system detected **34 critical anomalies** — readings that were both flagged as ‘critical status’ by the machine and exceeded the high-temperature threshold.\n> The first few of these readings fall between **81°C and 86°C** , which is well above our normal operating range of around 45°C. This suggests that a small number of sensors are reporting **dangerous spikes** , possibly indicating overheating or sensor malfunction.  \n> In other words, while 99.99% of our data looks stable, these 34 points represent the **exact spots** where we should focus maintenance or investigate further.”\n  \nLet’s visualise this real quick with matplotlib\n![](../images/001.jpg)\nWhen I first plotted the results, I expected to see a cluster of red bars showing my critical anomalies. But there were none.\nAt first, I thought something was wrong, but then it clicked. Out of one million readings, only 34 were critical. That’s the beauty of Boolean masking: it detects what your eyes can’t. Even when the anomalies hide deep within millions of normal values, NumPy flags them in milliseconds.\n## Objective 4: Data Cleaning and Imputation\nLastly, NumPy allows you to get rid of inconsistencies and data that doesn’t make sense. You might have come across the concept of data cleaning in data analysis. In Python, NumPy and Pandas are often used to streamline this activity. \nTo demonstrate this, our `status_codes` contain entries with a value of 3 (Faulty/Missing). If we use these faulty temperature readings in our overall analysis, they will skew our results. The solution is to replace the faulty readings with a statistically sound estimated value.\nThe first step is to figure out what value we should use to replace the bad data. The median is always a great choice because, unlike the mean, it is less affected by extreme values.\npython\n\n```\n# TASK: Identify the mask for ‘Valid’ data (where status_codes is NOT 3 — Faulty/Missing).\nvalid_data_mask = (status_codes != 3)\n\n# TASK: Calculate the median temperature ONLY for the Valid data points. This is our imputation value.\nvalid_median_temp = np.median(temperature_data[valid_data_mask])\nprint(f”Median of all valid readings: {valid_median_temp:.2f}°C”)\n```\n\n**Output:**\nmarkup\n\n```\nMedian of all valid readings: 44.99°C\n```\n\nNow, we’ll perform some conditional replacement using the powerful `np.where()` function. Here’s a typical structure of the function.\n**np.where(Condition, Value_if_True, Value_if_False)**\nIn our case:  \n\n  * **Condition:** Is the status code **3** (Faulty/Missing)?\n  * **Value if True:** Use our calculated `valid_median_temp`.\n  * **Value if False:** Keep the original temperature reading.\n\n\npython\n\n```\n# TASK: Implement the conditional replacement using np.where().\ncleaned_temperature_data = np.where(\nstatus_codes == 3, # CONDITION: Is the reading faulty?\nvalid_median_temp, # VALUE_IF_TRUE: Replace with the calculated median.\ntemperature_data # VALUE_IF_FALSE: Keep the original temperature value.\n)\n\n# TASK: Print the total number of replaced values.\nimputed_count = (status_codes == 3).sum()\nprint(f”Total Faulty readings imputed: {imputed_count}”)\n```\n\n**Output:**\nmarkup\n\n```\nTotal Faulty readings imputed: 20102\n```\n\nI didn’t expect the missing values to be this much. It probably affected our reading above in some way. Good thing, we managed to replace them in seconds.\nNow, let’s verify the fix by checking the median for both the original and cleaned data\npython\n\n```\n# TASK: Print the change in the overall mean or median to show the impact of the cleaning.\nprint(f”\\nOriginal Median: {np.median(temperature_data):.2f}°C”)\nprint(f”Cleaned Median: {np.median(cleaned_temperature_data):.2f}°C”)\n```\n\n**Output:**\nmarkup\n\n```\nOriginal Median: 44.99°CCleaned Median: 44.99°C\n```\n\nIn this case, even after cleaning over 20,000 faulty records, the median temperature remained steady at **44.99°C,** indicating that the dataset is statistically sound and balanced.\nLet’s present this to the client:\n> “Out of one million temperature readings, **20,102** were marked as faulty (status code = 3). Instead of removing these faulty records, we replaced them with the **median temperature value (≈ 45°C)** — a standard data-cleaning approach that keeps the dataset consistent without distorting the trend.  \n> Interestingly, the **median temperature remained unchanged (44.99°C)** before and after cleaning. That’s a good sign: it means the faulty readings didn’t skew the dataset, and the replacement didn’t alter the overall data distribution.”\n## Conclusion\nAnd there we go! We initiated this project to address a critical issue for **EnviroTech Dynamics** : the need for faster, loop-free data analysis. The power of NumPy arrays and vectorisation allowed us to fix the problem and future-proof their analytical pipeline.\nNumPy ndarray is the silent engine of the entire Python data science ecosystem. Every major library, like **Pandas** , **scikit-learn** , **TensorFlow** , and **PyTorch,** uses NumPy arrays at its core for fast numerical computation.\nBy mastering NumPy, you’ve built a powerful analytical foundation. The next logical step for me is to move from single arrays to structured analysis with the Pandas library, which organises NumPy arrays into tables (DataFrames) for even easier labelling and manipulation.\nThanks for reading! Feel free to connect with me:\n[Medium](https://medium.com/@ibbysalam)\n[LinkedIn](https://www.linkedin.com/in/ibrahim-salami-059863228/)\n[Twitter](https://x.com/IbbySalam)\n[YouTube](https://www.youtube.com/@ibbysalam)\n## Register Now to Continue Reading\n### Unlock Towards Data Science with a Free Account\nAll articles on Towards Data Science are available to registered users. Create a free account today to access this article and thousands more.\nRegister for freeSign in to your account\n* * *\n![](../images/body-542334df68a32cd56c4a.jpeg)\nWritten By\n## [Ibrahim Salami](https://towardsdatascience.com/author/ibrahim.salami/)\n[See all from Ibrahim Salami](https://towardsdatascience.com/author/ibrahim.salami/)\n[Deep Dives](https://towardsdatascience.com/tag/deep-dives/)[Big Data](https://towardsdatascience.com/tag/big-data/)[Data Analytics](https://towardsdatascience.com/tag/data-analytics/)[Numpy](https://towardsdatascience.com/tag/numpy/)[Numpy Array](https://towardsdatascience.com/tag/numpy-array/)[Python](https://towardsdatascience.com/tag/python/)\nShare This Article\n  * [](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Ftowardsdatascience.com%2Fnumpy-for-absolute-beginners-a-project-based-approach-to-data-analysis%2F&title=NumPy%20for%20Absolute%20Beginners%3A%20A%20Project-Based%20Approach%20to%20Data%C2%A0Analysis)\n  * [](https://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Ftowardsdatascience.com%2Fnumpy-for-absolute-beginners-a-project-based-approach-to-data-analysis%2F&title=NumPy%20for%20Absolute%20Beginners%3A%20A%20Project-Based%20Approach%20to%20Data%C2%A0Analysis)\n  * [](https://x.com/share?url=https%3A%2F%2Ftowardsdatascience.com%2Fnumpy-for-absolute-beginners-a-project-based-approach-to-data-analysis%2F&text=NumPy%20for%20Absolute%20Beginners%3A%20A%20Project-Based%20Approach%20to%20Data%C2%A0Analysis)\n\n\nTowards Data Science is a community publication. Submit your insights to reach our global audience and earn through the TDS Author Payment Program.\n[Write for TDS](https://towardsdatascience.com/submissions/)\n## Related Articles\n  * [![](../images/002.jpg)](https://towardsdatascience.com/my-medium-journey-as-a-data-scientist-6-months-18-articles-and-3-000-followers-c449306e45f7/)\n## [My Medium Journey as a Data Scientist: 6 Months, 18 Articles, and 3,000 Followers](https://towardsdatascience.com/my-medium-journey-as-a-data-scientist-6-months-18-articles-and-3-000-followers-c449306e45f7/)\n[Data Science](https://towardsdatascience.com/category/data-science/)\nReal numbers, earnings, and data-driven growth strategy for Medium writers\n[Yu Dong](https://towardsdatascience.com/author/ydong029/)\nNovember 11, 20249 min read\n  * [![](../images/003.png)](https://towardsdatascience.com/transfer-learning-using-pre-trained-alexnet-model-and-fashion-mnist-43898c2966fb/)\n## [Transfer Learning using Pre-Trained AlexNet Model and Fashion-MNIST](https://towardsdatascience.com/transfer-learning-using-pre-trained-alexnet-model-and-fashion-mnist-43898c2966fb/)\n[Data Science](https://towardsdatascience.com/category/data-science/)\nBuilding CNN classifiers in Apache MxNet Gluon framework to classify articles of clothing\n[Andrea Yoss](https://towardsdatascience.com/author/andrea-yoss/)\nDecember 16, 202010 min read\n  * [![](../images/004.png)](https://towardsdatascience.com/vectorization-in-python-46486819d3a/)\n## [Vectorization in Python](https://towardsdatascience.com/vectorization-in-python-46486819d3a/)\n[Artificial Intelligence](https://towardsdatascience.com/category/artificial-intelligence/)\nPyTrix#1: Speeding up our Python Code\n[Kurtis Pykes](https://towardsdatascience.com/author/kurtispykes/)\nMay 7, 20204 min read\n  * [![](../images/005.jpg)](https://towardsdatascience.com/add-a-customized-rasa-chatbot-for-your-facebook-page-9313687fbdcb/)\n## [Add a Customized Rasa Chatbot for Your Facebook Page](https://towardsdatascience.com/add-a-customized-rasa-chatbot-for-your-facebook-page-9313687fbdcb/)\n[NLP](https://towardsdatascience.com/category/artificial-intelligence/nlp/)\nA simple walkthrough for setting up a Rasa chatbot for your Facebook page\n[Ikshura Tachintha](https://towardsdatascience.com/author/ikshura/)\nJuly 27, 20217 min read\n  * [![](https://towardsdatascience.com/images/fallback-image.jpg)](https://towardsdatascience.com/3-most-asked-python-interview-questions-for-data-scientists-1a2ad63ebe56/)\n## [3 Most Asked Python Interview Questions for Data Scientists](https://towardsdatascience.com/3-most-asked-python-interview-questions-for-data-scientists-1a2ad63ebe56/)\n[Data Science](https://towardsdatascience.com/category/data-science/)\nTop python interview questions for data scientists\n[Alexandros Zenonos, PhD](https://towardsdatascience.com/author/azenresearchlabs/)\nAugust 16, 20204 min read\n  * [![](../images/007.jpeg)](https://towardsdatascience.com/extreme-value-theory-in-a-nutshell-with-various-applications-3260b6a84316/)\n## [Extreme Value Theory in a Nutshell with Various Applications](https://towardsdatascience.com/extreme-value-theory-in-a-nutshell-with-various-applications-3260b6a84316/)\n[Coding](https://towardsdatascience.com/category/programming/coding/)\nIn the beginning when statistics was discovered to answer questions related to gambling win chances in the 18th century, normal...\n[Hanan Ahmed](https://towardsdatascience.com/author/hanan-ahmed/)\nFebruary 19, 20218 min read\n  * [![](../images/008.jpg)](https://towardsdatascience.com/data-science-write-robust-python-with-static-typing-c71b9c9c8044/)\n## [Data Science: Write Robust Python With Static Typing](https://towardsdatascience.com/data-science-write-robust-python-with-static-typing-c71b9c9c8044/)\n[Artificial Intelligence](https://towardsdatascience.com/category/artificial-intelligence/)\nUpdated for Python 3.11\n[Nikos Kafritsas](https://towardsdatascience.com/author/nikoskafritsas/)\nJuly 27, 20227 min read\n  * [![](../images/009.jpg)](https://towardsdatascience.com/from-static-to-dynamic-skills-a-different-model-for-agent-knowledge/)\n## [From Static to Dynamic Skills: A Different Model for Agent Knowledge](https://towardsdatascience.com/from-static-to-dynamic-skills-a-different-model-for-agent-knowledge/)\n[Agentic AI](https://towardsdatascience.com/category/artificial-intelligence/agentic-ai/)\nWhy the skill-inflation panic is aimed at the wrong thing, and what it costs to make agent knowledge a build artifact instead of a file.\n[Tomer Mesika](https://towardsdatascience.com/author/tomer-mesika-tds/)\nSeptember 14, 202614 min read\n  * [![](../images/010.jpg)](https://towardsdatascience.com/how-to-negotiate-your-salary-as-a-data-scientist-4c6ce176b2a5/)\n## [How to Negotiate Your Salary as a Data Scientist](https://towardsdatascience.com/how-to-negotiate-your-salary-as-a-data-scientist-4c6ce176b2a5/)\n[Data Science](https://towardsdatascience.com/category/data-science/)\nAnd how much I made my first year\n[Haden Pelletier](https://towardsdatascience.com/author/pelletierhaden/)\nOctober 27, 20246 min read\n\n\n  * [YouTube](https://www.youtube.com/c/TowardsDataScience)\n  * [X](https://x.com/TDataScience)\n  * [LinkedIn](https://www.linkedin.com/company/towards-data-science/)\n  * [Threads](https://www.threads.net/@towardsdatascience)\n  * [Bluesky](https://bsky.app/profile/towardsdatascience.com)\n\n\n[](https://towardsdatascience.com/)\nYour home for data science and AI. The world's leading publication for data science, data analytics, data engineering, machine learning, and artificial intelligence professionals.\nSubscribe to Our Newsletter[Write For TDS](https://towardsdatascience.com/submissions/)•[About](https://towardsdatascience.com/about-towards-data-science-d691af11cc2f/)•[Advertise](https://contact.towardsdatascience.com/advertise-with-towards-data-science)•[Privacy Policy](https://towardsdatascience.com/privacy-policy/)•[Terms of Use](https://towardsdatascience.com/website-terms-of-use/)\n© Insight Media Group, LLC 2026•[The New Stack](https://thenewstack.io)•[roadmap.sh](https://roadmap.sh)•[Creator Network](https://insightmediagroup.io/creator-network)\n####  Recommended Articles \nClose\n  * [ ![](https://h030.towardsdatascience.com/rest/v2/contentStores/d7d3a4ab-7caf-4383-bbd2-fbf7fb4f1787/items/4970/image?etag=1780565225463&width=500&height=500) Productivity Tips, Data Career Insights, and Other Recent Must-Reads ](https://towardsdatascience.com/productivity-tips-data-career-insights-and-other-recent-must-reads-5c47eb7a2fe0/ \"Productivity Tips, Data Career Insights, and Other Recent Must-Reads\")\n  * [ ![](https://h030.towardsdatascience.com/rest/v2/contentStores/d7d3a4ab-7caf-4383-bbd2-fbf7fb4f1787/items/607639/image?etag=1781250125848&width=500&height=500) Javascript Fatigue: HTMX Is All You Need to Build ChatGPT — Part 1 ](https://towardsdatascience.com/javascript-fatigue-you-dont-need-js-to-build-chatgpt/ \"Javascript Fatigue: HTMX Is All You Need to Build ChatGPT — Part 1\")\n  * [ ![](https://h030.towardsdatascience.com/rest/v2/contentStores/d7d3a4ab-7caf-4383-bbd2-fbf7fb4f1787/items/607930/image?etag=1782124566054&width=500&height=500) The Subset Sum Problem Solved in Linear Time for Dense Enough Inputs ](https://towardsdatascience.com/subset-sum-problem-solved-in-linear-time-for-dense-enough-inputs/ \"The Subset Sum Problem Solved in Linear Time for Dense Enough Inputs\")\n  * [ ![](https://h030.towardsdatascience.com/rest/v2/contentStores/d7d3a4ab-7caf-4383-bbd2-fbf7fb4f1787/items/3660/image?etag=1780176246070&width=500&height=500) Does Your Company Have a Data Strategy? ](https://towardsdatascience.com/does-your-company-have-a-data-strategy-e8944dbec4ae/ \"Does Your Company Have a Data Strategy?\")\n\n\n",
  "metadata": {
    "title": "NumPy for Absolute Beginners: A Project-Based Approach to Data Analysis | Towards Data Science",
    "description": "Build a high-performance sensor data pipeline from scratch and unlock the true speed of Python's scientific computing core",
    "keywords": null,
    "author": "Ibrahim Salami",
    "og:locale": "en_US",
    "og:type": "article",
    "og:title": "NumPy for Absolute Beginners: A Project-Based Approach to Data Analysis",
    "og:description": "Build a high-performance sensor data pipeline from scratch and unlock the true speed of Python's scientific computing core",
    "og:url": "https://towardsdatascience.com/numpy-for-absolute-beginners-a-project-based-approach-to-data-analysis/",
    "og:site_name": "Towards Data Science",
    "og:image": "https://assets.insightmediagroup.io/media/wp-content/uploads/2025/11/Screenshot-2025-11-03-141455.jpg",
    "og:image:width": "926",
    "og:image:height": "548",
    "og:image:type": "image/jpeg",
    "twitter:card": "summary_large_image",
    "twitter:site": "@TDataScience",
    "twitter:creator": "@TDataScience",
    "twitter:label1": "Written by",
    "twitter:data1": "Ibrahim Salami",
    "twitter:label2": "Est. reading time",
    "twitter:data2": "13 min read",
    "article:published_time": "2025-11-04T15:29:45.000Z",
    "article:modified_time": "2025-11-04T15:29:45.000Z",
    "article:author": "https://towardsdatascience.com/author/ibrahim.salami/"
  },
  "paywall": {
    "listed_paid": false,
    "detected": false,
    "marker": "",
    "public_only": false,
    "policy": "付费/会员内容只保留页面公开可见部分，不绕过付费墙"
  },
  "crawl": {
    "success": true,
    "status_code": 202,
    "error": ""
  },
  "code_blocks": [
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_000.txt",
      "chars": 481
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_001.txt",
      "chars": 118
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_002.txt",
      "chars": 296
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_003.txt",
      "chars": 145
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_004.txt",
      "chars": 100
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_005.txt",
      "chars": 236
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_006.txt",
      "chars": 29
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_007.txt",
      "chars": 159
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_008.txt",
      "chars": 108
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_009.txt",
      "chars": 238
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_010.txt",
      "chars": 19
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_011.txt",
      "chars": 614
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_012.txt",
      "chars": 146
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_013.txt",
      "chars": 381
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_014.txt",
      "chars": 130
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_015.txt",
      "chars": 305
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_016.txt",
      "chars": 12
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_017.txt",
      "chars": 185
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_018.txt",
      "chars": 34
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_019.txt",
      "chars": 352
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_020.txt",
      "chars": 56
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_021.txt",
      "chars": 415
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_022.txt",
      "chars": 130
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_023.txt",
      "chars": 364
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_024.txt",
      "chars": 38
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_025.txt",
      "chars": 453
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_026.txt",
      "chars": 37
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_027.txt",
      "chars": 226
    },
    {
      "language": "txt",
      "file": "attachments/51c06ef2bde2/code/block_028.txt",
      "chars": 48
    }
  ],
  "images": [
    {
      "status": "ok",
      "url": "https://towardsdatascience.com/images/fallback-image.jpg",
      "bytes": 5092,
      "reused": true,
      "local_path": "attachments/51c06ef2bde2/images/body-63beb50f664a055ed739.jpg",
      "src": "https://towardsdatascience.com/images/fallback-image.jpg",
      "alt": "",
      "downloaded": true,
      "discovery": "saved_markdown"
    },
    {
      "status": "http_404",
      "url": "https://h030.towardsdatascience.com/rest/v2/contentStores/d7d3a4ab-7caf-4383-bbd2-fbf7fb4f1787/items/4970/image?etag=1780565225463&width=500&height=500",
      "src": "https://h030.towardsdatascience.com/rest/v2/contentStores/d7d3a4ab-7caf-4383-bbd2-fbf7fb4f1787/items/4970/image?etag=1780565225463&width=500&height=500",
      "alt": "",
      "downloaded": false,
      "discovery": "saved_markdown",
      "retried_at": "2026-10-20T17:49:33Z"
    },
    {
      "status": "http_404",
      "url": "https://h030.towardsdatascience.com/rest/v2/contentStores/d7d3a4ab-7caf-4383-bbd2-fbf7fb4f1787/items/607639/image?etag=1781250125848&width=500&height=500",
      "src": "https://h030.towardsdatascience.com/rest/v2/contentStores/d7d3a4ab-7caf-4383-bbd2-fbf7fb4f1787/items/607639/image?etag=1781250125848&width=500&height=500",
      "alt": "",
      "downloaded": false,
      "discovery": "saved_markdown",
      "retried_at": "2026-10-20T17:49:33Z"
    },
    {
      "status": "http_404",
      "url": "https://h030.towardsdatascience.com/rest/v2/contentStores/d7d3a4ab-7caf-4383-bbd2-fbf7fb4f1787/items/607930/image?etag=1782124566054&width=500&height=500",
      "src": "https://h030.towardsdatascience.com/rest/v2/contentStores/d7d3a4ab-7caf-4383-bbd2-fbf7fb4f1787/items/607930/image?etag=1782124566054&width=500&height=500",
      "alt": "",
      "downloaded": false,
      "discovery": "saved_markdown",
      "retried_at": "2026-10-20T17:49:33Z"
    },
    {
      "status": "http_404",
      "url": "https://h030.towardsdatascience.com/rest/v2/contentStores/d7d3a4ab-7caf-4383-bbd2-fbf7fb4f1787/items/3660/image?etag=1780176246070&width=500&height=500",
      "src": "https://h030.towardsdatascience.com/rest/v2/contentStores/d7d3a4ab-7caf-4383-bbd2-fbf7fb4f1787/items/3660/image?etag=1780176246070&width=500&height=500",
      "alt": "",
      "downloaded": false,
      "discovery": "saved_markdown",
      "retried_at": "2026-10-20T17:49:33Z"
    }
  ],
  "audio": [],
  "videos": [
    {
      "url": "https://www.youtube.com/@ibbysalam",
      "kind": "channel_reference",
      "status": "reference_only"
    },
    {
      "url": "https://www.youtube.com/c/TowardsDataScience",
      "kind": "channel_reference",
      "status": "reference_only"
    }
  ],
  "links": [
    {
      "type": "internal",
      "href": "https://towardsdatascience.com/"
    },
    {
      "type": "internal",
      "href": "https://towardsdatascience.com/latest/"
    },
    {
      "type": "internal",
      "href": "https://towardsdatascience.com/tag/editors-pick/"
    },
    {
      "type": "internal",
      "href": "https://towardsdatascience.com/tag/the-variable/"
    },
    {
      "type": "internal",
      "href": "https://towardsdatascience.com/shipai/"
    },
    {
      "type": "internal",
      "href": "https://towardsdatascience.com/submissions/"
    },
    {
      "type": "internal",
      "href": "https://towardsdatascience.com/category/data-science/"
    },
    {
      "type": "internal",
      "href": "https://towardsdatascience.com/author/ibrahim.salami/"
    },
    {
      "type": "internal",
      "href": "https://towardsdatascience.com/using-numpy-to-analyze-my-daily-habits-sleep-screen-time-mood/"
    },
    {
      "type": "internal",
      "href": "https://towardsdatascience.com/hidden-gems-in-numpy-7-functions-every-data-scientist-should-know/"
    },
    {
      "type": "internal",
      "href": "https://towardsdatascience.com/tag/deep-dives/"
    },
    {
      "type": "internal",
      "href": "https://towardsdatascience.com/tag/big-data/"
    },
    {
      "type": "internal",
      "href": "https://towardsdatascience.com/tag/data-analytics/"
    },
    {
      "type": "internal",
      "href": "https://towardsdatascience.com/tag/numpy/"
    },
    {
      "type": "internal",
      "href": "https://towardsdatascience.com/tag/numpy-array/"
    },
    {
      "type": "internal",
      "href": "https://towardsdatascience.com/tag/python/"
    },
    {
      "type": "internal",
      "href": "https://towardsdatascience.com/my-medium-journey-as-a-data-scientist-6-months-18-articles-and-3-000-followers-c449306e45f7/"
    },
    {
      "type": "internal",
      "href": "https://towardsdatascience.com/author/ydong029/"
    },
    {
      "type": "internal",
      "href": "https://towardsdatascience.com/transfer-learning-using-pre-trained-alexnet-model-and-fashion-mnist-43898c2966fb/"
    },
    {
      "type": "internal",
      "href": "https://towardsdatascience.com/author/andrea-yoss/"
    },
    {
      "type": "external",
      "href": "https://write.insightmediagroup.io"
    },
    {
      "type": "external",
      "href": "https://www.linkedin.com/company/towards-data-science/"
    },
    {
      "type": "external",
      "href": "https://x.com/TDataScience"
    },
    {
      "type": "external",
      "href": "https://roadmap.sh/ai-data-scientist"
    },
    {
      "type": "external",
      "href": "https://medium.com/@ibbysalam"
    },
    {
      "type": "external",
      "href": "https://www.linkedin.com/in/ibrahim-salami-059863228/"
    },
    {
      "type": "external",
      "href": "https://x.com/IbbySalam"
    },
    {
      "type": "external",
      "href": "https://www.youtube.com/@ibbysalam"
    },
    {
      "type": "external",
      "href": "https://www.facebook.com/sharer/sharer.php?title=NumPy+for+Absolute+Beginners%3A+A+Project-Based+Approach+to+Data%C2%A0Analysis&u=https%3A%2F%2Ftowardsdatascience.com%2Fnumpy-for-absolute-beginners-a-project-based-approach-to-data-analysis%2F"
    },
    {
      "type": "external",
      "href": "https://www.linkedin.com/shareArticle?mini=true&title=NumPy+for+Absolute+Beginners%3A+A+Project-Based+Approach+to+Data%C2%A0Analysis&url=https%3A%2F%2Ftowardsdatascience.com%2Fnumpy-for-absolute-beginners-a-project-based-approach-to-data-analysis%2F"
    },
    {
      "type": "external",
      "href": "https://x.com/share?text=NumPy+for+Absolute+Beginners%3A+A+Project-Based+Approach+to+Data%C2%A0Analysis&url=https%3A%2F%2Ftowardsdatascience.com%2Fnumpy-for-absolute-beginners-a-project-based-approach-to-data-analysis%2F"
    },
    {
      "type": "external",
      "href": "https://www.youtube.com/c/TowardsDataScience"
    },
    {
      "type": "external",
      "href": "https://www.threads.net/@towardsdatascience"
    },
    {
      "type": "external",
      "href": "https://bsky.app/profile/towardsdatascience.com"
    },
    {
      "type": "external",
      "href": "https://thenewstack.io"
    },
    {
      "type": "external",
      "href": "https://roadmap.sh"
    },
    {
      "type": "external",
      "href": "https://insightmediagroup.io/creator-network"
    }
  ],
  "repair_version": 2,
  "repaired_at": "2026-10-20T17:27:02Z",
  "source_url": "https://towardsdatascience.com/numpy-for-absolute-beginners-a-project-based-approach-to-data-analysis/",
  "delivery_status": "unverified",
  "discovery_status": "http_403",
  "missing_reason": "源页面未重新核验:http_403；已按保留正文补采图片",
  "repair_error": "",
  "actual_video_files": [],
  "expected_saved_body_images": 5,
  "image_discovery": "saved_markdown",
  "source_body_markdown": "![Revisit consent button](https://cdn-cookieyes.com/assets/images/revisit.svg)\nWe value your privacy\nWe use cookies to enhance your browsing experience, serve personalised ads or content, and analyse our traffic. By clicking \"Accept All\", you consent to our use of cookies.\nCustomise Reject All Accept All\nCustomise Consent Preferences ![](https://cdn-cookieyes.com/assets/images/close.svg)\nWe use cookies to help you navigate efficiently and perform certain functions. You will find detailed information about all cookies under each consent category below.\nThe cookies that are categorised as \"Necessary\" are stored on your browser as they are essential for enabling the basic functionalities of the site. ... Show more\nNecessaryAlways Active\nNecessary cookies are required to enable the basic features of this site, such as providing secure log-in or adjusting your consent preferences. These cookies do not store any personally identifiable data.\n  * Cookie\nBCTempID\n  * Duration\n10 minutes\n  * Description\nNo description available.\n\n\n  * Cookie\n__cf_bm\n  * Duration\n1 hour\n  * Description\nThis cookie, set by Cloudflare, is used to support Cloudflare Bot Management. \n\n\n  * Cookie\nAWSALBCORS\n  * Duration\n7 days\n  * Description\nAmazon Web Services set this cookie for load balancing.\n\n\n  * Cookie\n_cfuvid\n  * Duration\nsession\n  * Description\nCloudflare sets this cookie to track users across sessions to optimize user experience by maintaining session consistency and providing personalized services\n\n\n  * Cookie\nli_gc\n  * Duration\n6 months\n  * Description\nLinkedin set this cookie for storing visitor's consent regarding using cookies for non-essential purposes.\n\n\n  * Cookie\n__hssrc\n  * Duration\nsession\n  * Description\nThis cookie is set by Hubspot whenever it changes the session cookie. The __hssrc cookie set to 1 indicates that the user has restarted the browser, and if the cookie does not exist, it is assumed to be a new session.\n\n\n  * Cookie\n__hssc\n  * Duration\n1 hour\n  * Description\nHubSpot sets this cookie to keep track of sessions and to determine if HubSpot should increment the session number and timestamps in the __hstc cookie.\n\n\n  * Cookie\nwpEmojiSettingsSupports\n  * Duration\nsession\n  * Description\nWordPress sets this cookie when a user interacts with emojis on a WordPress site. It helps determine if the user's browser can display emojis properly.\n\n\n  * Cookie\nBCSessionID\n  * Duration\n1 year 1 month 4 days\n  * Description\nBlueconic sets this cookie as a unique identifier for the BlueConic profile.\n\n\n  * Cookie\n_octo\n  * Duration\n1 year\n  * Description\nNo description available.\n\n\n  * Cookie\nlogged_in\n  * Duration\n1 year\n  * Description\nNo description available.\n\n\n  * Cookie\n__Secure-YEC\n  * Duration\npast\n  * Description\nYouTube sets this cookie to stores the user's video player preferences using embedded YouTube video\n\n\n  * Cookie\n__eoi\n  * Duration\n6 months\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\nAWSALBTGCORS\n  * Duration\n7 days\n  * Description\nNo description available.\n\n\n  * Cookie\nlogin-status-p\n  * Duration\npast\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\nAWSALBTG\n  * Duration\n7 days\n  * Description\nNo description available.\n\n\n  * Cookie\ncsrf_token\n  * Duration\nsession\n  * Description\nNo description available.\n\n\n  * Cookie\ntoken_v2\n  * Duration\n1 day\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\nD\n  * Duration\n1 year\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\nPHPSESSID\n  * Duration\nsession\n  * Description\nThis cookie is native to PHP applications. The cookie stores and identifies a user's unique session ID to manage user sessions on the website. The cookie is a session cookie and will be deleted when all the browser windows are closed.\n\n\n  * Cookie\nVISITOR_PRIVACY_METADATA\n  * Duration\n6 months\n  * Description\nYouTube sets this cookie to store the user's cookie consent state for the current domain. \n\n\n  * Cookie\ncookietest\n  * Duration\nsession\n  * Description\nThe cookietest cookie is typically used to determine whether the user's browser accepts cookies, essential for website functionality and user experience.\n\n\n  * Cookie\n__Host-airtable-session\n  * Duration\n1 year\n  * Description\nThis cookie is used to enable us to integrate the services of Airtable.\n\n\n  * Cookie\n__Host-airtable-session.sig\n  * Duration\n1 year\n  * Description\nThis cookie is used to enable us to integrate the services of Airtable.\n\n\n  * Cookie\nm\n  * Duration\n1 year 1 month 4 days\n  * Description\nStripe sets this cookie for fraud prevention purposes. It identifies the device used to access the website, allowing the website to be formatted accordingly.\n\n\n  * Cookie\nBIGipServer*\n  * Duration\nsession\n  * Description\nMarketo sets this cookie to collect information about the user's online activity and build a profile about their interests to provide advertisements relevant to the user. \n\n\n  * Cookie\n__cfruid\n  * Duration\nsession\n  * Description\nCloudflare sets this cookie to identify trusted web traffic.\n\n\n  * Cookie\n_GRECAPTCHA\n  * Duration\n6 months\n  * Description\nGoogle Recaptcha service sets this cookie to identify bots to protect the website against malicious spam attacks.\n\n\n  * Cookie\n__Secure-YNID\n  * Duration\n6 months\n  * Description\nGoogle cookie used to protect user security and prevent fraud, especially during the login process.\n\n\n  * Cookie\ncookieyes-consent\n  * Duration\n1 year\n  * Description\nCookieYes sets this cookie to remember users' consent preferences so that their preferences are respected on subsequent visits to this site. It does not collect or store any personal information about the site visitors.\n\n\nFunctional\nFunctional cookies help perform certain functionalities like sharing the content of the website on social media platforms, collecting feedback, and other third-party features.\n  * Cookie\nlidc\n  * Duration\n1 day\n  * Description\nLinkedIn sets the lidc cookie to facilitate data center selection.\n\n\n  * Cookie\nbrw\n  * Duration\n1 year\n  * Description\nNo description available.\n\n\n  * Cookie\nbrwConsent\n  * Duration\n5 minutes\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\nWMF-Uniq\n  * Duration\n1 year\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\nloom_anon_comment\n  * Duration\n1 year\n  * Description\nNo description available.\n\n\n  * Cookie\nloom_referral_video\n  * Duration\nsession\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\nVISITOR_INFO1_LIVE\n  * Duration\n6 months\n  * Description\nA cookie set by YouTube to measure bandwidth that determines whether the user gets the new or old player interface.\n\n\n  * Cookie\nyt-remote-connected-devices\n  * Duration\nNever Expires\n  * Description\nYouTube sets this cookie to store the user's video preferences using embedded YouTube videos.\n\n\n  * Cookie\nytidb::LAST_RESULT_ENTRY_KEY\n  * Duration\nNever Expires\n  * Description\nThe cookie ytidb::LAST_RESULT_ENTRY_KEY is used by YouTube to store the last search result entry that was clicked by the user. This information is used to improve the user experience by providing more relevant search results in the future.\n\n\n  * Cookie\nyt-remote-device-id\n  * Duration\nNever Expires\n  * Description\nYouTube sets this cookie to store the user's video preferences using embedded YouTube videos.\n\n\n  * Cookie\nyt-remote-session-name\n  * Duration\nsession\n  * Description\nThe yt-remote-session-name cookie is used by YouTube to store the user's video player preferences using embedded YouTube video.\n\n\n  * Cookie\nyt-remote-fast-check-period\n  * Duration\nsession\n  * Description\nThe yt-remote-fast-check-period cookie is used by YouTube to store the user's video player preferences for embedded YouTube videos.\n\n\n  * Cookie\nyt-remote-session-app\n  * Duration\nsession\n  * Description\nThe yt-remote-session-app cookie is used by YouTube to store user preferences and information about the interface of the embedded YouTube video player.\n\n\n  * Cookie\nyt-remote-cast-available\n  * Duration\nsession\n  * Description\nThe yt-remote-cast-available cookie is used to store the user's preferences regarding whether casting is available on their YouTube video player.\n\n\n  * Cookie\nyt-remote-cast-installed\n  * Duration\nsession\n  * Description\nThe yt-remote-cast-installed cookie is used to store the user's video player preferences using embedded YouTube video.\n\n\n  * Cookie\ncp_session\n  * Duration\n3 months\n  * Description\nCodepen sets this cookie for Help systems found in the website.\n\n\n  * Cookie\nloid\n  * Duration\n1 year 1 month 4 days\n  * Description\nThis cookie is set by the Reddit. The cookie enables the sharing of content from the website onto the social media platform.\n\n\nAnalytics\nAnalytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics such as the number of visitors, bounce rate, traffic source, etc.\n  * Cookie\n__hstc\n  * Duration\n6 months\n  * Description\nHubspot set this main cookie for tracking visitors. It contains the domain, initial timestamp (first visit), last timestamp (last visit), current timestamp (this visit), and session number (increments for each subsequent session).\n\n\n  * Cookie\nhubspotutk\n  * Duration\n6 months\n  * Description\nHubSpot sets this cookie to keep track of the visitors to the website. This cookie is passed to HubSpot on form submission and used when deduplicating contacts.\n\n\n  * Cookie\n_ga\n  * Duration\n1 year 1 month 4 days\n  * Description\nGoogle Analytics sets this cookie to calculate visitor, session and campaign data and track site usage for the site's analytics report. The cookie stores information anonymously and assigns a randomly generated number to recognise unique visitors.\n\n\n  * Cookie\n_ga_*\n  * Duration\n1 year 1 month 4 days\n  * Description\nGoogle Analytics sets this cookie to store and count page views.\n\n\n  * Cookie\n__Host-psifi.analyticsTrace\n  * Duration\n6 hours\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\n__Host-psifi.analyticsTraceV2\n  * Duration\n6 hours\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\n_gh_sess\n  * Duration\nsession\n  * Description\nGitHub sets this cookie for temporary application and framework state between pages like what step the user is on in a multiple step form.\n\n\n  * Cookie\nYSC\n  * Duration\nsession\n  * Description\nYSC cookie is set by Youtube and is used to track the views of embedded videos on Youtube pages.\n\n\n  * Cookie\najs_anonymous_id\n  * Duration\n1 year\n  * Description\nThis cookie is set by Segment to count the number of people who visit a certain site by tracking if they have visited before.\n\n\n  * Cookie\nvuid\n  * Duration\n1 year 1 month 4 days\n  * Description\nVimeo installs this cookie to collect tracking information by setting a unique ID to embed videos on the website. \n\n\nPerformance\nPerformance cookies are used to understand and analyse the key performance indexes of the website which helps in delivering a better user experience for the visitors.\n  * Cookie\nAWSALB\n  * Duration\n7 days\n  * Description\nAWSALB is an application load balancer cookie set by Amazon Web Services to map the session to the target.\n\n\n  * Cookie\nacq\n  * Duration\npast\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\nacq.sig\n  * Duration\npast\n  * Description\nDescription is currently not available.\n\n\n  * Cookie\nptc\n  * Duration\n2 years\n  * Description\nNo description available.\n\n\nAdvertisement\nAdvertisement cookies are used to provide visitors with customised advertisements based on the pages you visited previously and to analyse the effectiveness of the ad campaigns.\n  * Cookie\nmuc_ads\n  * Duration\n1 year 1 month 4 days\n  * Description\nTwitter sets this cookie to collect user behaviour and interaction data to optimize the website.\n\n\n  * Cookie\nguest_id_marketing\n  * Duration\n1 year 1 month 4 days\n  * Description\nTwitter sets this cookie to identify and track the website visitor.\n\n\n  * Cookie\nguest_id_ads\n  * Duration\n1 year 1 month 4 days\n  * Description\nTwitter sets this cookie to identify and track the website visitor.\n\n\n  * Cookie\npersonalization_id\n  * Duration\n1 year 1 month 4 days\n  * Description\nTwitter sets this cookie to integrate and share features for social media and also store information about how the user uses the website, for tracking and targeting.\n\n\n  * Cookie\nguest_id\n  * Duration\n1 year 1 month 4 days\n  * Description\nTwitter sets this cookie to identify and track the website visitor. It registers if a user is signed in to the Twitter platform and collects information about ad preferences.\n\n\n  * Cookie\nbcookie\n  * Duration\n1 year\n  * Description\nLinkedIn sets this cookie from LinkedIn share buttons and ad tags to recognize browser IDs.\n\n\n  * Cookie\n__Secure-ROLLOUT_TOKEN\n  * Duration\n6 months\n  * Description\nYouTube sets this cookie to manage feature rollout and experimentation. It helps Google control which new features or interface changes are shown to users as part of testing and staged rollouts, ensuring consistent experience for a given user during an experiment.\n\n\n  * Cookie\nyt.innertube::nextId\n  * Duration\nNever Expires\n  * Description\nYouTube sets this cookie to register a unique ID to store data on what videos from YouTube the user has seen.\n\n\n  * Cookie\nyt.innertube::requests\n  * Duration\nNever Expires\n  * Description\nYouTube sets this cookie to register a unique ID to store data on what videos from YouTube the user has seen.\n\n\n  * Cookie\nsession_tracker\n  * Duration\nsession\n  * Description\nThis cookie is set by the Reddit. This cookie is used to identify trusted web traffic. It also helps in adverstising on the website.\n\n\n  * Cookie\nedgebucket\n  * Duration\nsession\n  * Description\nReddit sets this cookie to save the information about a log-on Reddit user, for the purpose of advertisement recommendations and updating the content.\n\n\n  * Cookie\ndid\n  * Duration\n1 year\n  * Description\nArbor sets this cookie to show targeted ads to site visitors.This cookie expires after 2 months or 1 year.\n\n\nUncategorised\nOther uncategorised cookies are those that are being analysed and have not been classified into a category as yet.\nNo cookies to display.\nReject All Save My Preferences Accept All\nToggle Search[](https://towardsdatascience.com/)Toggle Mobile Navigation\n[](https://towardsdatascience.com/)\nPublish AI, ML & data-science insights to a global community of data professionals.\nSign in[Submit an Article](https://write.insightmediagroup.io)\n[Latest](https://towardsdatascience.com/latest/)[Editor's Picks](https://towardsdatascience.com/tag/editors-pick/)[Newsletter](https://towardsdatascience.com/tag/the-variable/)[ShipAI](https://towardsdatascience.com/shipai/)\n* * *\n[Write For TDS](https://towardsdatascience.com/submissions/)\n[LinkedIn](https://www.linkedin.com/company/towards-data-science/)[X](https://x.com/TDataScience)Toggle Search\n[Data Science](https://towardsdatascience.com/category/data-science/)\n# NumPy for Absolute Beginners: A Project-Based Approach to Data Analysis\nBuild a high-performance sensor data pipeline from scratch and unlock the true speed of Python's scientific computing core\n[Ibrahim Salami](https://towardsdatascience.com/author/ibrahim.salami/)\nNovember 4, 202513 min read\n![](https://assets.insightmediagroup.io/media/wp-content/uploads/2025/11/Screenshot-2025-11-03-141455.jpg)\nTo learn NumPy, I’ve been running a series where I build mini projects. I’ve built a [Personal Habit](https://towardsdatascience.com/using-numpy-to-analyze-my-daily-habits-sleep-screen-time-mood/) and [Weather Analysis](https://towardsdatascience.com/hidden-gems-in-numpy-7-functions-every-data-scientist-should-know/) project. But I haven’t really gotten the chance to explore the full power and capability of NumPy. I want to try to understand why NumPy is so useful in data analysis. To wrap up this series, I’m going to be showcasing this in real time.\nI’ll be using a fictional client or company to make things interactive. In this case, our client is going to be**EnviroTech Dynamics** , a global operator of industrial sensor networks.\nCurrently, EnviroTech relies on outdated, loop-based Python scripts to process over **1 million sensor readings daily**. This process is agonizingly slow, delaying critical maintenance decisions and impacting operational efficiency. They need a modern, high-performance solution.\nI’ve been tasked with creating a NumPy-based proof-of-concept to demonstrate how to **turbocharge their data pipeline**.\nLearn this step by step with the interactive [AI and Data Scientist](https://roadmap.sh/ai-data-scientist) roadmap.\n## The Dataset: Simulated Sensor Readings\nTo prove the concept, I’ll be working with a large, simulated dataset generated using NumPy‘s random module, featuring entries with the following key arrays:\n  * Temperature —Each data point represents how hot a machine or system component is running. These readings can quickly help us detect when a machine starts overheating — a sign of possible failure, inefficiency, or safety risk.\n  * Pressure — data showing how much pressure is building up inside the system, and if it is within a safe range\n  * Status codes — represent the health or state of each machine or system at a given moment. 0 (Normal), 1 (Warning), 2 (Critical), 3 (Faulty/Missing).  \n\n\n\n## Project Objectives\nThe core goal is to provide four clear, vectorised solutions to EnviroTech’s data challenges, demonstrating speed and power. So I’ll be showcasing all of these:\n  * Performance and efficiency benchmark\n  * Foundational statistical baseline\n  * Critical anomaly detection and\n  * Data cleaning and imputation\n\n\nBy the end of this article, you should be able to get a full grasp of NumPy and its usefulness in data analysis.\n## Objective 1: Performance and Efficiency Benchmark\nFirst, we need a massive dataset to make the speed difference obvious. I’ll be using the **1,000,000 temperature readings** we planned earlier.\npython\n\n```\nimport numpy as np\n# Set the size of our data\nNUM_READINGS = 1_000_000\n\n# Generate the Temperature array (1 million random floating-point numbers)\n# We use a seed so the results are the same every time you run the code\nnp.random.seed(42)\nmean_temp = 45.0\nstd_dev_temp = 12.0\ntemperature_data = np.random.normal(loc=mean_temp, scale=std_dev_temp, size=NUM_READINGS)\n\nprint(f”Data array size: {temperature_data.size} elements”)\nprint(f”First 5 temperatures: {temperature_data[:5]}”)\n```\n\n**Output:**\ntext\n\n```\nData array size: 1000000 elements\nFirst 5 temperatures: [50.96056984 43.34082839 52.77226246 63.27635828 42.1901595 ]\n```\n\nNow that we have our records. Let’s check out the effectiveness of NumPy.\nAssuming we wanted to calculate the average of all these elements using a standard Python loop, it’ll go something like this.\npython\n\n```\n# Function using a standard Python loop\ndef calculate_mean_loop(data):\ntotal = 0\ncount = 0\nfor value in data:\ntotal += value\ncount += 1\nreturn total / count\n\n# Let’s run it once to make sure it works\nloop_mean = calculate_mean_loop(temperature_data)\nprint(f”Mean (Loop method): {loop_mean:.4f}”)\n```\n\nThere’s nothing wrong with this method. But it’s quite slow, because the computer has to process each number one by one, constantly moving between the Python interpreter and the CPU.\nTo truly showcase the speed, I’ll be using the`%timeit` command. This runs the code hundreds of times to provide a reliable average execution time.\npython\n\n```\n# Time the standard Python loop (will be slow)\nprint(“ — — Timing the Python Loop — -”)\n%timeit -n 10 -r 5 calculate_mean_loop(temperature_data)\n```\n\n**Output**\nmarkup\n\n```\n--- Timing the Python Loop ---244 ms ± 51.5 ms per loop (mean ± std. dev. of 5 runs, 10 loops each)\n```\n\nUsing the` -n 10`, I’m basically running the code in the loop 10 times (to get a stable average), and using the` -r 5`, the whole process will be repeated 5 times (for even more stability).\nNow, let’s compare this with NumPy vectorisation. And by vectorisation, it means the entire operation (average in this case) will be performed on the entire array at once, using highly optimised C code in the background.   \n\nHere’s how the average will be calculated using NumPy\npython\n\n```\n# Using the built-in NumPy mean function\ndef calculate_mean_numpy(data):\nreturn np.mean(data)\n# Let’s run it once to make sure it works\nnumpy_mean = calculate_mean_numpy(temperature_data)\nprint(f”Mean (NumPy method): {numpy_mean:.4f}”)\n```\n\n**Output:**\nmarkup\n\n```\nMean (NumPy method): 44.9808\n```\n\nNow let’s time it.\npython\n\n```\n# Time the NumPy vectorized function (will be fast)\nprint(“ — — Timing the NumPy Vectorization — -”)\n%timeit -n 10 -r 5 calculate_mean_numpy(temperature_data)\n```\n\n**Output:**\nmarkup\n\n```\n--- Timing the NumPy Vectorization ---1.49 ms ± 114 μs per loop (mean ± std. dev. of 5 runs, 10 loops each)\n```\n\nNow, that’s a huge difference. That’s like almost non-existent. That’s the power of vectorisation.\nLet's present this speed difference to the client:  \n\n> “We compared two methods for performing the same calculation on one million temperature readings — a traditional Python for-loop and a NumPy vectorized operation.\n> The difference was dramatic: The pure Python loop took about **244 milliseconds** per run while the NumPy version completed the same task in just **1.49 milliseconds**.\n> That’s roughly a **160× speed improvement**.”\n## Objective 2: Foundational Statistical Baseline\nAnother cool feature NumPy offers is the ability to perform basic to advanced statistics — this way, you can get a good overview of what’s going on in your dataset. It offers operations like:\n  * np.mean() — to calculate the average\n  * np.median — the middle value of the data\n  * np.std() — shows how spread out your numbers are from the average\n  * np.percentile() — tells you the value below which a certain percentage of your data falls.\n\n\nNow that we’ve managed to provide an alternative and efficient solution to retrieve and perform summaries and calculations on their huge dataset, we can start playing around with it.\nWe already managed to generate our simulated temperature data. Let’s do the same for pressure. Calculating pressure is a great way to demonstrate the ability of NumPy to handle multiple massive arrays in no time at all.\nFor our client, it also allows me to showcase a health check on their industrial systems.\nAlso, temperature and pressure are often related. A sudden pressure drop might be the cause of a spike in temperature, or vice versa. Calculating baselines for both allows us to see if they are drifting together or independently  \n\npython\n\n```\n# Generate the Pressure array (Uniform distribution between 100.0 and 500.0)\nnp.random.seed(43) # Use a different seed for a new dataset\npressure_data = np.random.uniform(low=100.0, high=500.0, size=1_000_000)\nprint(“Data arrays ready.”)\n```\n\n**Output:**\nmarkup\n\n```\nData arrays ready.\n```\n\nAlright, let’s begin our calculations.\npython\n\n```\nprint(“\\n — — Temperature Statistics — -”)\n# 1. Mean and Median\ntemp_mean = np.mean(temperature_data)\ntemp_median = np.median(temperature_data)\n\n# 2. Standard Deviation\ntemp_std = np.std(temperature_data)\n\n# 3. Percentiles (Defining the 90% Normal Range)\ntemp_p5 = np.percentile(temperature_data, 5) # 5th percentile\ntemp_p95 = np.percentile(temperature_data, 95) # 95th percentile\n\n# Formating our results\nprint(f”Mean (Average): {temp_mean:.2f}°C”)\nprint(f”Median (Middle): {temp_median:.2f}°C”)\nprint(f”Std. Deviation (Spread): {temp_std:.2f}°C”)\nprint(f”90% Normal Range: {temp_p5:.2f}°C to {temp_p95:.2f}°C”)\n```\n\n**Here’s the output:**\nmarkup\n\n```\n--- Temperature Statistics ---Mean (Average): 44.98°CMedian (Middle): 44.99°CStd. Deviation (Spread): 12.00°C90% Normal Range: 25.24°C to 64.71°C\n```\n\nSo to explain what you’re seeing here\n**The Mean (Average): 44.98°C** basically gives us a central point around which most readings are expected to fall. This is pretty cool because we don’t have to scan through the entire large dataset. With this number, I’ve gotten a pretty good idea of where our temperature readings usually fall.\n**The Median (Middle): 44.99°C** is quite identical to the mean if you notice. This tells us that there aren’t extreme outliers dragging the average too high or too low.\n**The standard deviation of 12°C** means the temperatures vary quite a bit from the average. Basically, some days are much hotter or cooler than others. A lower value (say 3°C or 4°C) would have suggested more consistency, but 12°C indicates a highly variable pattern.\nFor the **percentile** , it basically means most days hover between 25°C and 65°C,  \nIf I were to present this to the client, I could put it like this:\n> “On average, the system (or environment) maintains a temperature around **45°C** , which serves as a reliable baseline for typical operating or environmental conditions. A deviation of 12°C indicates that temperature levels fluctuate significantly around the average. \n> To put it simply, the readings are not very stable. Lastly, 90% of all readings fall between 25°C and 65°C. This gives a realistic picture of what “normal” looks like, helping you define acceptable thresholds for alerts or maintenance. To improve performance or reliability, we could identify the causes of high fluctuations (e.g., external heat sources, ventilation patterns, system load).”\nLet’s calculate for pressure also.\npython\n\n```\nprint(“\\n — — Pressure Statistics — -”)\n# Calculate all 5 measures for Pressure\npressure_stats = {\n“Mean”: np.mean(pressure_data),\n“Median”: np.median(pressure_data),\n“Std. Dev”: np.std(pressure_data),\n“5th %tile”: np.percentile(pressure_data, 5),\n“95th %tile”: np.percentile(pressure_data, 95),\n}\nfor label, value in pressure_stats.items():\nprint(f”{label:<12}: {value:.2f} kPa”)\n```\n\nTo improve our codebase, I’m storing all the calculations performed in a dictionary called pressure stats, and I’m simply looping over the key-value pairs.\n**Here’s the output:**\nmarkup\n\n```\n--- Pressure Statistics ---Mean : 300.09 kPaMedian : 300.04 kPaStd. Dev : 115.47 kPa5th %tile : 120.11 kPa95th %tile : 480.09 kPa\n```\n\nIf I were to present this to the client. It’d go something like this:  \n\n> “Our **pressure readings average around** **300 kilopascals** , and the median — the middle value — is almost the same. That tells us the pressure distribution is quite balanced overall. However, the **standard deviation is about 115 kPa** , which means there’s a lot of variation between readings. In other words, some readings are much higher or lower than the typical 300 kPa level.  \n> Looking at the **percentiles** , 90% of our readings fall between **120 and 480 kPa**. That’s a wide range, suggesting that pressure conditions are not stable — possibly fluctuating between low and high states during operation. So while the average looks fine, the variability could point to **inconsistent performance** or **environmental factors** affecting the system.”\n## Objective 3: Critical Anomaly Identification\nOne of my favourite features of NumPy is the ability to quickly identify and filter out anomalies in your dataset. To demonstrate this, our fictional client, EnviroTech Dynamics, provided us with another helpful array that contains system status codes. This tells us how the machine is consistently operating. It’s simply a range of codes (0–3).\n  * **0** → Normal\n  * **1** → Warning\n  * **2** → Critical\n  * **3** → Sensor Error  \n\n\n\nThey receive millions of readings per day, and our job is to find every machine that’s both in a critical state and running dangerously hot.  \nDoing this manually, or even with a loop, would take ages. This is where Boolean Indexing (masking) comes in. It lets us filter huge datasets in milliseconds by applying logical conditions directly to arrays, without loops.\nEarlier, we generated our temperature and pressure data. Let’s do the same for the status codes.\npython\n\n```\n# Reusing 'temperature_data' from earlier\nimport numpy as np\n\nnp.random.seed(42) # For reproducibility\n\nstatus_codes = np.random.choice(\na=[0, 1, 2, 3],\nsize=len(temperature_data),\np=[0.85, 0.10, 0.03, 0.02] # 0=Normal, 1=Warning, 2=Critical, 3=Offline\n)\n\n# Let’s preview our data\nprint(status_codes[:5])\n```\n\n**Output:**\nmarkup\n\n```\n[0 2 0 0 0]\n```\n\nEach temperature reading now has a matching status code. This allows us to pinpoint _which_ sensors report problems and _how severe_ they are.\nNext, we’ll need some sort of threshold or anomaly criteria. In most scenarios, anything above **mean + 3 × standard deviation** is considered a severe outlier, the kind of reading you don’t want in your system. To compute that\npython\n\n```\ntemp_mean = np.mean(temperature_data)\ntemp_std = np.std(temperature_data)\nSEVERITY_THRESHOLD = temp_mean + (3 * temp_std)\nprint(f”Severe Outlier Threshold: {SEVERITY_THRESHOLD:.2f}°C”)\n```\n\n**Output:**\nmarkup\n\n```\nSevere Outlier Threshold: 80.99°C\n```\n\nNext, we’ll create two filters (masks) to isolate data that meets our conditions. One for readings where the system status is Critical (code 2) and another for readings where the temperature exceeds the threshold.\npython\n\n```\n# Mask 1 — Readings where system status = Critical (code 2)\ncritical_status_mask = (status_codes == 2)\n\n# Mask 2 — Readings where temperature exceeds threshold\nhigh_temp_outlier_mask = (temperature_data > SEVERITY_THRESHOLD)\n\nprint(f”Critical status readings: {critical_status_mask.sum()}”)\nprint(f”High-temp outliers: {high_temp_outlier_mask.sum()}”)\n```\n\nHere’s what's going on behind the scenes. NumPy creates two arrays filled with True or False. Every True marks a reading that satisfies the condition. True will be represented as 1, and False will be represented as 0. Summing them quickly counts how many match.\nHere’s the output:\nmarkup\n\n```\nCritical status readings: 30178High-temp outliers: 1333\n```\n\nLet’s combine both anomalies before printing our final result. We want readings that are both critical and too hot. NumPy allows us to filter on multiple conditions using logical operators. In this case, we’ll be using the AND function represented as `&.`\npython\n\n```\n# Combine both conditions with a logical AND\ncritical_anomaly_mask = critical_status_mask & high_temp_outlier_mask\n\n# Extract actual temperatures of those anomalies\nextracted_anomalies = temperature_data[critical_anomaly_mask]\nanomaly_count = critical_anomaly_mask.sum()\n\nprint(“\\n — — Final Results — -”)\nprint(f”Total Critical Anomalies: {anomaly_count}”)\nprint(f”Sample Temperatures: {extracted_anomalies[:5]}”)\n```\n\n**Output:**\nmarkup\n\n```\n--- Final Results ---Total Critical Anomalies: 34Sample Temperatures: [81.9465697 81.11047892 82.23841531 86.65859372 81.146086 ]\n```\n\nLet’s present this to the client  \n\n> “After analyzing one million temperature readings, our system detected **34 critical anomalies** — readings that were both flagged as ‘critical status’ by the machine and exceeded the high-temperature threshold.\n> The first few of these readings fall between **81°C and 86°C** , which is well above our normal operating range of around 45°C. This suggests that a small number of sensors are reporting **dangerous spikes** , possibly indicating overheating or sensor malfunction.  \n> In other words, while 99.99% of our data looks stable, these 34 points represent the **exact spots** where we should focus maintenance or investigate further.”\n  \nLet’s visualise this real quick with matplotlib\n![](https://assets.insightmediagroup.io/media/wp-content/uploads/2025/11/Screenshot-2025-11-03-141455-1.jpg)\nWhen I first plotted the results, I expected to see a cluster of red bars showing my critical anomalies. But there were none.\nAt first, I thought something was wrong, but then it clicked. Out of one million readings, only 34 were critical. That’s the beauty of Boolean masking: it detects what your eyes can’t. Even when the anomalies hide deep within millions of normal values, NumPy flags them in milliseconds.\n## Objective 4: Data Cleaning and Imputation\nLastly, NumPy allows you to get rid of inconsistencies and data that doesn’t make sense. You might have come across the concept of data cleaning in data analysis. In Python, NumPy and Pandas are often used to streamline this activity. \nTo demonstrate this, our `status_codes` contain entries with a value of 3 (Faulty/Missing). If we use these faulty temperature readings in our overall analysis, they will skew our results. The solution is to replace the faulty readings with a statistically sound estimated value.\nThe first step is to figure out what value we should use to replace the bad data. The median is always a great choice because, unlike the mean, it is less affected by extreme values.\npython\n\n```\n# TASK: Identify the mask for ‘Valid’ data (where status_codes is NOT 3 — Faulty/Missing).\nvalid_data_mask = (status_codes != 3)\n\n# TASK: Calculate the median temperature ONLY for the Valid data points. This is our imputation value.\nvalid_median_temp = np.median(temperature_data[valid_data_mask])\nprint(f”Median of all valid readings: {valid_median_temp:.2f}°C”)\n```\n\n**Output:**\nmarkup\n\n```\nMedian of all valid readings: 44.99°C\n```\n\nNow, we’ll perform some conditional replacement using the powerful `np.where()` function. Here’s a typical structure of the function.\n**np.where(Condition, Value_if_True, Value_if_False)**\nIn our case:  \n\n  * **Condition:** Is the status code **3** (Faulty/Missing)?\n  * **Value if True:** Use our calculated `valid_median_temp`.\n  * **Value if False:** Keep the original temperature reading.\n\n\npython\n\n```\n# TASK: Implement the conditional replacement using np.where().\ncleaned_temperature_data = np.where(\nstatus_codes == 3, # CONDITION: Is the reading faulty?\nvalid_median_temp, # VALUE_IF_TRUE: Replace with the calculated median.\ntemperature_data # VALUE_IF_FALSE: Keep the original temperature value.\n)\n\n# TASK: Print the total number of replaced values.\nimputed_count = (status_codes == 3).sum()\nprint(f”Total Faulty readings imputed: {imputed_count}”)\n```\n\n**Output:**\nmarkup\n\n```\nTotal Faulty readings imputed: 20102\n```\n\nI didn’t expect the missing values to be this much. It probably affected our reading above in some way. Good thing, we managed to replace them in seconds.\nNow, let’s verify the fix by checking the median for both the original and cleaned data\npython\n\n```\n# TASK: Print the change in the overall mean or median to show the impact of the cleaning.\nprint(f”\\nOriginal Median: {np.median(temperature_data):.2f}°C”)\nprint(f”Cleaned Median: {np.median(cleaned_temperature_data):.2f}°C”)\n```\n\n**Output:**\nmarkup\n\n```\nOriginal Median: 44.99°CCleaned Median: 44.99°C\n```\n\nIn this case, even after cleaning over 20,000 faulty records, the median temperature remained steady at **44.99°C,** indicating that the dataset is statistically sound and balanced.\nLet’s present this to the client:\n> “Out of one million temperature readings, **20,102** were marked as faulty (status code = 3). Instead of removing these faulty records, we replaced them with the **median temperature value (≈ 45°C)** — a standard data-cleaning approach that keeps the dataset consistent without distorting the trend.  \n> Interestingly, the **median temperature remained unchanged (44.99°C)** before and after cleaning. That’s a good sign: it means the faulty readings didn’t skew the dataset, and the replacement didn’t alter the overall data distribution.”\n## Conclusion\nAnd there we go! We initiated this project to address a critical issue for **EnviroTech Dynamics** : the need for faster, loop-free data analysis. The power of NumPy arrays and vectorisation allowed us to fix the problem and future-proof their analytical pipeline.\nNumPy ndarray is the silent engine of the entire Python data science ecosystem. Every major library, like **Pandas** , **scikit-learn** , **TensorFlow** , and **PyTorch,** uses NumPy arrays at its core for fast numerical computation.\nBy mastering NumPy, you’ve built a powerful analytical foundation. The next logical step for me is to move from single arrays to structured analysis with the Pandas library, which organises NumPy arrays into tables (DataFrames) for even easier labelling and manipulation.\nThanks for reading! Feel free to connect with me:\n[Medium](https://medium.com/@ibbysalam)\n[LinkedIn](https://www.linkedin.com/in/ibrahim-salami-059863228/)\n[Twitter](https://x.com/IbbySalam)\n[YouTube](https://www.youtube.com/@ibbysalam)\n## Register Now to Continue Reading\n### Unlock Towards Data Science with a Free Account\nAll articles on Towards Data Science are available to registered users. Create a free account today to access this article and thousands more.\nRegister for freeSign in to your account\n* * *\n![](https://assets.insightmediagroup.io/media/1787657709013_9ddcph.jpeg)\nWritten By\n## [Ibrahim Salami](https://towardsdatascience.com/author/ibrahim.salami/)\n[See all from Ibrahim Salami](https://towardsdatascience.com/author/ibrahim.salami/)\n[Deep Dives](https://towardsdatascience.com/tag/deep-dives/)[Big Data](https://towardsdatascience.com/tag/big-data/)[Data Analytics](https://towardsdatascience.com/tag/data-analytics/)[Numpy](https://towardsdatascience.com/tag/numpy/)[Numpy Array](https://towardsdatascience.com/tag/numpy-array/)[Python](https://towardsdatascience.com/tag/python/)\nShare This Article\n  * [](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Ftowardsdatascience.com%2Fnumpy-for-absolute-beginners-a-project-based-approach-to-data-analysis%2F&title=NumPy%20for%20Absolute%20Beginners%3A%20A%20Project-Based%20Approach%20to%20Data%C2%A0Analysis)\n  * [](https://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Ftowardsdatascience.com%2Fnumpy-for-absolute-beginners-a-project-based-approach-to-data-analysis%2F&title=NumPy%20for%20Absolute%20Beginners%3A%20A%20Project-Based%20Approach%20to%20Data%C2%A0Analysis)\n  * [](https://x.com/share?url=https%3A%2F%2Ftowardsdatascience.com%2Fnumpy-for-absolute-beginners-a-project-based-approach-to-data-analysis%2F&text=NumPy%20for%20Absolute%20Beginners%3A%20A%20Project-Based%20Approach%20to%20Data%C2%A0Analysis)\n\n\nTowards Data Science is a community publication. Submit your insights to reach our global audience and earn through the TDS Author Payment Program.\n[Write for TDS](https://towardsdatascience.com/submissions/)\n## Related Articles\n  * [![](https://assets.insightmediagroup.io/media/wp-content/uploads/2024/11/1_fZiZiuqhnWOVd_g5QsOtw.jpg)](https://towardsdatascience.com/my-medium-journey-as-a-data-scientist-6-months-18-articles-and-3-000-followers-c449306e45f7/)\n## [My Medium Journey as a Data Scientist: 6 Months, 18 Articles, and 3,000 Followers](https://towardsdatascience.com/my-medium-journey-as-a-data-scientist-6-months-18-articles-and-3-000-followers-c449306e45f7/)\n[Data Science](https://towardsdatascience.com/category/data-science/)\nReal numbers, earnings, and data-driven growth strategy for Medium writers\n[Yu Dong](https://towardsdatascience.com/author/ydong029/)\nNovember 11, 20249 min read\n  * [![](https://assets.insightmediagroup.io/media/wp-content/uploads/2020/12/0x-qsIInLP6pOMjVv.png)](https://towardsdatascience.com/transfer-learning-using-pre-trained-alexnet-model-and-fashion-mnist-43898c2966fb/)\n## [Transfer Learning using Pre-Trained AlexNet Model and Fashion-MNIST](https://towardsdatascience.com/transfer-learning-using-pre-trained-alexnet-model-and-fashion-mnist-43898c2966fb/)\n[Data Science](https://towardsdatascience.com/category/data-science/)\nBuilding CNN classifiers in Apache MxNet Gluon framework to classify articles of clothing\n[Andrea Yoss](https://towardsdatascience.com/author/andrea-yoss/)\nDecember 16, 202010 min read\n  * [![](https://assets.insightmediagroup.io/media/wp-content/uploads/2020/05/11b57MV6akYI-O-7dmJlFbQ.png)](https://towardsdatascience.com/vectorization-in-python-46486819d3a/)\n## [Vectorization in Python](https://towardsdatascience.com/vectorization-in-python-46486819d3a/)\n[Artificial Intelligence](https://towardsdatascience.com/category/artificial-intelligence/)\nPyTrix#1: Speeding up our Python Code\n[Kurtis Pykes](https://towardsdatascience.com/author/kurtispykes/)\nMay 7, 20204 min read\n  * [![](https://assets.insightmediagroup.io/media/wp-content/uploads/2021/07/0PQutB_Fxuf7CNiev-scaled.jpg)](https://towardsdatascience.com/add-a-customized-rasa-chatbot-for-your-facebook-page-9313687fbdcb/)\n## [Add a Customized Rasa Chatbot for Your Facebook Page](https://towardsdatascience.com/add-a-customized-rasa-chatbot-for-your-facebook-page-9313687fbdcb/)\n[NLP](https://towardsdatascience.com/category/artificial-intelligence/nlp/)\nA simple walkthrough for setting up a Rasa chatbot for your Facebook page\n[Ikshura Tachintha](https://towardsdatascience.com/author/ikshura/)\nJuly 27, 20217 min read\n  * [![](https://towardsdatascience.com/images/fallback-image.jpg)](https://towardsdatascience.com/3-most-asked-python-interview-questions-for-data-scientists-1a2ad63ebe56/)\n## [3 Most Asked Python Interview Questions for Data Scientists](https://towardsdatascience.com/3-most-asked-python-interview-questions-for-data-scientists-1a2ad63ebe56/)\n[Data Science](https://towardsdatascience.com/category/data-science/)\nTop python interview questions for data scientists\n[Alexandros Zenonos, PhD](https://towardsdatascience.com/author/azenresearchlabs/)\nAugust 16, 20204 min read\n  * [![](https://assets.insightmediagroup.io/media/wp-content/uploads/2021/02/1U1MCbCufqLOoBCDLy8Oegg.jpeg)](https://towardsdatascience.com/extreme-value-theory-in-a-nutshell-with-various-applications-3260b6a84316/)\n## [Extreme Value Theory in a Nutshell with Various Applications](https://towardsdatascience.com/extreme-value-theory-in-a-nutshell-with-various-applications-3260b6a84316/)\n[Coding](https://towardsdatascience.com/category/programming/coding/)\nIn the beginning when statistics was discovered to answer questions related to gambling win chances in the 18th century, normal...\n[Hanan Ahmed](https://towardsdatascience.com/author/hanan-ahmed/)\nFebruary 19, 20218 min read\n  * [![](https://assets.insightmediagroup.io/media/wp-content/uploads/2022/07/0rbiDe7yU1Za0dq1X-scaled.jpg)](https://towardsdatascience.com/data-science-write-robust-python-with-static-typing-c71b9c9c8044/)\n## [Data Science: Write Robust Python With Static Typing](https://towardsdatascience.com/data-science-write-robust-python-with-static-typing-c71b9c9c8044/)\n[Artificial Intelligence](https://towardsdatascience.com/category/artificial-intelligence/)\nUpdated for Python 3.11\n[Nikos Kafritsas](https://towardsdatascience.com/author/nikoskafritsas/)\nJuly 27, 20227 min read\n  * [![](https://assets.insightmediagroup.io/media/1789064330790_5tdxoz.jpg)](https://towardsdatascience.com/from-static-to-dynamic-skills-a-different-model-for-agent-knowledge/)\n## [From Static to Dynamic Skills: A Different Model for Agent Knowledge](https://towardsdatascience.com/from-static-to-dynamic-skills-a-different-model-for-agent-knowledge/)\n[Agentic AI](https://towardsdatascience.com/category/artificial-intelligence/agentic-ai/)\nWhy the skill-inflation panic is aimed at the wrong thing, and what it costs to make agent knowledge a build artifact instead of a file.\n[Tomer Mesika](https://towardsdatascience.com/author/tomer-mesika-tds/)\nSeptember 14, 202614 min read\n  * [![](https://assets.insightmediagroup.io/media/wp-content/uploads/2024/10/0fRwCyanMJ6Oax2y5-scaled.jpg)](https://towardsdatascience.com/how-to-negotiate-your-salary-as-a-data-scientist-4c6ce176b2a5/)\n## [How to Negotiate Your Salary as a Data Scientist](https://towardsdatascience.com/how-to-negotiate-your-salary-as-a-data-scientist-4c6ce176b2a5/)\n[Data Science](https://towardsdatascience.com/category/data-science/)\nAnd how much I made my first year\n[Haden Pelletier](https://towardsdatascience.com/author/pelletierhaden/)\nOctober 27, 20246 min read\n\n\n  * [YouTube](https://www.youtube.com/c/TowardsDataScience)\n  * [X](https://x.com/TDataScience)\n  * [LinkedIn](https://www.linkedin.com/company/towards-data-science/)\n  * [Threads](https://www.threads.net/@towardsdatascience)\n  * [Bluesky](https://bsky.app/profile/towardsdatascience.com)\n\n\n[](https://towardsdatascience.com/)\nYour home for data science and AI. The world's leading publication for data science, data analytics, data engineering, machine learning, and artificial intelligence professionals.\nSubscribe to Our Newsletter[Write For TDS](https://towardsdatascience.com/submissions/)•[About](https://towardsdatascience.com/about-towards-data-science-d691af11cc2f/)•[Advertise](https://contact.towardsdatascience.com/advertise-with-towards-data-science)•[Privacy Policy](https://towardsdatascience.com/privacy-policy/)•[Terms of Use](https://towardsdatascience.com/website-terms-of-use/)\n© Insight Media Group, LLC 2026•[The New Stack](https://thenewstack.io)•[roadmap.sh](https://roadmap.sh)•[Creator Network](https://insightmediagroup.io/creator-network)\n####  Recommended Articles \nClose\n  * [ ![](https://h030.towardsdatascience.com/rest/v2/contentStores/d7d3a4ab-7caf-4383-bbd2-fbf7fb4f1787/items/4970/image?etag=1780565225463&width=500&height=500) Productivity Tips, Data Career Insights, and Other Recent Must-Reads ](https://towardsdatascience.com/productivity-tips-data-career-insights-and-other-recent-must-reads-5c47eb7a2fe0/ \"Productivity Tips, Data Career Insights, and Other Recent Must-Reads\")\n  * [ ![](https://h030.towardsdatascience.com/rest/v2/contentStores/d7d3a4ab-7caf-4383-bbd2-fbf7fb4f1787/items/607639/image?etag=1781250125848&width=500&height=500) Javascript Fatigue: HTMX Is All You Need to Build ChatGPT — Part 1 ](https://towardsdatascience.com/javascript-fatigue-you-dont-need-js-to-build-chatgpt/ \"Javascript Fatigue: HTMX Is All You Need to Build ChatGPT — Part 1\")\n  * [ ![](https://h030.towardsdatascience.com/rest/v2/contentStores/d7d3a4ab-7caf-4383-bbd2-fbf7fb4f1787/items/607930/image?etag=1782124566054&width=500&height=500) The Subset Sum Problem Solved in Linear Time for Dense Enough Inputs ](https://towardsdatascience.com/subset-sum-problem-solved-in-linear-time-for-dense-enough-inputs/ \"The Subset Sum Problem Solved in Linear Time for Dense Enough Inputs\")\n  * [ ![](https://h030.towardsdatascience.com/rest/v2/contentStores/d7d3a4ab-7caf-4383-bbd2-fbf7fb4f1787/items/3660/image?etag=1780176246070&width=500&height=500) Does Your Company Have a Data Strategy? ](https://towardsdatascience.com/does-your-company-have-a-data-strategy-e8944dbec4ae/ \"Does Your Company Have a Data Strategy?\")\n\n\n",
  "body_base_path": "attachments/51c06ef2bde2/pages/",
  "body_markdown_path": "attachments/51c06ef2bde2/pages/archived-body.md",
  "local_html": "attachments/51c06ef2bde2/pages/archived-body.html",
  "body_source": "prior_capture"
}