ararpy 0.1.35__tar.gz → 0.1.37__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. {ararpy-0.1.35 → ararpy-0.1.37}/PKG-INFO +1 -1
  2. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/__init__.py +2 -3
  3. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/calc/basic.py +12 -0
  4. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/calc/raw_funcs.py +3 -3
  5. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/calc/regression.py +207 -100
  6. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/files/calc_file.py +35 -34
  7. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/files/raw_file.py +97 -131
  8. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/smp/info.py +2 -2
  9. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/smp/initial.py +14 -11
  10. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/smp/json.py +2 -2
  11. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/smp/raw.py +4 -4
  12. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/smp/sample.py +59 -70
  13. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/smp/style.py +4 -1
  14. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy.egg-info/PKG-INFO +1 -1
  15. {ararpy-0.1.35 → ararpy-0.1.37}/setup.py +1 -1
  16. {ararpy-0.1.35 → ararpy-0.1.37}/LICENSE +0 -0
  17. {ararpy-0.1.35 → ararpy-0.1.37}/README.md +0 -0
  18. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/Example - Check arr.py +0 -0
  19. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/Example - Granite Cooling History.py +0 -0
  20. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/Example - Plot temperature calibration.py +0 -0
  21. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/Example - Show MDD results.py +0 -0
  22. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/Example - Show all Kfs age spectra.py +0 -0
  23. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/Example - Show random walk results.py +0 -0
  24. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/Example - Tc calculation.py +0 -0
  25. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/calc/__init__.py +0 -0
  26. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/calc/age.py +0 -0
  27. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/calc/arr.py +0 -0
  28. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/calc/corr.py +0 -0
  29. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/calc/err.py +0 -0
  30. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/calc/histogram.py +0 -0
  31. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/calc/isochron.py +0 -0
  32. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/calc/jvalue.py +0 -0
  33. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/calc/plot.py +0 -0
  34. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/calc/spectra.py +0 -0
  35. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/examples/022_VU124-M11a.ahd +0 -0
  36. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/examples/20WHA0103.age +0 -0
  37. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/examples/22WHA0078.xls +0 -0
  38. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/examples/22WHA0433.age +0 -0
  39. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/examples/22WHA0433.arr +0 -0
  40. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/examples/22WHA0433.full.xls +0 -0
  41. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/examples/24WHN0001-51-592.XLS +0 -0
  42. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/examples/AHD.input-filter +0 -0
  43. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/examples/ArAr.calc +0 -0
  44. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/examples/ArArCALC.age +0 -0
  45. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/examples/NGX-600 - Copy.TXT +0 -0
  46. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/examples/NGX-600.TXT +0 -0
  47. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/examples/NGX-XLS.input-filter +0 -0
  48. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/examples/Qtegra-exported-xls.input-filter +0 -0
  49. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/examples/S01-239.csv +0 -0
  50. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/examples/WH01.irra +0 -0
  51. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/examples/WHA.pdf +0 -0
  52. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/examples/raw_example.xls +0 -0
  53. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/examples/sample-default.smp +0 -0
  54. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/files/__init__.py +0 -0
  55. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/files/arr_file.py +0 -0
  56. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/files/basic.py +0 -0
  57. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/files/new_file.py +0 -0
  58. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/files/xls.py +0 -0
  59. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/smp/EXPORT_TO_PDF_DATA_PROPERTIES.py +0 -0
  60. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/smp/__init__.py +0 -0
  61. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/smp/basic.py +0 -0
  62. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/smp/calculation.py +0 -0
  63. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/smp/consts.py +0 -0
  64. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/smp/corr.py +0 -0
  65. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/smp/diffusion_funcs.py +0 -0
  66. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/smp/export.py +0 -0
  67. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/smp/plots.py +0 -0
  68. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/smp/table.py +0 -0
  69. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/test.py +0 -0
  70. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/thermo/__init__.py +0 -0
  71. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/thermo/arrhenius.py +0 -0
  72. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/thermo/atomic_level_random_walk.py +0 -0
  73. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy/thermo/basic.py +0 -0
  74. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy.egg-info/SOURCES.txt +0 -0
  75. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy.egg-info/dependency_links.txt +0 -0
  76. {ararpy-0.1.35 → ararpy-0.1.37}/ararpy.egg-info/top_level.txt +0 -0
  77. {ararpy-0.1.35 → ararpy-0.1.37}/setup.cfg +0 -0
  78. {ararpy-0.1.35 → ararpy-0.1.37}/tests/test.py +0 -0
  79. {ararpy-0.1.35 → ararpy-0.1.37}/tests/test2.py +0 -0
  80. {ararpy-0.1.35 → ararpy-0.1.37}/tests/test_error_correlation.py +0 -0
  81. {ararpy-0.1.35 → ararpy-0.1.37}/tests/test_regression_methods.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ararpy
