Issue 1:
Describe your issue.

Currently, applying the ** operator to a sparse array implements the numpy.linalg.matrix_power function. This is not compatible with the np.array implementation of **, which does element-wise power. This should be fixed as part of the migration from sparse "matrices" to sparse "arrays". Additionally, the matrix_power function should then also be included in the sparse.linalg package.

Reproducing Code Example

from scipy.sparse import csr_array, random

A = csr_array(random(5,5,0.1))
print(A.A)
print((A**2).A) #This does matrix_power, eventhough it is initialised as a sparse array (not a matrix)
print((A.A)**2) #This does element-wise power, since it is a numpy array

Error message

N/A

SciPy/NumPy/Python version information

1.8.0 1.20.3 sys.version_info(major=3, minor=9, micro=7, releaselevel='final', serial=0)

Issue 2:
In #13699, I am implementing the fitting of distributions to censored data. To represent censored data, I created a fairly simple class called CensoredData, and updated the fit method of the univariate continuous distributions to be able to handle an instance of the class. There have been questions about the API for representing censored data in the PR. Instead of having that discussion in the PR (where we also discuss implementation details), it seems cleaner to break out the API discussion to its own issue.

The wikipedia article Censoring (statistics) provides an overview of what censored data is. In the CensoredData class, we want to represent a data set that contains a mix of regular (i.e. not censored) data, right-censored data, left-censored data and interval-censored data. The first three cases require a single number for each data point, while the last, interval-censored, requires two values to define the interval.

A common case of censoring is a data set that is a mix of regular values and censored values that all have the same type. For example, the data shown in this page are either not censored or right censored. The same is true for the first example in this set of slides. It would be nice if the API makes it easy to create an instance of CensoredData for such data sets.

The following are two possible constructors for the CensoredData class.

Alternative 1: CensoredData(lower, upper)

At the time of writing this comment, the CensoredData class has a constructor with the signature __init__(self, lower, upper), where lower and upper are expected to be 1D arrays of numbers. A number can be ±inf. This API follows from the fact that we can represent all four cases (not censored, left-censored, right-censored or interval-censored) as an interval, if we allow ±inf as an end point, and if we interpret an interval of length 0 as an uncensored point. The meaning of those points in the interval-censored case is as expected. For a left-censored data point, the left value of the pair is set to -inf (i.e. the pair [-inf, 1] represents a left-censored value that is less than 1). Likewise, for a right-censored data point, the right value is set to +inf. For data points that are not censored, the two values are set to the same value (i.e. it is an "interval" with length 0).

Above I mentioned the common case of data that is a mix of uncensored and right-censored points. A simple example in the docstring for CensoredData has four regular values, [13, 22, 17, 15], and two right-censored values, [20, 18]. To create a CensoredData instance for this data using the constructor, one would write:

CensoredData(lower=[13, 22, 17, 15, 20, 18], upper=[13, 22, 17, 15, np.inf, np.inf])

The first four pairs (lower[i], upper[i]) represent the uncensored data points, and the last two represent the right-censored data.

This API is very similar to the API provided by the R function fitdistcens that is part of the fitdistrplus package. fitdistcens expects the censored data set to be represented as a data frame with two columns, named left and right. The interpretion of the values in those columns is the same as that used in the current implemention of CensoredData, except that the R function uses NA instead of ±inf to indicate that a data point is left- or right-censored. The above example in R would be

data = data.frame(left=c(13, 22, 17, 15, 20, 18), right=c(13, 22, 17, 15, NA, NA))

To make it a bit easier to create data sets of this form, CensoredData has two alternative constructors implemented as class methods, left_censored and right_censored. These take two arguments, a 1D array x of numbers and a boolean array of the same length that indicates if the corresponding value in x is censored. With the right_censored method, the example above is created with

CensoredData.right_censored(13, 22, 17, 15, 20, 18], [False, False, False, False, True, True])

So instead of having to create a copy of the values and assign inf where appropriate, the user supplies a boolean array. A 0/1 flag is pretty common in the examples that I've found on the web where the data is shown in a textual format, so it is likely that such boolean array would be easily created when, say, reading the data from a file.

Alternative 2: CensoredData(x=None, left=None, right=None, intervals=None)

This is an alternative API, in which the constructor has a parameter for each type of censoring. The parameters are

x: a 1D array of uncensored measurements

left: a 1D array of left-censored measurements

right: a 1D array of right-censored measurements

intervals: a 2D array with shape (m, 2) containing the intervals for m interval-censored values

The nice thing about this API is its explicitness, and that it doesn't require the user to use ±inf to create left- or right-censored values. The simple example given above can be represented as

CensoredData(x=[13, 22, 17, 15], right=[20, 18])

That is a clean API for creating a right-censored data set, so the convenience provided by the alternative constructor CensoredData.right_censored is less important. If we went with this API, I would probably remove the left_censored and right_censored methods.

There is redundancy here, because (assuming we interpret intervals containing ±inf and intervals with length 0 the same as they are interpreted in the other API), any value that can be represent with x, left or right can also be represented as an interval. That is, the right-censored example could also be represented as

CensoredData(intervals=[[13, 13], [22, 22], [17, 17], [15, 15], [20, np.inf], [20, np.inf]])

But that isn't necessarily a problem.