Now d1and the newly created view of d2 havethe same shape, so we can combine them (by forming their sum, in thiscase). Note that even though reshape()is a member function, it does not change the shape of the instanceitself but instead returns a new view object: d2is still a one-dimensional vector. (There is also a standaloneversion of this function, so we could also have written view= np.reshape( d2, (3,4) ). The presence of such redundantfunctionality is due to the desire to maintain backward compatibilitywith both of NumPys ancestors.)We can now accessindividual elements of the data structures, depending on their shape.Since both d1 and view are matrices,they are indexed by a pair of indices (in the order [row,col]).However, d2 is still a one-dimensionalvector and thus takes only a single index. (We will have more to sayabout indexing in a moment.) Finally, we examine some diagnosticsregarding the shape of the data structures, emphasizing their precisesemantics. The shape is a tuple, giving the number of elements ineach dimension. The size is the total number of elements andcorresponds to the value returned by len()for the entire data structure. Finally, ndimgives the number of dimensions (i.e., d.ndim ==len(d.shape)) and is equivalent to the rankof the entire data structure. (Again, the redundant functionalityexists to maintain backward compatibility.)Finally, lets take acloser look at the ways in which we can access elements or largersubsets of an ndarray. In the previous listing we saw how to accessan individual element by fully specifying an index for eachdimension. We can also specify larger sub-arrays of a data structureusing two additional techniques, known as slicing and advancedindexing. The following listing shows some representative examples.(Again, consider this an interactive Python session.)We first create a12-element vector and reshape it into a 3 4 matrix as before.Slicing uses the standard Python slicing syntax start:stop:step,where the start position is inclusive but the stopping position isexclusive. (In the listing, I use only the simplest form of slicing,selecting all available elements.) There are two potential gotchaswith slicing. First of all, specifying an explicit subscripting index(not a slice!) reduces the corresponding dimension to a scalar.Slicing, though, does not reduce the dimensionality of the datastructure. Consider the two extreme cases: in the expression d[0,1],indices for both dimensions are fully specified, and so we are leftwith a scalar. In contrast, d[0:1,1:2]is sliced in both dimensions. Neither dimension is removed, and theresulting object is still a (two-dimensional) matrix but of smallersize: it has shape 1 1. The second issue to watch out for is thatslices return views, not copies. Besides slicing, we can also indexan ndarray with a vector of indices, by an operation called advancedindexing. The previous listing showed two simple examples. In thefirst we use a Python list object, which contains the integer indices(i.e., the positions) of the desired columns and in the desiredorder, to select a subset of columns. In the second example, we forman ndarray of Boolean entries to select only those rows for which theBoolean evaluates to True. In contrast to slicing, advanced indexingreturns copies, not views. This completes our overview of the basiccapabilities of the NumPy module. NumPy