3
- Version: 0.1.35
3
+ Version: 0.1.37
4
4
  Summary: A project for Ar-Ar geochronology
5
5
  Home-page: https://github.com/wuyangchn/ararpy.git
6
6
  Author: Yang Wu
@@ -16,10 +16,10 @@ from . import calc, smp, files, thermo, test
16
16
  """ Information """
17
17
 
18
18
  name = 'ararpy'
19
- version = '0.1.35'
19
+ version = '0.1.37'
20
20
  __version__ = version
21
21
  full_version = version
22
- last_update = '2025-12-02'
22
+ last_update = '2025-12-12'
23
23
 
24
24
  """ ArArPy Functions """
25
25
 
@@ -141,6 +141,5 @@ RawData.get_sequence = smp.raw.get_sequence
141
141
  RawData.to_sample = smp.initial.from_raw_data
142
142
  RawData.get_unknown = lambda _raw: smp.raw.get_sequence(_raw, True, 'is_unknown', unique=False)
143
143
  RawData.get_blank = lambda _raw: smp.raw.get_sequence(_raw, True, 'is_blank', unique=False)
144
- RawData.get_air = lambda _raw: smp.raw.get_sequence(_raw, True, 'is_air', unique=False)
145
144
  Sequence.get_data_df = lambda _seq: pd.DataFrame(_seq.data)
146
145
  Sequence.get_flag_df = lambda _seq: pd.DataFrame(_seq.flag)
@@ -57,6 +57,18 @@ def get_datetime(t_year: int, t_month: int, t_day: int, t_hour: int, t_min: int,
57
57
  return ts - base
58
58
 
59
59
 
60
+ def get_timestring(timestamp: int = 0, base=None):
61
+ """
62
+ :param timestamp: timestamp (utz)
63
+ :param base: base time [y, m, d, h, m]
64
+ :return:
65
+ """
66
+ if base is None:
67
+ base = [1970, 1, 1, 0, 0]
68
+ ts = timestamp + datetime(*base, tzinfo=timezone.utc).timestamp()
69
+ return datetime.fromtimestamp(ts, tz=timezone.utc).isoformat(timespec='seconds')
70
+
71
+
60
72
  def merge_dicts(a: dict, b: dict):
61
73
  """
62
74
  a and b, two dictionary. Return updated a
@@ -30,8 +30,8 @@ def get_raw_data_regression_results(points_data, unselected: list = None):
30
30
 
31
31
  """
32
32
  def power(a0, a1):
33
- return regression.power(a0, a1)
34
- # raise ValueError("Deprecated regression")
33
+ # return regression.power(a0, a1)
34
+ raise ValueError("Deprecated regression")
35
35
  # if unselected is None:
36
36
  # unselected = []
37
37
  # linesData = []
@@ -42,9 +42,9 @@ def get_raw_data_regression_results(points_data, unselected: list = None):
42
42
  power, regression.average]
43
43
  # size = 50
44
44
  # lines_x = [(max(x + un_x) - 0) / size * i for i in range(size + 1)]
45
+ x, y = transpose(points_data, ignore=False)
45
46
  for i in range(len(reg_handler)):
46
47
  try:
47
- x, y = transpose(points_data, ignore=False)
48
48
  res = reg_handler[i](a0=y, a1=x)
49
49
  # line_data = transpose([lines_x, res[7](lines_x)])
50
50
  line_results = res[0:4]
@@ -16,7 +16,7 @@ import traceback
16
16
  import numpy as np
17
17
  import pandas as pd
18
18
  from scipy.stats import distributions
