Showing posts with label python programming. Show all posts
Showing posts with label python programming. Show all posts

Monday, September 23, 2024

Handling Bad Lines in Pandas: A Guide to error_bad_lines and Its Successor

Pandas error_bad_lines Explained – Handling Bad CSV Rows Like a Pro

๐Ÿ“Š Pandas error_bad_lines – Clean Messy CSV Data Efficiently

When working with real-world datasets, things rarely go perfectly. CSV files often contain broken rows, extra columns, or missing values.

Instead of crashing your code, Pandas gives you tools to handle this smartly.

๐Ÿ“š Table of Contents


๐Ÿšจ The Problem with CSV Files

CSV files assume every row has the same number of columns.

Mathematically:

\[ Columns_{row1} = Columns_{row2} = Columns_{row3} \]

But in reality:

\[ Columns_{row4} \ne Expected\ Columns \]

๐Ÿ‘‰ This mismatch creates a "bad line"

⚙️ What is error_bad_lines?

This parameter tells Pandas what to do when it encounters bad rows.

ValueBehavior
TrueThrow error and stop
FalseSkip bad rows

๐Ÿ’ป Code Example

import pandas as pd data = pd.read_csv('orders.csv', error_bad_lines=False) print(data)

๐Ÿ–ฅ️ CLI Output

Click to Expand
   OrderID Product Quantity Price
0 1 Phone 2 300
1 2 Laptop 1 1200
2 3 Headphones 2 50
3 5 Tablet 1 500
The broken row is silently removed.

๐Ÿ“ Why This Works (Simple Math)

Pandas expects fixed-width rows:

\[ Valid\ Row = (n\ columns) \]

Bad row:

\[ Row_i \neq n \]

So Pandas applies:

\[ Dataset = Dataset - Bad\ Rows \]

๐Ÿ‘‰ It filters out inconsistent rows automatically.

⚠️ Deprecation Notice

error_bad_lines is deprecated.

Use this instead:

data = pd.read_csv('orders.csv', on_bad_lines='skip')

๐Ÿง  Custom Handling

def handle_bad_lines(row): print("Bad row:", row) return None data = pd.read_csv('orders.csv', on_bad_lines=handle_bad_lines)

❌ When NOT to Use It

  • If data quality is critical
  • If too many rows are bad
  • If missing data affects analysis
Skipping data blindly can lead to wrong insights.

๐Ÿ’ก Key Takeaways

  • Bad rows break CSV structure
  • error_bad_lines skips them (deprecated)
  • on_bad_lines is the modern replacement
  • Always validate data before skipping

๐ŸŽฏ Final Thoughts

Handling messy data is a core skill in data science. Tools like on_bad_lines make life easier—but they should be used wisely.

Remember: clean data → reliable insights.

Python nonlocal Keyword Explained with Practical Examples

Python nonlocal Keyword Explained: Complete Guide to Scopes, Closures, LEGB Rule and Examples

Python nonlocal Keyword Explained: Complete Guide to Scopes, Closures, LEGB Rule and Nested Functions

Understanding variable scope is one of the most important skills in Python programming. Many beginners learn variables quickly, but become confused when variables start behaving differently inside nested functions. This confusion usually appears when working with closures, decorators, callbacks, state management, and advanced function designs.

The nonlocal keyword was introduced to solve a specific problem: allowing nested functions to modify variables from their enclosing scope without affecting global variables.

๐Ÿ’ก Key Takeaway

  • local = current function
  • nonlocal = nearest enclosing function
  • global = module-level variable
  • built-in = Python predefined namespace

Table of Contents


What is nonlocal?

The nonlocal keyword tells Python that a variable belongs to an enclosing function scope rather than the current local scope.

When Python encounters an assignment statement inside a function, it normally creates a local variable. However, sometimes we want to update a variable defined in the outer function. The nonlocal keyword enables exactly that behavior.

General Syntax


def outer():
    variable = 10

    def inner():
        nonlocal variable
        variable += 1

    inner()

Why Was nonlocal Introduced?

Before Python introduced nonlocal, modifying variables inside closures required workarounds such as mutable lists or dictionaries. These approaches were less readable and harder to maintain.

Consider the following problem:


def outer():
    x = 5

    def inner():
        x = 10

    inner()
    print(x)

outer()

Output

5

Even though x was assigned inside inner(), it did not modify the outer x. Python created an entirely new local variable.


Understanding the LEGB Rule

Python resolves variable names according to the LEGB rule.

