Создать DataFrame из указанной c функции Python - PullRequest
0 голосов
/ 14 июля 2020

Я пытаюсь создать новый фрейм данных (df_new) из специальной c функции (stats.boxcox), примененной к исходному фрейму даты (df). Обратите внимание, что функция stats.boxcox создает две новые переменные, которые захватываются df_new [column] и lam. Хотя мой код может выполнять задачу очень медленно. Есть ли способ сделать это более эффективным способом в Python?

import numpy as np
import pandas as pd
from scipy import stats

df_new = pd.DataFrame()
for column in list(df):
        df_new[column], lam = stats.boxcox(df[column])

Ответы [ 2 ]

1 голос
/ 17 июля 2020

Я профилировал функцию. У меня есть одно решение, оно может работать только для предоставленного вами образца базы данных.

Timer unit: 1e-07 s

Total time: 0.629038 s
File: C:\Users\@user@\AppData\Roaming\Python\Python37\site-packages\scipy\stats\morestats.py
Function: boxcox at line 948

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
   948                                           def boxcox(x, lmbda=None, alpha=None):
   949                                               r"""
   950                                               Return a dataset transformed by a Box-Cox power transformation.
   951                                           
   952                                               Parameters
   953                                               ----------
   954                                               x : ndarray
   955                                                   Input array.  Must be positive 1-dimensional.  Must not be constant.
   956                                               lmbda : {None, scalar}, optional
   957                                                   If `lmbda` is not None, do the transformation for that value.
   958                                           
   959                                                   If `lmbda` is None, find the lambda that maximizes the log-likelihood
   960                                                   function and return it as the second output argument.
   961                                               alpha : {None, float}, optional
   962                                                   If ``alpha`` is not None, return the ``100 * (1-alpha)%`` confidence
   963                                                   interval for `lmbda` as the third output argument.
   964                                                   Must be between 0.0 and 1.0.
   965                                           
   966                                               Returns
   967                                               -------
   968                                               boxcox : ndarray
   969                                                   Box-Cox power transformed array.
   970                                               maxlog : float, optional
   971                                                   If the `lmbda` parameter is None, the second returned argument is
   972                                                   the lambda that maximizes the log-likelihood function.
   973                                               (min_ci, max_ci) : tuple of float, optional
   974                                                   If `lmbda` parameter is None and ``alpha`` is not None, this returned
   975                                                   tuple of floats represents the minimum and maximum confidence limits
   976                                                   given ``alpha``.
   977                                           
   978                                               See Also
   979                                               --------
   980                                               probplot, boxcox_normplot, boxcox_normmax, boxcox_llf
   981                                           
   982                                               Notes
   983                                               -----
   984                                               The Box-Cox transform is given by::
   985                                           
   986                                                   y = (x**lmbda - 1) / lmbda,  for lmbda > 0
   987                                                       log(x),                  for lmbda = 0
   988                                           
   989                                               `boxcox` requires the input data to be positive.  Sometimes a Box-Cox
   990                                               transformation provides a shift parameter to achieve this; `boxcox` does
   991                                               not.  Such a shift parameter is equivalent to adding a positive constant to
   992                                               `x` before calling `boxcox`.
   993                                           
   994                                               The confidence limits returned when ``alpha`` is provided give the interval
   995                                               where:
   996                                           
   997                                               .. math::
   998                                           
   999                                                   llf(\hat{\lambda}) - llf(\lambda) < \frac{1}{2}\chi^2(1 - \alpha, 1),
  1000                                           
  1001                                               with ``llf`` the log-likelihood function and :math:`\chi^2` the chi-squared
  1002                                               function.
  1003                                           
  1004                                               References
  1005                                               ----------
  1006                                               G.E.P. Box and D.R. Cox, "An Analysis of Transformations", Journal of the
  1007                                               Royal Statistical Society B, 26, 211-252 (1964).
  1008                                           
  1009                                               Examples
  1010                                               --------
  1011                                               >>> from scipy import stats
  1012                                               >>> import matplotlib.pyplot as plt
  1013                                           
  1014                                               We generate some random variates from a non-normal distribution and make a
  1015                                               probability plot for it, to show it is non-normal in the tails:
  1016                                           
  1017                                               >>> fig = plt.figure()
  1018                                               >>> ax1 = fig.add_subplot(211)
  1019                                               >>> x = stats.loggamma.rvs(5, size=500) + 5
  1020                                               >>> prob = stats.probplot(x, dist=stats.norm, plot=ax1)
  1021                                               >>> ax1.set_xlabel('')
  1022                                               >>> ax1.set_title('Probplot against normal distribution')
  1023                                           
  1024                                               We now use `boxcox` to transform the data so it's closest to normal:
  1025                                           
  1026                                               >>> ax2 = fig.add_subplot(212)
  1027                                               >>> xt, _ = stats.boxcox(x)
  1028                                               >>> prob = stats.probplot(xt, dist=stats.norm, plot=ax2)
  1029                                               >>> ax2.set_title('Probplot after Box-Cox transformation')
  1030                                           
  1031                                               >>> plt.show()
  1032                                           
  1033                                               """
  1034         2        153.0     76.5      0.0      x = np.asarray(x)
  1035         2         55.0     27.5      0.0      if x.ndim != 1:
  1036                                                   raise ValueError("Data must be 1-dimensional.")
  1037                                           
  1038         2         41.0     20.5      0.0      if x.size == 0:
  1039                                                   return x
  1040                                           
  1041         2     168219.0  84109.5      2.7      if np.all(x == x[0]):
  1042                                                   raise ValueError("Data must not be constant.")
  1043                                           
  1044         2      67990.0  33995.0      1.1      if any(x <= 0):
  1045                                                   raise ValueError("Data must be positive.")
  1046                                           
  1047         2         47.0     23.5      0.0      if lmbda is not None:  # single transformation
  1048         1     161912.0 161912.0      2.6          return special.boxcox(x, lmbda)
  1049                                           
  1050                                               # If lmbda=None, find the lmbda that maximizes the log-likelihood function.
  1051         1    5891911.0 5891911.0     93.7      lmax = boxcox_normmax(x, method='mle')
  1052         1         29.0     29.0      0.0      y = boxcox(x, lmax)
  1053                                           
  1054         1         15.0     15.0      0.0      if alpha is None:
  1055         1          8.0      8.0      0.0          return y, lmax
  1056                                               else:
  1057                                                   # Find confidence interval
  1058                                                   interval = _boxcox_conf_interval(x, lmax, alpha)
  1059                                                   return y, lmax, interval