19
- from scipy.optimize import fsolve
19
+ from scipy.optimize import minimize_scalar
20
20
  import warnings
21
21
  from scipy.optimize import minimize
22
22
  warnings.simplefilter(action="ignore", category=RuntimeWarning)
@@ -495,22 +495,25 @@ def linest(a0: list, a1: list, *args):
495
495
  # calculate Y values base on the fitted formula
496
496
  estimate_y = np.matmul(x, beta)
497
497
  resid = (estimate_y - y) ** 2
498
- reg = (estimate_y - np.mean(estimate_y)) ** 2
499
- ssresid = resid.sum()
500
- ssreg = reg.sum()
501
- sstotal = ssreg + ssresid
498
+ reg = (estimate_y - np.mean(y)) ** 2
499
+ ssresid = resid.sum() # 残差平方和
500
+ ssreg = reg.sum() # 回归平方和
501
+ sstotal = ((y - np.mean(y)) ** 2).sum()
502
+ r2 = ssreg / sstotal if sstotal != 0 else np.inf
503
+
502
504
  df = m - n
503
- m_ssresid = ssresid / df
504
- se_beta = (m_ssresid * np.diagonal(inv_xtx)) ** .5
505
- beta = beta.transpose()[0]
505
+ m_ssresid = ssresid / df # 均方残差,与加权平均中的MSWD对应
506
+ cov_beta = m_ssresid * inv_xtx
507
+ se_beta = np.diagonal(cov_beta) ** .5
508
+
509
+ beta = beta.flatten()
506
510
  rse_beta = se_beta / beta
507
- r2 = ssreg / sstotal if sstotal != 0 else np.inf
508
511
 
509
512
  def get_adjusted_y(*args):
510
513
  args = [[1] * len(args[0]), *args]
511
514
  return [sum([beta[i] * args[i][j] for i in range(len(beta))]) for j in range(len(args[0]))]
512
515
 
513
- return beta[0], se_beta[0], rse_beta[0] * 100, r2, m_ssresid, beta, se_beta, get_adjusted_y, m_ssresid
516
+ return beta[0], se_beta[0], abs(rse_beta[0]) * 100, r2, m_ssresid, beta, cov_beta, get_adjusted_y, m_ssresid
514
517
 
515
518
 
516
519
  def average(a0: list, a1=None):
@@ -535,12 +538,12 @@ def average(a0: list, a1=None):
535
538
  m_ssresid = ssresid / df
536
539
  r2 = ssreg / sstotal if sstotal != 0 else 1 # r2 = ssreg / sstotal
537
540
 
538
- k1 = pow(sum([(i - k0) ** 2 for i in a0]) / df, 0.5) # standard deviation
539
- k2 = k1 / k0 * 100 if k0 != 0 else 0 # relative standard error
541
+ k6 = [[sum([(i - k0) ** 2 for i in a0]) / df]]
542
+ k1 = pow(k6[0][0], 0.5) # standard deviation
543
+ k2 = k1 / abs(k0) * 100 if k0 != 0 else 0 # relative standard error
540
544
  k3 = r2 # determination coefficient
541
- k4 = 'MSWD'
545
+ k4 = m_ssresid # 'MSWD'
542
546
  k5 = [k0]
543
- k6 = [k1]
544
547
  k8 = m_ssresid
545
548
 
546
549
  def get_adjusted_y(x: list):
@@ -737,7 +740,7 @@ def quadratic(a0: list, a1: list):
737
740
  """
738
741
  # y = b + m1 * x + m2 * x ^ 2
739
742
  k = list(linest(a0, a1, [i ** 2 for i in a1]))
740
- b, seb, rseb, r2, mswd, [b, m1, m2], [seb, sem1, sem2] = k[0:7]
743
+ [b, m1, m2] = k[5]
741
744
 
742
745
  def get_adjusted_y(x: list):
743
746
  return [b + m1 * _x + m2 * _x ** 2 for _x in x]
@@ -756,7 +759,7 @@ def polynomial(a0: list, a1: list, degree: int = 5):
756
759
  """
757
760
  # y = b + m1 * x + m2 * x ^ 2 + ... + m[n] * x ^ n
758
761
  k = list(linest(a0, *[[j ** (i + 1) for j in a1] for i in range(degree)]))