Level Name Description
L Local Current function scope
E Enclosing Outer nested functions
G Global Module scope
B Built-in Python built-ins

Visualization

Built-in
   ↑
Global
   ↑
Enclosing
   ↑
Local

Python searches variables from Local upward toward Built-in until a matching name is found.


Mathematical Model of Scope Resolution

You can think of scope lookup mathematically as:

Variable Resolution Function:

R(x) = L → E → G → B

Where:

  • L = Local namespace
  • E = Enclosing namespace
  • G = Global namespace
  • B = Built-in namespace

Python evaluates namespaces sequentially until the variable is found.

If:

x ∉ L

x ∉ E

x ∉ G

x ∉ B

Then:

NameError

First Working Example


def outer_function():
    x = 5

    def inner_function():
        nonlocal x
        x = 10

    inner_function()

    print(x)

outer_function()

CLI Output

10

Step-by-Step Execution

  1. outer_function creates x = 5
  2. inner_function is defined
  3. nonlocal tells Python to use enclosing x
  4. x becomes 10
  5. outer_function prints updated value

What Happens Without nonlocal?


def outer():
    x = 5

    def inner():
        x = 10

    inner()

    print(x)

outer()

CLI Output

5

Python creates a new local variable inside inner(). The outer variable remains unchanged.


Using nonlocal Correctly


def outer():
    x = 5

    def inner():
        nonlocal x
        x = 10

    inner()

    print(x)

outer()

CLI Output

10

Closures and nonlocal

Closures are one of the most important applications of nonlocal.

A closure is a function that remembers variables from its enclosing environment even after the outer function has completed execution.


def counter():

    count = 0

    def increment():
        nonlocal count
        count += 1
        return count

    return increment

c = counter()

print(c())
print(c())
print(c())

CLI Output

1 2 3

The count variable survives because the closure retains access to its enclosing environment.


Closure Memory Diagram

counter()
   |
   |-- count = 0
   |
   |-- increment()
           |
           |-- remembers count

Advanced Closure Example


def bank_account(balance):

    def deposit(amount):
        nonlocal balance
        balance += amount
        return balance

    return deposit

account = bank_account(1000)

print(account(500))
print(account(200))

CLI Output

1500 1700

Advanced Example: Multiple Nested Scopes


def level1():

    x = 1

    def level2():

        def level3():
            nonlocal x
            x = 100

        level3()

    level2()

    print(x)

level1()

CLI Output

100

global vs nonlocal

Feature global nonlocal
Scope Module level Enclosing function
Works in closures No Yes
Changes global state Yes No
Recommended for nested functions No Yes

Example of global


count = 0

def increment():

    global count

    count += 1

increment()

print(count)
1

Example of nonlocal


def outer():

    count = 0

    def increment():

        nonlocal count

        count += 1

    increment()

    print(count)

outer()
1

Common Mistakes

Mistake #1: Using nonlocal without enclosing variable

def test():

    def inner():
        nonlocal x
Results in:
SyntaxError
Mistake #2: Confusing global and nonlocal

nonlocal cannot access module-level variables.

Mistake #3: Forgetting closure behavior

Many developers expect variables to reset after function execution. Closures preserve state intentionally.


Real-World Applications

  • State management
  • Function decorators
  • Caching systems
  • Event handlers
  • GUI callbacks
  • Rate limiting
  • Counters
  • Memoization
  • Data processing pipelines
  • Middleware systems

Decorator Example


def call_counter(func):

    count = 0

    def wrapper(*args, **kwargs):

        nonlocal count

        count += 1

        print("Calls:", count)

        return func(*args, **kwargs)

    return wrapper

@call_counter
def hello():
    print("Hello")

hello()
hello()
hello()

CLI Output

Calls: 1 Hello Calls: 2 Hello Calls: 3 Hello

Best Practices

  • Use nonlocal only when state must persist.
  • Prefer classes if state becomes complex.
  • Avoid excessive nesting.
  • Keep closure logic simple.
  • Document closure behavior.
  • Use meaningful variable names.
  • Avoid mixing global and nonlocal.

๐Ÿ’ก Best Practice Rule

If your closure starts managing many variables, consider replacing it with a class.


Class Alternative


class Counter:

    def __init__(self):
        self.count = 0

    def increment(self):
        self.count += 1
        return self.count

For complex state management, classes are often easier to maintain than closures.