Как видите, большая часть времени, затрачиваемого функцией, проходит на вычисление лямбда. Я уверен, что повышение эффективности функции получения лямбда должно быть предметом исследования, но вот быстрое решение, если ваши данные похожи на мой образец данных.

In:

    %%timeit
for column in df.columns:
    stats.boxcox(df[column])

Out :

1min 59s ± 2.46 s per loop (mean ± std. dev. of 7 runs, 1 loop each)

Если вы распечатываете результаты, в моем примере это привело к тому, что все лямбды были около некоторого числа с плавающей запятой: 0.71 ...

(array([24.3917785 , 26.59336098, 28.42778141, ...,  0.89856936,
       20.09087919, 25.34396741]), 0.7191265555780741)
(array([32.21200102, 21.42019555, 17.61088955, ...,  2.37689377,
       11.43847546,  4.80996571]), 0.7186638451956158)
(array([32.04912451,  5.34619315,  2.37388797, ..., 28.25042847,
       21.65944327, 35.68435748]), 0.717094388354133)
(array([24.12034838, 20.22153029, 17.46007125, ...,  9.20987077,
       27.79432177, 28.38850624]), 0.7152672101519897)
(array([24.43175536, 29.97646547, 15.44100467, ..., 29.67889106,
       33.75136616, 18.01618903]), 0.719690932457849)
(array([31.3006977 , 14.24153427,  8.80686258, ..., 27.74442602,
       29.54262716,  5.35448321]), 0.7182204065752503)
(array([ 0.89885059, 33.21042971,  7.41516615, ..., 26.66002733,
       32.05761174,  2.37938055]), 0.719960442157806)
(array([18.75921571, 20.15657425, 32.38744267, ..., 32.09731377,
       34.95687043, 33.82390653]), 0.7203446358711867)
(array([30.61614136, 16.82387108, 23.61599906, ..., 26.74368558,
       26.43727409, 26.43727409]), 0.7171650690241015)
(array([32.03243895, 18.46213843, 15.23999702, ..., 33.70140582,
       34.52403407,  7.82011755]), 0.7141993257439302)
(array([16.39388107, 20.23652878, 25.38777257, ..., 27.81775952,
        3.63937585, 12.98507701]), 0.7155422854115251)
(array([23.84209605, 24.47289056, 32.48229038, ..., 29.90484308,
       11.37093225,  6.8765052 ]), 0.7158092390730108)

Вы можете вычислить среднее значение первого N значений и используйте его для остальных. После запуска всей базы данных ни одно значение не изменилось, значение + - стандартное отклонение. Используйте его как второй аргумент в функции stats.boxcox.

In:

%%timeit
for column in df.columns:
    stats.boxcox(df[column], 0.715)

Out:

3.67 s ± 116 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Как я уже говорил, это может быть проще исследование либо с исходной базой данных, либо с резервной копией компании. Удачи!

1 голос
/ 14 июля 2020

Не могли бы вы предоставить образец фрейма данных? Я могу придумать ...

df.apply(lambda x: stats.boxcox(x))

Но трудно найти подходящий способ без образца базы данных. (Я не могу комментировать, поскольку у меня недостаточно репутации) Спасибо!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...