759
- b, seb, rseb, r2, mswd, beta, se_beta = k[0:7]
762
+ beta = k[5]
760
763
 
761
764
  def get_adjusted_y(x: list):
762
765
  return [sum([beta[i] * _x ** i for i in range(degree + 1)]) for _x in x]
@@ -766,6 +769,7 @@ def polynomial(a0: list, a1: list, degree: int = 5):
766
769
  return k
767
770
 
768
771
 
772
+ ### Deprecated
769
773
  def logest(a0: list, a1: list):
770
774
  """
771
775
  :param a0: known_y's, y = b * m ^ x
@@ -775,15 +779,19 @@ def logest(a0: list, a1: list):
775
779
  # y = b * m ^ x, Microsoft Excel LOGEST function, ln(y) = ln(b) + ln(m) * x
776
780
  a0 = [np.log(i) for i in a0] # ln(y)
777
781
  linest_res = linest(a0, a1)
778
- lnb, selnb, rseb, r2, mswd, [lnb, lnm], [selnb, selnm] = linest_res[0:7]
782
+ lnb, selnb, rseb, r2, mswd, beta, cov_beta = linest_res[0:7]
783
+ lnb, lnm = beta
784
+ selnb, selnm = np.diagonal(cov_beta) ** .5
785
+
779
786
  b = np.exp(lnb)
780
787
  m = np.exp(lnm)
781
788
  sem = np.exp(lnm) * selnm
782
789
  seb = np.exp(lnb) * selnb # Excel.Logest function do not consider the error propagation
783
- rseb = seb / b * 100
790
+ rseb = seb / abs(b) * 100
784
791
  return b, seb, rseb, r2, mswd, m, sem
785
792
 
786
793
 
794
+ ### Deprecated
787
795
  def power(a0: list, a1: list):
788
796
  """
789
797
  :param a0: known_y's, y = a * x ^ b + c
@@ -841,7 +849,9 @@ def power(a0: list, a1: list):
841
849
  raise IndexError
842
850
 
843
851
  f = linest(a0, [_x ** b for _x in a1])
844
- a, sea, c, sec = f[5][1], f[6][1], f[0], f[1]
852
+ beta, cov_beta = f[5:7]
853
+ c, a = beta
854
+ sec, sea = np.diagonal(cov_beta) ** .5
845
855
 
846
856
  calculated_y = [_pow_func(i, a, b, c) for i in a1]
847
857
  resid = [(calculated_y[i] - a0[i]) ** 2 for i in range(len(a0))]
@@ -862,104 +872,193 @@ def power(a0: list, a1: list):
862
872
  errfx = pow(sum([i ** 2 for i in a1]) / (dp * sum([i ** 2 for i in a1]) - sum(a1) ** 2), 0.5)
863
873
  # seb = errfz * sey = errfz * ssresid / df -> se_intercept = sey * errfx = seb / errfz * errfx
864
874
  se_intercept = sec / errfz * errfx
865
- rse_intercept = se_intercept / intercept * 100
875
+ rse_intercept = se_intercept / abs(intercept) * 100
876
+
877
+
878
+ exp_beta = [a, b, c]
879
+ exp_cov_beta = [
880
+ [cov_beta[1][1], 0, cov_beta[1][0]],
881
+ [0, 0, 0],
882
+ [cov_beta[0][1], 0, cov_beta[0][0]],
883
+ ]
866
884
 
867
885
  return intercept, se_intercept, rse_intercept, r2, 'mswd', [a, b, c], 'se', \
868
886
  lambda x: [_pow_func(i, a, b, c) for i in x], m_ssresid
869
887
 
870
888
 
871
889
  def exponential(a0: list, a1: list):
872
- """
873
- :param a0: known_y's, y = a * b ^ x + c
874
- :param a1: known_x's
875
- :return: intercept | standard error of intercept | relative error | R2 | MSWD | [m, c, b] | [sem, sec, seb]
876
- """
890
+ try:
891
+ k = _exponential(a0, a1, newton_minimize_1d)
892
+ if k[2] > 100:
893
+ raise ValueError
894
+ if abs(k[0] - min(a0)) > 5 * (max(a0) - min(a0)):
895
+ raise ValueError
896
+ except Exception as e:
897
+ print(f"newton_minimize_1d failed, using grad minimize")
898
+ k = _exponential(a0, a1, grad_minimize)
899
+ return k
877
900
 
