LogisticRegression coefficients should be stored in column major order to improve sparse inference performance.

### Describe the workflow you want to enable

I want to enable the workflow of training a `LogisticRegression` model on sparse data, with substantial numbers of features and classes, with acceptable performance. Currently, inference for a `LogisticRegression` model slows rather substantially when using sparse features since the transpose of the coefficient matrix must be stored in row-major order to perform the sparse matrix multiply. Changing the ordering of the coefficient array improves the performance dramatically. This is illustrated in the below code snippet:

```python
import scipy
import numpy as np

from sklearn.linear_model import LogisticRegression

X = np.random.rand(10_000, 10_000)
y = np.random.randint(0, 500, size=10_000)
clf = LogisticRegression(max_iter=10).fit(X, y)

%timeit clf.predict_proba(scipy.sparse.rand(1, 10_000))
# 21.9 ms ± 973 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%prun clf.predict_proba(scipy.sparse.rand(1, 10_000))
#   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
#        2    0.019    0.010    0.019    0.010 {method 'ravel' of 'numpy.ndarray' objects}
#        1    0.003    0.003    0.022    0.022 _compressed.py:493(_mul_multivector)

clf.coef_ = np.asfortranarray(clf.coef_)

%timeit clf.predict_proba(scipy.sparse.rand(1, 10_000))
# 467 µs ± 11 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

%prun clf.predict_proba(scipy.sparse.rand(1, 10_000))
#   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
#        1    0.000    0.000    0.000    0.000 {built-in method scipy.sparse._sparsetools.csr_matvecs}
#        1    0.000    0.000    0.000    0.000 {method 'choice' of 'numpy.random.mtrand.RandomState' objects}
```

Additional information can be found [here](https://stackoverflow.com/questions/74325646/why-doesnt-scikit-learns-logisticregression-classifier-use-column-major-for-co).

### Describe your proposed solution

My proposed solution is to ensure that the coefficient matrix in `LogisticRegression` is converted to column major order with `np.asfortranarray` once training has completed. For sparse input, this will dramatically improve performance, while for dense inference, it will not degrade performance too much, as demonstrated below:

```python
import scipy
import numpy as np

from sklearn.linear_model import LogisticRegression

X = np.random.rand(10_000, 10_000)
y = np.random.randint(0, 500, size=10_000)
clf = LogisticRegression(max_iter=10).fit(X, y)

X_test = scipy.sparse.rand(1, 10_000)
X_dense = X_test.A

%timeit clf.predict_proba(X_test)
# 23.4 ms ± 253 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit clf.predict_proba(X_dense)
# 2.81 ms ± 277 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

clf.coef_ = np.asfortranarray(clf.coef_)

%timeit clf.predict_proba(X_test)
# 201 µs ± 705 ns per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
%timeit clf.predict_proba(X_dense)
# 3.05 ms ± 48.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
```

### Describe alternatives you've considered, if relevant

Alternatives include simply ensuring the input to inference is always dense, which results in a 10x speedup. However, this is still a ~10x slowdown relative to the column major ordering solution.

### Additional context

_No response_

COMMENT:
Let's close then.

Labels: New Feature, module:linear_model