<jupyter_start><jupyter_text>NumpyNumPy is the fundamental package for scientific computing with Python.In Python, data is almost universally represented as NumPy arrays. Even newer tools like Pandas are built around the NumPy array.We will be seeing: 1. 1D array, 2D array 2. Array slices, joins, subsets 3. Arithmetic Operations on 2D arrays 4. Covariance, Correlation    Initializing Numpy Arrays 1. Using np.array2. Using np.ndarray<jupyter_code>import numpy as np
np.random.seed(0)  # seed for reproducibility
x1 = np.random.randint(10, size=6)  # One-dimensional array
x2 = np.random.randint(10, size=(3, 3))  # Two-dimensional array
print(x1)
print(x2)<jupyter_output><empty_output><jupyter_text>Using np.array()<jupyter_code>x1 = np.array([1,2,3,4])
print(x1)
print(type(x1))
x2 = np.array([[1,2,3],[4,5,6]])
print(x2)
print(type(x2))<jupyter_output>[[1 2 3]
 [4 5 6]]
<class 'numpy.ndarray'><jupyter_text>Using np.ndarray()<jupyter_code>x = np.ndarray(shape=(1,3),dtype=int, buffer = np.array([1,2,3]))
print(x)
x = np.append(x,5)
print(x)
print(type(x))
x = np.ndarray(shape=(2,2), dtype=float,buffer = np.array([[1.4,2.5],[1.3,2.4]]))
print(x)
x = np.ndarray(shape=(2,2), dtype=int,buffer = np.array([[1,2],[1,2]]))
print(x)<jupyter_output>[[1 2]
 [1 2]]<jupyter_text>Attributes of ndarray Each array has attributes `ndim` (the number of dimensions), `shape` (the size of each dimension), and `size` (the total size of the array):<jupyter_code>x2 = np.array([[1,2,3],[4,5,6]])
print("x2.ndim = ",x2.ndim)
print("x2.shape = ",x2.shape)
print("x2.size = ",x2.size)<jupyter_output>x2.ndim =  2
x2.shape =  (2, 3)
x2.size =  6<jupyter_text>Another useful attribute is the `dtype` which tells you about the type of elements in the array:<jupyter_code>print("x2.dtype = ",x2.dtype)<jupyter_output>x2.dtype =  int64<jupyter_text>Other attributes include `itemsize`, which lists the size (in bytes) of each array element, and `nbytes`, which lists the total size (in bytes) of the array:<jupyter_code>print("itemsize:", x2.itemsize, "bytes")
print("nbytes:", x2.nbytes, "bytes")<jupyter_output>itemsize: 8 bytes
nbytes: 48 bytes<jupyter_text>Array Indexing: Accessing Single Elements In a one-dimensional array, the ith value (counting from zero) can be accessed by specifying the desired index in square brackets, just as with Python lists:<jupyter_code>x1 = np.array([1,2,3,4])
print("x1 = ",x1)
print("x1[0] = ",x1[0]) # just like arrays in c/c++
print("x1[-1] = ",x1[-1]) # negative indexing just like lists<jupyter_output>x1 =  [1 2 3 4]
x1[0] =  1
x1[-1] =  4<jupyter_text>In a multi-dimensional array, items can be accessed using a comma-separated tuple of indices:<jupyter_code>print("x2 = "); print(x2)
print("x2[0] = ",x2[0]) # will print the entire 1st row

# to print 1st element of 1st row
print("x2[0][0]= ", x2[0][0]) 
print("x2[0,0] = ",x2[0,0])