878
- def _exp_func(x, a, b, c):
879
- return a * b ** x + c
880
901
 
881
- def _residuals(params):
882
- a, b, c = params
883
- return [_exp_func(xi, a, b, c) - yi for xi, yi in zip(a1, a0)]
902
+ def _exponential(a0, a1, method):
884
903
 
885
- def _sum_squared_error(params):
886
- return sum(r**2 for r in _residuals(params))
904
+ X = np.array(a1)
905
+ Y = np.array(a0)
906
+ y = np.array([a0]).transpose()
887
907
 
888
- def _get_ac(b):
889
- f = linest(a0, [b ** xi for xi in a1])
890
- return f[5][1], b, f[0]
908
+ def _exp_func(xi, a, b, c):
909
+ return a * np.exp(b * xi) + c
910
+
911
+ @np.vectorize
912
+ def _get_s(b):
913
+ x = np.concatenate(([np.ones(len(a1))], [np.exp(b * np.array(a1))]), axis=0).transpose()
914
+ try:
915
+ inv_xtx = np.linalg.inv(np.matmul(x.transpose(), x))
916
+ except np.linalg.LinAlgError:
917
+ raise np.linalg.LinAlgError(f"The determinant of the given matrix must not be zero ")
918
+ beta = np.matmul(inv_xtx, np.matmul(x.transpose(), y))
919
+ c, a = beta.flatten()
920
+ reg_y = _exp_func(X, a, b, c)
921
+ resid = (reg_y - Y) ** 2
922
+ ssresid = sum(resid)
923
+ return ssresid
924
+
925
+ # 1阶
926
+ ini_f1 = linest(Y, X)
927
+ y_range = max(Y) - min(Y)
928
+ ini_b = ini_f1[5][1] / max(y_range, 1e-12)
929
+ # 2阶
930
+ ini_f2 = quadratic(Y, X)
931
+ ini_b *= np.sign(ini_f1[5][1]) * np.sign(ini_f2[5][2])
932
+
933
+ b, count = method(_get_s, ini_b)
934
+
935
+ x = np.concatenate(([np.ones(len(a1))], [np.exp(b * np.array(a1))]), axis=0).transpose()
936
+
937
+ m, n = x.shape # number of data, number of unknown x
938
+ try:
939
+ inv_xtx = np.linalg.inv(np.matmul(x.transpose(), x))
940
+ except np.linalg.LinAlgError:
941
+ raise np.linalg.LinAlgError(f"The determinant of the given matrix must not be zero ")
942
+ beta = np.matmul(inv_xtx, np.matmul(x.transpose(), y))
943
+ estimate_y = np.matmul(x, beta)
944
+ resid = (estimate_y - y) ** 2
945
+ reg = (estimate_y - np.mean(y)) ** 2
946
+ ssresid = resid.sum() # 残差平方和
947
+ ssreg = reg.sum() # 回归平方和
948
+ sstotal = ((y - np.mean(y)) ** 2).sum()
949
+ r2 = ssreg / sstotal if sstotal != 0 else 1
891
950
 
892
- def _get_init():
893
- f = linest(np.log(np.array(a0)), np.array(a1))
894
- return np.exp(f[0]), np.exp(f[5][1]), 0
951
+ df = m - n
952
+ m_ssresid = ssresid / df # 均方残差,与加权平均中的MSWD对应
953
+ cov_beta = m_ssresid * inv_xtx
895
954
 