Python Interview Questions

  1. What is nonlocal in Python?
  2. How does nonlocal differ from global?
  3. What is an enclosing scope?
  4. What is the LEGB rule?
  5. How do closures use nonlocal?
  6. Can nonlocal modify global variables?
  7. When should nonlocal be avoided?
  8. Why was nonlocal introduced?
  9. How does scope resolution work internally?
  10. Can multiple nested functions use nonlocal?

Quick Revision Sheet

Keyword Purpose
local Current function variable
nonlocal Modify enclosing scope variable
global Modify module variable

Frequently Asked Questions

What is nonlocal in Python?

nonlocal allows nested functions to modify variables from an enclosing scope.

Can nonlocal access global variables?

No. It only works with enclosing function scopes.

Can I use nonlocal outside a nested function?

No. Python raises a SyntaxError.

Is nonlocal faster than classes?

Performance differences are usually negligible. Choose based on readability and maintainability.


๐ŸŽฏ Final Key Takeaways

  • Python follows the LEGB rule.
  • nonlocal targets enclosing function variables.
  • global targets module-level variables.
  • Closures commonly rely on nonlocal.
  • nonlocal preserves state between calls.
  • Use it carefully to avoid confusing code.
  • Prefer classes for large stateful systems.
  • Understanding nonlocal is essential for decorators and closures.
  • Mastering scope resolution improves debugging skills.
  • Strong knowledge of nonlocal is frequently tested in Python interviews.

The nonlocal keyword may appear small, but it plays a major role in Python's functional programming capabilities. Once you understand how Python searches namespaces through the LEGB rule and how closures preserve state, nonlocal becomes a natural and powerful tool for writing clean, reusable, and maintainable code.

Tuesday, August 20, 2024

Efficient Handling of Invalid Sensor Data with Pandas where Method

Pandas where vs Boolean Indexing – Complete Data Cleaning Guide

๐Ÿผ Pandas Data Cleaning: where vs Boolean Indexing

Data cleaning is one of the most important steps in any data science workflow. In this guide, we’ll explore two powerful techniques in Pandas:

  • where()
  • Boolean Indexing

You’ll learn when to use each, with real-world examples, interactive sections, and best practices.


๐Ÿ“š Table of Contents


๐Ÿ”น 1. Using where()

Code Example

import pandas as pd import numpy as np data = pd.DataFrame({'A': [1, 2, 3, 4, 5]}) result = data.where(data > 2, np.nan) print(result)

Explanation

where() keeps values where the condition is true and replaces others.

Condition: A > 2 → Keep values greater than 2 → Replace others with NaN

CLI Output

View Output
     A
0  NaN
1  NaN
2  3.0
3  4.0
4  5.0

✅ Pros

  • Clean and readable
  • Single-step replacement
  • Great for chaining

❌ Cons

  • Less flexible for complex logic

๐Ÿ”น 2. Boolean Indexing

Code Example

import pandas as pd import numpy as np data = pd.DataFrame({'A': [1, 2, 3, 4, 5]}) data[data <= 2] = np.nan print(data)

Explanation

This method directly modifies values based on a condition.

Condition: A ≤ 2 → Replace those values manually

CLI Output

View Output
     A
0  NaN
1  NaN
2  3.0
3  4.0
4  5.0

✅ Pros

  • Very flexible
  • Precise control

❌ Cons

  • Can overwrite data accidentally
  • Slightly more verbose

๐ŸŒก️ Real-World Scenario: Sensor Data Cleaning

Imagine a temperature sensor. Values below 0°C are invalid.

Dataset

import pandas as pd import numpy as np data = pd.DataFrame({ 'Temperature': [22.5, -300.0, 23.7, 25.1, -400.0, 26.8] }) print(data)

CLI Output

View Dataset
   Temperature
0        22.5
1      -300.0
2        23.7
3        25.1
4      -400.0
5        26.8

✔ Using where()

result = data.where(data['Temperature'] >= 0, np.nan) print(result)
Output
   Temperature
0        22.5
1         NaN
2        23.7
3        25.1
4         NaN
5        26.8
✔ Clean, readable, and safe ✔ No accidental overwrites

✔ Using Boolean Indexing

data.loc[data['Temperature'] < 0, 'Temperature'] = np.nan print(data)
Output
   Temperature
0        22.5
1         NaN
2        23.7
3        25.1
4         NaN
5        26.8

✔ Using np.where()

data['Temperature'] = np.where( data['Temperature'] >= 0, data['Temperature'], np.nan )

๐Ÿ“Š Comparison Table