# to print 2nd element of 3rd row
print("x2[2][1]= ", x2[2][1])
print("x2[2,1]= ", x2[2,1])<jupyter_output><empty_output><jupyter_text>Values can also be modified using any of the above index notation:<jupyter_code>x2[0, 0] = 12
print(x2)
x2[0][0] = 14
print(x2)<jupyter_output><empty_output><jupyter_text>**NOTE :** Unlike Python lists, NumPy arrays have a fixed type. This means, for example, if you attempt to insert a floating-point value to an integer array, the value will be silently truncated.i.e the float value gets converted to nearest int value.<jupyter_code>x1 = np.ndarray(5, buffer = np.array([1,2,3,4,5]),dtype = int)
print(x1)
x1[2] = 5.7
print("x1 after changing : ",x1)<jupyter_output><empty_output><jupyter_text>Array Slicing and Subsetting : Accessing Subarrays Just as we can use square brackets to access individual array elements, we can also use them to access subarrays with the slice notation, marked by the colon (:) character. The NumPy slicing syntax follows that of the standard Python list; to access a slice of an array x, use :```pythonx[start:stop:step]```**NOTE :** Default value of `start` is `0`, `stop` is `size of object` and `step` is `1`.<jupyter_code>x = np.ndarray(10, buffer = np.array([0,1,2,3,4,5,6,7,8,9]),dtype = int)
print(x)
print("x[:] = ",x[:])
print("x[:5] = ",x[:5])
print("x[5:] = ",x[5:])
print("x[1:5] = ",x[1:5])
print("x[1:5:2] = ",x[1:5:2])
print("x[::-1] = ",x[::-1])
np.random.seed(0)  # seed for reproducibility
x2 = np.random.randint(10, size=(3, 3))  
print(x2)
print("x2[:2, :3] = "); print(x2[:2, :3])  # first two rows, first three columns
print("x2[:3, ::2] = "); print(x2[:3, ::2]) # all rows, every other column
print("x2[::-1, ::-1] = "); print(x2[::-1, ::-1]) #reversed 2D array
print("x2[:, 0] = ",x2[:, 0])  # first column of x2<jupyter_output><empty_output><jupyter_text>Joining Two Arrays Joining of two arrays in NumPy, is primarily accomplished using the routine `np.concatenate`.<jupyter_code>x = np.array([1,2,3])
y = np.array([4,5,6])
z = np.concatenate([x,y]) # Combines x and y to give one array. 
# a = np.concatenate([x,y,z])
print(z)
x2 = np.array([[1,2,3],[2,3,4]])
y2 = np.array([[3,4,5],[4,5,6]])
z2 = np.concatenate([x2,y2])
print(z2)<jupyter_output><empty_output><jupyter_text>Arithmetic Operations on 2D arrays  | Operator 	| Equivalent Function 	||----------	|---------------------	|| +        	| np.add              	|| -        	| np.subtract         	|| *        	| np.multiply         	|<jupyter_code>x2 = np.array([[1,2,3],[2,3,4]])
y2 = np.array([[3,4,5],[4,5,6]])
print("x2 + y2 = "); print(np.add(x2,y2))
print("x2 - y2 = "); print(np.subtract(x2,y2))
print("x2 * y2 = "); print(np.multiply(x2,y2))<jupyter_output><empty_output><jupyter_text>**NOTE :** Here as you can see, matrix multiplication isn't actually possible and we actually just get a matrix where `x2[i,j] * y2[1,j]` is the output.<jupyter_code>x2 = np.array([[1,2,3],[2,3,4]])
y2 = np.array([[3,4,5],[4,5,6]])
print(np.matmul(x2,y2))
x2 = np.array([[1,2,3],[2,3,4]])
y2 = np.array([[3,4],[4,5],[5,6]])
print(np.matmul(x2,y2))<jupyter_output><empty_output><jupyter_text>CovarianceCovariance indicates the level to which two variables vary together. If we examine N-dimensional samples, `X = [x_1, x_2, ... x_N]^T`, then the covariance matrix element `C_{ij}` is the covariance of `x_i` and `x_j`. The element `C_{ii}` is the variance of `x_i`.<jupyter_code>x2 = np.array([[0,1,2],[2,1,0]])
print(x2)<jupyter_output><empty_output><jupyter_text>Note here how `x[0]` increases and `x[1]` decreases.  This is also shown by the covariance matrix :<jupyter_code>print(np.cov(x2))<jupyter_output><empty_output><jupyter_text>Note that again, `C[0,1]` and `C[1,0]` which shows the correlation between `x[0]` and `x[1]`, is negative.However `C[0,0]` and `C[1,1]` which show the correlation between `x[0]` and `x[0]` and `x[1]` and `x[1]` is 1.  Note how x and y are combined:<jupyter_code>x = np.array([-2.1, -1,  4.3])
y = np.array([3,  1.1,  0.12])
X = np.stack((x, y))
print(np.cov(X))
# To check 
print(np.cov(x))
print(np.cov(y))<jupyter_output><empty_output><jupyter_text>Correlation The term "correlation" refers to a mutual relationship or association between quantities.It is a standardised form of Covariance. Correlation Coeffecients take values between `[-1,1]`In Numpy (and in general), Correlation Matrix refers to the normalised version of a Covariance matrix.<jupyter_code>x = np.array([-2.1, -1,  4.3])
y = np.array([3,  1.1,  0.12])
X = np.stack((x, y))
print(np.corrcoef(X))<jupyter_output><empty_output><jupyter_text>Linear Regression Linear regression is used for finding linear relationship between target and one or more predictors. Simple linear regression is useful for finding relationship between two continuous variables. One is predictor or independent variable and other is response or dependent variable.  scipy.stats.linregressscipy.stats.linregress(x, y=None) Parameters:	x, y : array_like Returns:	slope : float> slope of the regression lineintercept : float> intercept of the regression liner-value : float> correlation coefficientp-value : float> two-sided p-value for a hypothesis test whose null hypothesis is that the slope is zero.stderr : float> Standard error of the estimate<jupyter_code>from scipy import stats
x = np.random.random(10)
y = np.random.random(10)
print(x); print(y)
slope, intercept, r_value, p_value, std_err = stats.linregress(x,y)
slope<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.17151754701161817, 'fraction_numerical': 0.046592406276200746, 'mean_word_length': 5.528537920250195, 'pattern_counts': {'":': 0, '<': 72, '<?xml version=': 0, '>': 77, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '19', 'dir': 'jupyter-structured-clean-dedup', 'id': '218767', 'license': 'MIT', 'n_tokens_mistral': 3321, 'n_tokens_neox': 3206, 'n_words': 861, 'path': 'Numpy/Numpy.ipynb', 'repo_name': 'RohitMidha23/Explanatory-Data-Analysis', 'size': '8349'}