896
- try:
897
- a, b, c = _get_init()
898
- # a, b, c = minimize(_sum_squared_error, [a, b, c], method="Nelder-Mead").x # 优化方法
899
- count = 0
900
- step = 0.01
901
- while count < 100:
902
- a, b, c = _get_ac(b)
903
- s = _sum_squared_error([a, b, c])
904
- b_left, b_right = b - step * b, b + step * b
905
- s_left = _sum_squared_error(_get_ac(b_left))
906
- s_right = _sum_squared_error(_get_ac(b_right))
907
- if s_left > s > s_right:
908
- b = b_right
909
- continue
910
- elif s_left < s < s_right:
911
- b = b_left
912
- continue
913
- elif s_left < s_right:
914
- b = (b + b_left) / 2
915
- else:
916
- b = (b + b_right) / 2
917
- count += 1
918
- step = step * 0.5
919
- if step < 0.000001:
920
- break
955
+ sc, sa = np.diagonal(cov_beta) ** .5
956
+ c, a = beta.flatten()
957
+ intercept = a + c
958
+ se_intercept = pow(sa ** 2 + sc ** 2 + 2 * cov_beta[0][1] , 0.5)
921
959
 
922
- except RuntimeError:
923
- raise RuntimeError
924
- except np.linalg.LinAlgError:
925
- raise np.linalg.LinAlgError
926
- except TypeError:
927
- raise TypeError
928
- except IndexError:
929
- raise IndexError
960
+ exp_beta = [a, b, c]
961
+ exp_cov_beta = [
962
+ [cov_beta[1][1], 0, cov_beta[1][0]],
963
+ [0, 0, 0],
964
+ [cov_beta[0][1], 0, cov_beta[0][0]],
965
+ ]
930
966
 
931
- f = linest(a0, [b ** xi for xi in a1])
932
- a, sea, c, sec = f[5][1], f[6][1], f[0], f[1]
967
+ # print(f"{b = }, {a = }, {c = }, {count = }, {ssresid = }, {r2 = }")
933
968
 
934
- calculated_y = [_exp_func(i, a, b, c) for i in a1]
935
- resid = [(calculated_y[i] - a0[i]) ** 2 for i in range(len(a0))]
936
- reg = [(i - sum(calculated_y) / len(calculated_y)) ** 2 for i in calculated_y]
937
- ssresid = sum(resid)
938
- ssreg = sum(reg)
939
- sstotal = ssreg + ssresid
940
- dp = len(a1)
941
- df = dp - 1
942
- m_ssresid = ssresid / df
943
- r2 = ssreg / sstotal if sstotal != 0 else 1
969
+ return intercept, se_intercept, se_intercept / abs(intercept) * 100, r2, m_ssresid, exp_beta, exp_cov_beta, \
970
+ lambda x: [_exp_func(xi, a, b, c) for xi in x], m_ssresid
944
971
 
945
- z = [b ** xi for xi in a1]
946
- intercept = a + c
947
- se_intercept_1 = np.sqrt(sea ** 2 + sec ** 2)
948
- # calculate error of intercept
949
- errfz = pow(sum([i ** 2 for i in z]) / (dp * sum([i ** 2 for i in z]) - sum(z) ** 2), 0.5)
950
- errfx = pow(sum([i ** 2 for i in a1]) / (dp * sum([i ** 2 for i in a1]) - sum(a1) ** 2), 0.5)
951
- # seb = errfz * sey = errfz * ssresid / df -> se_intercept = sey * errfx = seb / errfz * errfx
952
- se_intercept = sec / errfz * errfx
953
- rse_intercept = se_intercept / intercept * 100
954
972
 