Method Readability Flexibility Safety
where() High Medium High
Boolean Indexing Medium High Medium
np.where() Low Medium Medium

๐Ÿ–ฅ️ Interactive Practice

Try modifying conditions like:

  • Replace values greater than 25
  • Replace values between 10 and 20
  • Apply multiple conditions
Example Challenge
Replace temperatures > 25 with NaN

๐Ÿ’ก Key Takeaways

  • where() is best for clean, readable replacements
  • Boolean indexing is more powerful but riskier
  • np.where() is useful but less intuitive
  • Always prioritize readability in data cleaning

๐ŸŽฏ Final Thoughts

Choosing the right method depends on your goal. For most cleaning tasks, where() provides the best balance between simplicity and safety.

Master these techniques, and your data preprocessing skills will improve significantly.

Saturday, August 17, 2024

A Beginner’s Guide to reshape, transpose, and axis in NumPy

# Import NumPy library
import numpy as np

# Example for `reshape`
b = np.array([1, 2, 3])
reshaped_b = b.reshape(3, 1)
print(reshaped_b)


**Output**:

[[1]
 [2]
 [3]]


**Explanation**:
- The original array `b` is a 1D array with shape `(3,)`.
- `reshape(3, 1)` converts it into a 2D array with shape `(3, 1)`, resulting in three rows and one column.

**Key Point**: `reshape` is used to change the dimensions of an array while preserving its data, as long as the new shape has the same number of elements as the original shape.


# Example for `transpose`
b = np.array([[1, 2, 3], [4, 5, 6]])
transposed_b = b.T
print(transposed_b)


**Output**:

[[1 4]
 [2 5]
 [3 6]]


**Explanation**:
- The original array `b` is a 2D array with shape `(2, 3)` (2 rows and 3 columns).
- The `transpose()` method (or `b.T`) switches rows and columns, converting it to a shape of `(3, 2)`.

**Key Point**: `transpose` is used to swap the dimensions of an array. For 2D arrays, it effectively flips the array over its diagonal.


# Example for `axis` with operations like sum
b = np.array([[1, 2, 3], [4, 5, 6]])
sum_along_axis0 = np.sum(b, axis=0)
sum_along_axis1 = np.sum(b, axis=1)

print("Sum along axis 0:", sum_along_axis0)
print("Sum along axis 1:", sum_along_axis1)


**Output**:

Sum along axis 0: [5 7 9]
Sum along axis 1: [ 6 15]


**Explanation**:
- `axis=0` refers to the vertical axis (columns), so summing along `axis=0` sums each column.
- `axis=1` refers to the horizontal axis (rows), so summing along `axis=1` sums each row.

**Key Point**: The concept of `axis` is not about reshaping or transposing but about how operations are performed across dimensions of the array.

### Summary:

- **`reshape`**: Changes the shape of an array while keeping the same data. Useful for reformatting arrays without altering their content.
- **`transpose`**: Swaps the dimensions of the array. For 2D arrays, it converts rows to columns and vice versa.
- **`axis`**: Defines the direction along which operations (like sum, mean) are applied. It’s crucial for performing operations that aggregate or reduce data along specific dimensions.

### Visualizing the Difference:

For a 2D array like `[[1, 2, 3], [4, 5, 6]]`:

- **`reshape(3, 2)`**: Converts it to `[[1, 2], [3, 4], [5, 6]]`, rearranging the elements into a new shape.
- **`transpose()`**: Converts it to `[[1, 4], [2, 5], [3, 6]]`, switching rows with columns.

Each of these operations is useful in different contexts, depending on what you need to achieve with the array's structure.

Fixing Array Reshape Issues in NumPy: A Practical Guide


### Understanding and Handling Reshape Errors in NumPy

When working with arrays in NumPy, reshaping is a common operation. It allows you to change the shape of an existing array without altering its data. However, one of the most frequent errors encountered during this operation is the "reshape error." Let’s explore why this error occurs, how to understand it, and ways to handle or avoid it effectively.

### **What is Reshaping in NumPy?**

In NumPy, reshaping means changing the dimensions of an array. For example, you might want to convert a 1D array into a 2D array, or a 2D array into a 3D array, depending on your needs. The `reshape` function is used for this purpose:


import numpy as np

# Example of reshaping a 1D array into a 2D array
arr = np.array([1, 2, 3, 4, 5, 6])
reshaped_arr = arr.reshape(2, 3)


