<p dir="auto">The scipy curve_fit documentation says that xdata can be an object:</p>
<blockquote>
<p dir="auto">xdataarray_like or object<br>
The independent variable where the data is measured. Should usually be an M-length sequence or an (k,M)-shaped array for functions with k predictors, <strong>but can actually be any object.</strong></p>
</blockquote>
<p dir="auto">(emphasis mine)</p>
<p dir="auto">This is currently not respected. Previously, anything could be passed in, but with 1.2.3, it appears that a numpy array is assumed and xdata is modified to float64.</p>
<p dir="auto"><code class="notranslate">xdata = xdata.astype(float)</code></p>
<p dir="auto">The xdata should not be modified by curve_fit since it's not, in any way, meant for curve_fit to consume. It's meant for our models. These may rely on the data types of the xdata, possibly non-numeric. Even for numeric models, casting to float breaks models that rely on the data types passed to them, or would require possibly lossy conversions back.</p>
<p dir="auto">This is a regression that breaks all models that use something besides float64 numpy arrays or need to preserve data types for their models to work.</p>
<h4 dir="auto">Reproducing code example:</h4>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="from scipy.optimize import curve_fit

class ExampleObject(object):
    def __init__(self, a=5, b=3.0):
        self.a = 5.0
        self.b = 3.0

def model(xdata, k):
    return xdata.a * k

values = range(10)

answer = curve_fit(
            model,  # Function to fit the data to
            xdata=ExampleObject(),
            ydata=values,
            p0=[1.0],
        )
"><pre class="notranslate"><code class="notranslate">from scipy.optimize import curve_fit

class ExampleObject(object):
    def __init__(self, a=5, b=3.0):
        self.a = 5.0
        self.b = 3.0

def model(xdata, k):
    return xdata.a * k

values = range(10)

answer = curve_fit(
            model,  # Function to fit the data to
            xdata=ExampleObject(),
            ydata=values,
            p0=[1.0],
        )

</code></pre></div>
<h4 dir="auto">Error message:</h4>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="  File &quot;/usr/local/lib/python2.7/site-packages/scipy/optimize/minpack.py&quot;, line 716, in curve_fit
    xdata = xdata.astype(float)
AttributeError: 'ExampleObject' object has no attribute 'astype'"><pre class="notranslate"><code class="notranslate">  File "/usr/local/lib/python2.7/site-packages/scipy/optimize/minpack.py", line 716, in curve_fit
    xdata = xdata.astype(float)