955
- return intercept, se_intercept, rse_intercept, r2, 'mswd', [a, b, c], 'se', \
956
- lambda x: [_exp_func(i, a, b, c) for i in x], m_ssresid
973
+ def newton_minimize_1d(func, x0, h=1e-5, tol=1e-8, max_iter=30):
974
+ x = x0
975
+ for i in range(max_iter):
976
+ fx = func(x)
977
+ if not np.isfinite(fx):
978
+ raise ValueError("Newton Minimize: Function returned non-finite value at x={}".format(x))
979
+
980
+ # 一阶导数(中心差分)
981
+ f_plus = func(x + h)
982
+ f_minus = func(x - h)
983
+ if not (np.isfinite(f_plus) and np.isfinite(f_minus)):
984
+ raise ValueError("Newton Minimize: Non-finite values in derivative computation")
985
+ df = (f_plus - f_minus) / (2 * h)
986
+ d2f = (f_plus - 2 * fx + f_minus) / (h * h)
987
+
988
+ # 牛顿步长
989
+ if abs(d2f) < 1e-12: # 避免除零或平坦区域
990
+ raise ValueError("Newton Minimize: Second derivative too small, stopping.")
991
+
992
+ step = df / d2f
993
+ x_new = x - step
994
+
995
+ if abs(step) < tol:
996
+ x = x_new
997
+ break
998
+
999
+ x = x_new
1000
+
1001
+ if i + 1 == max_iter:
1002
+ raise ValueError("Newton Minimize: Over iteration max_iter={}".format(max_iter))
1003
+
1004
+ return x, i + 1
1005
+
1006
+
1007
+ def grad_minimize(func, x, lr=1e-5, tol=1e-8, max_iter=1000):
1008
+
1009
+ for i in range(max_iter):
1010
+ f_plus = func(x + lr)
1011
+ f_minus = func(x - lr)
1012
+ if not (np.isfinite(f_plus) and np.isfinite(f_minus)):
1013
+ raise ValueError("Newton Minimize: Non-finite values in derivative computation")
1014
+ g = (f_plus - f_minus) / (2 * lr)
1015
+ x_new = x - lr * g
1016
+ if abs(func(x_new) - func(x)) < tol:
1017
+ break
1018
+ x = x_new
1019
+ return x, i+1
957
1020
 
958
1021
 
959
1022
  """ line functions """
960
1023
 
961
1024
 
962
- def linear_eq(x: list, beta: list):
1025
+ def linest_var(beta: list, cov: list, x: float):
1026
+ """ y = b0 * x^0 + b1 * x^1 + ... + bn * x^n
1027
+ Parameters
1028
+ ----------
1029
+
1030
+ Returns
1031
+ -------
1032
+
1033
+ """
1034
+ beta = np.array(beta, dtype=np.float64)
1035
+ cov_matrix = np.array(cov, dtype=np.float64)
1036
+ g = np.array([x ** k for k in range(len(beta))]).reshape(-1, 1)
1037
+ y = np.dot(g.T, beta.reshape(-1, 1))[0, 0]
1038
+ var = np.matmul(np.matmul(g.T, cov_matrix), g)[0, 0]
1039
+ return y, var
1040
+
1041
+
1042
+ def quadratic_var(beta: list, cov: list, x: float):
1043
+ """ y = b0 * x^0 + b1 * x^1 + b2 * x^2
1044
+ Parameters
1045
+ ----------
1046
+ beta : coefficients
1047
+ x :
1048
+
1049
+ Returns
1050
+ -------
1051
+
1052
+ """
1053
+ beta = np.array(beta, dtype=np.float64)
1054
+ cov_matrix = np.array(cov, dtype=np.float64)
1055
+ g = np.array([x ** k for k in range(len(beta))]).reshape(-1, 1)
1056
+ y = np.dot(g.T, beta.reshape(-1, 1))[0, 0]
1057
+ var = np.matmul(np.matmul(g.T, cov_matrix), g)[0, 0]
1058
+ return y, var
1059
+
1060
+
1061
+ def average_var(beta: list, cov: list, x: float):
963
1062
  """ y = b0 * x^0 + b1 * x^1 + ... + bn * x^n
964
1063
  Parameters
965
1064
  ----------
@@ -970,21 +1069,29 @@ def linear_eq(x: list, beta: list):
970
1069
  -------
971
1070
 
972
1071
  """
973
- return [np.prod([beta, [_x ** i for i in range(len(beta))]], axis=0).sum() for _x in x]
1072
+ y, = beta
1073
+ var = np.array(cov, dtype=np.float64)[0, 0]
1074
+ return y, var
974
1075
 
975
1076
 
976
- def exponential_eq(x: list, beta: list):
977
- """ y = a * b ^ x + c
1077
+ def exponential_var(beta: list, cov: list, x: float):
1078
+ """ y = a * exp(bx) + c
978
1079
  Parameters
979
1080
  ----------
980
1081
  beta : coefficients, [a, b, c]
981
- x :
1082
+ cov : covariance [[], [], []]
982
1083
 
983
1084
  Returns
984
1085
  -------
985
1086
 