In this example, the 1D array `[1, 2, 3, 4, 5, 6]` is reshaped into a 2D array with 2 rows and 3 columns.

### **Why Do Reshape Errors Occur?**

The reshape error typically occurs when the new shape you’re trying to apply is incompatible with the total number of elements in the array. NumPy requires that the total number of elements before and after reshaping must remain the same. If you attempt to reshape an array into a shape that does not align with the number of elements, NumPy will raise a `ValueError`.

#### **Example of a Reshape Error:**


import numpy as np

arr = np.array([1, 2, 3, 4, 5, 6])
# Trying to reshape the array into a shape that is incompatible
reshaped_arr = arr.reshape(3, 3) # This will raise an error


Here, the original array has 6 elements, but the shape `(3, 3)` implies 9 elements (since 3x3=9), which leads to a `ValueError: cannot reshape array of size 6 into shape (3,3)`.

### **Understanding the Error Message:**

The error message `ValueError: cannot reshape array of size X into shape (Y, Z)` tells you that the number of elements in the original array (`X`) does not match the required number of elements implied by the new shape `(Y, Z)`. This is a key insight to quickly diagnosing and fixing the error.

### **How to Avoid Reshape Errors:**

1. **Check the Total Number of Elements:**
   Before reshaping, always ensure that the total number of elements remains consistent. You can easily check this using the `.size` attribute of the array.

   
   arr = np.array([1, 2, 3, 4, 5, 6])
   print(arr.size) # Output: 6
   

   Ensure that the product of the dimensions in your new shape matches this number.

2. **Use `-1` for Automatic Calculation:**
   NumPy allows you to use `-1` in the `reshape` function to automatically calculate the dimension that you leave unspecified. This can help avoid errors by letting NumPy handle the calculation.

   
   reshaped_arr = arr.reshape(2, -1) # NumPy calculates the second dimension
   print(reshaped_arr.shape) # Output: (2, 3)
   

   Here, by setting `-1`, NumPy automatically determines that the second dimension must be 3 to fit all elements.

3. **Understand the Data Layout:**
   If you're working with multi-dimensional arrays, it's important to understand how the data is laid out in memory (row-major order for C-style or column-major for Fortran-style). This can impact how you think about reshaping, especially when dealing with large datasets.

4. **Reshape with Caution When Reducing Dimensions:**
   When reshaping to reduce dimensions, ensure that the new shape logically represents the data's structure. Misaligned reshapes can lead to logical errors in your program even if they don’t raise exceptions.

### **Common Scenarios Leading to Reshape Errors:**

1. **Reading Data from Files:**
   When loading data from external files, it’s easy to make mistakes in specifying the intended shape. Always verify the shape of your data before reshaping.

2. **Misinterpreting Array Dimensions:**
   Sometimes, you might misinterpret the dimensions of your array, especially in complex pipelines. Use the `.shape` attribute frequently to check your assumptions.

3. **Incorrect Assumptions in Loops:**
   If you’re reshaping arrays within loops or functions, ensure that the shape is correctly calculated based on the data at each iteration.

### **Handling Reshape Errors Gracefully:**

When working in larger projects or shared codebases, catching and handling errors can improve robustness. You can use try-except blocks to catch reshape errors and handle them appropriately:


try:
    reshaped_arr = arr.reshape(3, 3)
except ValueError as e:
    print(f"Error: {e}")
    # Handle the error, e.g., by reshaping to a valid shape or alerting the user


This approach prevents your program from crashing and allows you to provide useful feedback or corrective actions.

### **Conclusion:**

Reshape errors in NumPy are common but easily avoidable with a solid understanding of array dimensions and careful consideration of the shapes you're working with. Always ensure that the total number of elements is consistent before and after reshaping. Utilize features like `-1` for automatic dimension calculation and adopt practices like error handling to make your code more resilient. With these strategies, you can confidently reshape arrays without running into frustrating errors.


Friday, August 16, 2024

Comparison of np.zeros and np.empty in NumPy: Initialization, Performance, and Use Cases

np.zeros vs np.empty in NumPy

np.zeros vs np.empty in NumPy

Understanding array initialization, performance, and use cases

NumPy provides multiple ways to create arrays. Two commonly used functions are np.zeros and np.empty. While they may look similar, they behave very differently under the hood.

np.zeros

๐Ÿ”ข Purpose & Behavior

np.zeros creates an array of a specified shape and initializes every element to 0.

This provides a clean and predictable starting point for computations.

๐Ÿงช Example
import numpy as np