AttributeError: 'ExampleObject' object has no attribute 'astype'
</code></pre></div>
<h4 dir="auto">Scipy/Numpy/Python version information:</h4>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="('1.2.3', '1.16.6', sys.version_info(major=2, minor=7, micro=17, releaselevel='final', serial=0))"><pre class="notranslate"><code class="notranslate">('1.2.3', '1.16.6', sys.version_info(major=2, minor=7, micro=17, releaselevel='final', serial=0))
</code></pre></div>
<p dir="auto">In the <a href="https://warrenweckesser.github.io/czi/scipy-2019-czi-proposal-revised.pdf" rel="nofollow">CZI Proposal</a>, we wrote:</p>
<blockquote>
<p dir="auto">The continuous distributions in SciPy all have a method for fitting the distribution to data using<br>
the method of maximum likelihood estimation (MLE). The proposed enhancements are:</p>
<ul dir="auto">
<li>Where possible, use an analytical formula rather than numerical optimization for greater<br>
speed and accuracy<br>
...</li>
</ul>
</blockquote>
<p dir="auto">This is part of our effort to address the <a href="https://docs.scipy.org/doc/scipy/reference/roadmap.html#statistics-enhancements" rel="nofollow">roadmap item</a> "Improve the options for fitting a probability distribution to data".</p>
<p dir="auto">One of the best sources I've found (via a <a href="https://www.itl.nist.gov/div898/handbook/eda/section3/eda366.htm" rel="nofollow">NIST Engineering Statistics Handbook</a>) is the Parameter Estimation sections from:<br>
<a href="http://personalpages.to.infn.it/~zaninett/pdf/statistical-distributions.pdf" rel="nofollow">Evans, Hastings, and Peacock (2000), <em>Statistical Distributions</em>, 3rd. Ed., John Wiley and Sons.</a></p>
<p dir="auto">Any other sources that are easily accessible?</p>
<p dir="auto">Also, for method of moments (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="584866490" data-permission-text="Title is private" data-url="https://github.com/scipy/scipy/issues/11695" data-hovercard-type="pull_request" data-hovercard-url="/scipy/scipy/pull/11695/hovercard" href="https://github.com/scipy/scipy/pull/11695">gh-11695</a>), I could write a program that tries to solve for fitting formulas (from the formulas for the moments) using SymPy.  I don't think that would work as well for MLE, though. Might not even get anything new for MM.</p>
<p dir="auto">Given the formulas, this should be pretty straightforward work: just override the <code class="notranslate">fit</code> methods of the distributions defined in  <code class="notranslate">/scipy/stats/_continuous_distns.py</code>, following existing examples (e.g. <code class="notranslate">beta_gen</code>) for extending documentation and any other conventions. For tests, I suppose we could mainly compare against the generic implementation. In cases where the generic implementation isn't working very well, we could check the partial derivatives of the likelihood function?</p>
<p dir="auto">If you have any thoughts / words of wisdom before we get started, please let us know here.</p>
<p dir="auto"><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/fletcheaston/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/fletcheaston">@fletcheaston</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/swallan/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/swallan">@swallan</a> I think this is next.</p>
<p dir="auto"><em>Update:</em><br>
<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/swallan/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/swallan">@swallan</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/WarrenWeckesser/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/WarrenWeckesser">@WarrenWeckesser</a> A simple but really useful script for generating first-order conditions is <a href="https://gist.github.com/mdhaber/1861b0c967e315e0830b347e988b3a27">here</a>. Now it can (sometimes) solve for a variable in terms of the rest.</p>
<table role="table">
<thead>
<tr>
<th align="center"><strong>Continuous distributions</strong></th>
<th align="left"><strong>Current status of fit override</strong></th>
<th align="right"><strong>Page Number of MLE (Evans)</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">laplace</td>
<td align="left">merged: <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="610612454" data-permission-text="Title is private" data-url="https://github.com/scipy/scipy/issues/11988" data-hovercard-type="pull_request" data-hovercard-url="/scipy/scipy/pull/11988/hovercard" href="https://github.com/scipy/scipy/pull/11988">gh-11988</a>, good</td>
<td align="right">124</td>
</tr>
<tr>
<td align="center">rayleigh</td>
<td align="left">merged: <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="616315009" data-permission-text="Title is private" data-url="https://github.com/scipy/scipy/issues/12097" data-hovercard-type="pull_request" data-hovercard-url="/scipy/scipy/pull/12097/hovercard" href="https://github.com/scipy/scipy/pull/12097">gh-12097</a>, <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1384871717" data-permission-text="Title is private" data-url="https://github.com/scipy/scipy/issues/17090" data-hovercard-type="pull_request" data-hovercard-url="/scipy/scipy/pull/17090/hovercard" href="https://github.com/scipy/scipy/pull/17090">gh-17090</a>, good</td>
<td align="right">175</td>
</tr>
<tr>
<td align="center">logistic</td>
<td align="left">merged: <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="681357163" data-permission-text="Title is private" data-url="https://github.com/scipy/scipy/issues/12738" data-hovercard-type="pull_request" data-hovercard-url="/scipy/scipy/pull/12738/hovercard" href="https://github.com/scipy/scipy/pull/12738">gh-12738</a>, <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1391808086" data-permission-text="Title is private" data-url="https://github.com/scipy/scipy/issues/17117" data-hovercard-type="pull_request" data-hovercard-url="/scipy/scipy/pull/17117/hovercard" href="https://github.com/scipy/scipy/pull/17117">gh-17117</a>, <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1632504876" data-permission-text="Title is private" data-url="https://github.com/scipy/scipy/issues/18177" data-hovercard-type="pull_request" data-hovercard-url="/scipy/scipy/pull/18177/hovercard" href="https://github.com/scipy/scipy/pull/18177">gh-18177</a>, almost good, but should use <code class="notranslate">root_scalar</code></td>
<td align="right">130</td>
</tr>
<tr>
<td align="center">pareto</td>
<td align="left">merged <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1129071572" data-permission-text="Title is private" data-url="https://github.com/scipy/scipy/issues/15567" data-hovercard-type="pull_request" data-hovercard-url="/scipy/scipy/pull/15567/hovercard" href="https://github.com/scipy/scipy/pull/15567">gh-15567</a>, good</td>
<td align="right">149</td>
</tr>
<tr>
<td align="center">invgauss, wald</td>
<td align="left">merged: <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="653748802" data-permission-text="Title is private" data-url="https://github.com/scipy/scipy/issues/12514" data-hovercard-type="pull_request" data-hovercard-url="/scipy/scipy/pull/12514/hovercard" href="https://github.com/scipy/scipy/pull/12514">gh-12514</a>, further investigation needed</td>
<td align="right">121</td>
</tr>
<tr>
<td align="center">gumbel_r, gumbel_l</td>
<td align="left">merged: <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="681356343" data-permission-text="Title is private" data-url="https://github.com/scipy/scipy/issues/12737" data-hovercard-type="pull_request" data-hovercard-url="/scipy/scipy/pull/12737/hovercard" href="https://github.com/scipy/scipy/pull/12737">gh-12737</a>, good</td>
<td align="right">101</td>
</tr>
<tr>
<td align="center">powerlaw</td>
<td align="left">merged: <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="738745581" data-permission-text="Title is private" data-url="https://github.com/scipy/scipy/issues/13053" data-hovercard-type="pull_request" data-hovercard-url="/scipy/scipy/pull/13053/hovercard" href="https://github.com/scipy/scipy/pull/13053">gh-13053</a>, good</td>
<td align="right">159</td>
</tr>
<tr>
<td align="center">nakagami</td>
<td align="left">see <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="503737984" data-permission-text="Title is private" data-url="https://github.com/scipy/scipy/issues/10908" data-hovercard-type="issue" data-hovercard-url="/scipy/scipy/issues/10908/hovercard" href="https://github.com/scipy/scipy/issues/10908">gh-10908</a></td>
<td align="right">-</td>
</tr>
<tr>
<td align="center">vonmises</td>
<td align="left">merged: <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1490487864" data-permission-text="Title is private" data-url="https://github.com/scipy/scipy/issues/17585" data-hovercard-type="pull_request" data-hovercard-url="/scipy/scipy/pull/17585/hovercard" href="https://github.com/scipy/scipy/pull/17585">gh-17585</a>, <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1590935940" data-permission-text="Title is private" data-url="https://github.com/scipy/scipy/issues/18013" data-hovercard-type="pull_request" data-hovercard-url="/scipy/scipy/pull/18013/hovercard" href="https://github.com/scipy/scipy/pull/18013">gh-18013</a>, <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1619559232" data-permission-text="Title is private" data-url="https://github.com/scipy/scipy/issues/18128" data-hovercard-type="pull_request" data-hovercard-url="/scipy/scipy/pull/18128/hovercard" href="https://github.com/scipy/scipy/pull/18128">gh-18128</a>. Almost good; see <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1619559232" data-permission-text="Title is private" data-url="https://github.com/scipy/scipy/issues/18128" data-hovercard-type="pull_request" data-hovercard-url="/scipy/scipy/pull/18128/hovercard" href="https://github.com/scipy/scipy/pull/18128">gh-18128</a>.</td>
<td align="right">192</td>
</tr>
<tr>
<td align="center">weibull_min, weibull_max</td>
<td align="left">see <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="594717349" data-permission-text="Title is private" data-url="https://github.com/scipy/scipy/issues/11806" data-hovercard-type="issue" data-hovercard-url="/scipy/scipy/issues/11806/hovercard" href="https://github.com/scipy/scipy/issues/11806">gh-11806</a></td>
<td align="right">196</td>
</tr>
<tr>
<td align="center">asymmetric laplace</td>
<td align="left">awaiting PR</td>
<td align="right"><a href="https://www.dropbox.com/s/4tyrqjr6708yhh1/MLE%20-%20Asymmetric%20Laplace.pdf?dl=0" rel="nofollow">notes</a></td>
</tr>
<tr>
<td align="center">genextreme</td>
<td align="left">see <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="467404132" data-permission-text="Title is private" data-url="https://github.com/scipy/scipy/issues/10446" data-hovercard-type="issue" data-hovercard-url="/scipy/scipy/issues/10446/hovercard" href="https://github.com/scipy/scipy/issues/10446">gh-10446</a></td>
<td align="right">-</td>
</tr>
</tbody>
</table>
<p dir="auto">Other distributions that have overridden <code class="notranslate">fit</code> method:<br>
<code class="notranslate">norm</code> - looks good, nothing to do here<br>
<code class="notranslate">beta</code> - investigate fitting <code class="notranslate">loc</code> and <code class="notranslate">scale</code>? Adjust inequality conditions for <code class="notranslate">FitDataError</code>.<br>
<code class="notranslate">expon</code> - works perfectly, AFAICT<br>
<code class="notranslate">weibull_min</code> - should implement analytical solution when <code class="notranslate">loc</code> is fixed<br>
<code class="notranslate">gamma</code> - look into fitting when <code class="notranslate">loc</code> is not fixed. Adjust inequality conditions for <code class="notranslate">FitDataError</code>.<br>
<code class="notranslate">lognorm</code> - merged: <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1339112947" data-permission-text="Title is private" data-url="https://github.com/scipy/scipy/issues/16839" data-hovercard-type="pull_request" data-hovercard-url="/scipy/scipy/pull/16839/hovercard" href="https://github.com/scipy/scipy/pull/16839">gh-16839</a>; works quite well. I'd rather not work on it more, but others are welcome to.<br>
<code class="notranslate">uniform</code> - works perfectly, AFAICT</p>