986
1087
  """
987
- return [beta[0] * beta[1] ** _x + beta[0] for _x in x]
1088
+ cov_matrix = np.array(cov)
1089
+ a, b, c = beta
1090
+ k = np.exp(b*x)
1091
+ g = np.array([k, a*x*k, 1]).reshape(-1, 1)
1092
+ y = a * k + c
1093
+ var = np.matmul(np.matmul(g.T, cov_matrix), g)[0, 0]
1094
+ return y, var
988
1095
 
989
1096
 
990
1097
  def power_eq(x: list, beta: list):
@@ -493,40 +493,41 @@ def open_full_xls(file_path: str, sample_name: str = ''):
493
493
  res['Inverse Isochron Table'], rows, [4, 5, 6, 7, 10])
494
494
  total_param = arr.partial(
495
495
  res['Sample Parameters'], rows, [
496
- # 1, 2, # 0-1
497
- -1, -1, -1, -1, # 2-5
498
- -1, -1, -1, -1, # 6-9
499
- -1, -1, -1, -1, -1, -1, # 10-15
500
- -1, -1, -1, -1, # 16-19
501
- -1, -1, # 20-21
502
- 23, 24, -1, -1, -1, -1, # 22-27
503
- -1, -1, # 28-29
504
- 22, -1, -1, -1, # 30-33
505
- -1, -1, # 34-35
506
- -1, -1, # 36-37
507
- -1, -1, # 38-39
508
- -1, -1, # 40-41
509
- -1, -1, # 42-43
510
- -1, -1, # 44-45
511
- -1, -1, # 46-47
512
- -1, -1, # 48-49
513
- -1, -1, # 50-51
514
- -1, -1, # 52-53
515
- -1, -1, # 54-55
516
- -1, -1, # 56-57
517
- -1, -1, # 58-59
518
- -1, -1, -1, -1, -1, -1, -1, -1, -1, # 60-68
519
- 10, 11, 12, 13, # 69-72
520
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, # 73-84
521
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, # 85-94
522
- -1, -1, -1, -1, # 95-98
523
- -1, -1, -1, -1, # 99-102
524
- -1, -1, -1, -1, # 103-106
525
- -1, -1, -1, -1, # 107-110
526
- -1, -1, -1, -1, # 111-114
527
- -1, -1, -1, -1, -1, -1, -1, -1, # 115-122
528
- -1, -1, -1, -1, -1, -1, -1, -1, # 123-130
529
- -1, -1, -1, -1, -1, # 131-135
496
+ # 1, 2, -1, # 0-2
497
+ -1, -1, -1, -1, # 3-6
498
+ -1, -1, -1, -1, # 7-10
499
+ -1, -1, -1, -1, -1, -1, # 11-16
500
+ -1, -1, -1, -1, # 17-20
501
+ -1, -1, # 21-22
502
+ 23, 24, -1, -1, -1, -1, # 23-28
503
+ -1, -1, # 29-30
504
+ 22, -1, -1, -1, # 31-34
505
+ -1, -1, # 35-36
506
+ -1, -1, # 37-38
507
+ -1, -1, # 39-40
508
+ -1, -1, # 41-42
509
+ -1, -1, # 43-44
510
+ -1, -1, # 45-46
511
+ -1, -1, # 47-48
512
+ -1, -1, # 49-50
513
+ -1, -1, # 51-52
514
+ -1, -1, # 53-54
515
+ -1, -1, # 55-56
516
+ -1, -1, # 57-58
517
+ -1, -1, # 59-60
518
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, # 61-69
519
+ 10, 11, 12, 13, # 70-73
520
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, # 74-85
521
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, # 86-95
522
+ -1, -1, -1, -1, # 96-99
523
+ -1, -1, -1, -1, # 100-103
524
+ -1, -1, -1, -1, # 104-107
525
+ -1, -1, -1, -1, # 108-111
526
+ -1, -1, -1, -1, # 112-115
527
+ -1, -1, -1, -1, -1, -1, -1, -1, # 116-123
528
+ -1, -1, -1, -1, -1, -1, -1, -1, # 124-131
529
+ -1, -1, -1, -1, -1, # 132-136
530
+ -1, -1, -1, -1, # 137-140
530
531
  ])
531
532
 
532
533
  month_convert = {'Jan': '01', 'Feb': '02', 'Mar': '03', 'Apr': '04', 'May': '05', 'Jun': '06',