array = np.zeros((3, 3))
print(array)

Output:

[[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]

Here, a 3×3 array is created and every element is explicitly set to zero.

np.empty

⚠️ Purpose & Behavior

np.empty creates an array of a specified shape without initializing its values.

The array contains whatever data already exists in memory at the time of allocation—often referred to as “garbage values.”

๐Ÿงช Example
import numpy as np

array = np.empty((3, 3))
print(array)

Output (example):

[[6.94843117e-310 6.94843117e-310 0.00000000e+000]
 [0.00000000e+000 6.94843113e-310 6.94843113e-310]
 [6.94843113e-310 6.94843113e-310 6.94843113e-310]]

The values appear random because NumPy does not overwrite memory when using np.empty.

Key Differences

Aspect np.zeros np.empty
Initialization All values set to 0 Uninitialized (random memory values)
Predictability Fully predictable Unpredictable
Performance Slightly slower Faster
Typical Use Clean starting state Immediate overwrite

When Should You Use Each?

  • Use np.zeros when you need a safe, known baseline for calculations.
  • Use np.empty when performance matters and you plan to assign all values immediately.

๐Ÿ’ก Key Takeaways

  • np.zeros guarantees clean initialization
  • np.empty skips initialization for speed
  • Uninitialized arrays may contain garbage values
  • Choose based on safety vs performance needs
  • Never rely on values from np.empty without overwriting them
NumPy array initialization: np.zeros vs np.empty

How numpy.arange() Works with Integers and Floating-Point Numbers




The behavior of `numpy.arange()` when dealing with floating-point numbers and integer numbers stems from how the function operates internally, particularly with respect to how floating-point arithmetic is handled.

### Floating-Point Arithmetic in `np.arange`:

Floating-point arithmetic can introduce small precision errors due to the way numbers are represented in memory. This can affect whether or not the upper bound is included in the output.


import numpy as np

print(np.arange(9, 6.6, -0.3))


- **Start**: `9`
- **Stop**: `6.6`
- **Step**: `-0.3`

Here’s what happens:

1. **Initial Value**: The sequence starts at `9.0`.
2. **Subsequent Values**: Each subsequent value is obtained by subtracting `0.3` from the previous value:
   - 9.0
   - 8.7
   - 8.4
   - 8.1
   - 7.8
   - 7.5
   - 7.2
   - 6.9
   - 6.6

3. **Stop Condition**: The function stops generating values when the next value would be less than `6.6`.

**Output**:

[9. 8.7 8.4 8.1 7.8 7.5 7.2 6.9 6.6]


The output includes `6.6` because, after subtracting `0.3` multiple times from `9.0`, the final value exactly matches `6.6` due to the nature of floating-point arithmetic.

### Why Integer Values Exclude Upper Bound:

For integer values, `np.arange(start, stop, step)` does not include the `stop` value by default. This is a design choice consistent with Python's `range()` function, where the range is half-open, meaning it includes the start value but excludes the stop value.

Example with integers:


print(np.arange(0, 10, 2))


**Output**:

[0 2 4 6 8]


Here, `10` is excluded because the sequence would go `0, 2, 4, 6, 8, 10`, but since `10` is the stop value, it is not included.

### Summary:

- **Floating-Point Arithmetic**: Precision issues can cause `np.arange()` to sometimes include the stop value if it matches exactly due to how the steps add up.
- **Integer Sequences**: By design, `np.arange()` excludes the stop value, similar to Python’s `range()` function, providing a half-open interval `[start, stop)`.

### Important Note:

For better control over floating-point sequences, especially when precision matters, it's often recommended to use `np.linspace` instead of `np.arange`, as `np.linspace` allows you to specify the number of points and guarantees the inclusion of both the start and stop values.



If you want to generate values from `9` to `6.6` without including `6.6`, you'd need to either:

**Use `endpoint=False`** in `np.linspace()` to exclude the stop value:

import numpy as np
print(np.linspace(9, 6.6, num=9, endpoint=False))

### Output with `endpoint=False`:

[9. 8.73 8.46 8.19 7.92 7.65 7.38 7.11 6.84]

In this case, `6.6` is not included because the sequence stops before reaching the exact stop value.

Featured Post

How HMT Watches Lost the Time: A Deep Dive into Disruptive Innovation Blindness in Indian Manufacturing

The Rise and Fall of HMT Watches: A Story of Brand Dominance and Disruptive Innovation Blindness The Rise and Fal...

Popular Posts