「ipython notebook」を使って簡単にタスク管理してみる。(3)

タスクの追加状況をグラフにしてみました。

以下を追加します。

import json
import pandas_highcharts.core
js_name_1 = '//code.highcharts.com/highcharts'
js_name_2 = '//code.highcharts.com/modules/exporting'
def graph_render(data):
  chart1 = pandas_highcharts.core.serialize(data, title=title_name, zoom="xy", output_type='dict')
  html = HTML('''
  <div id="chart1" style="min-width: 400px; height: 400px; margin: 0 auto"></div>
  <script>
    require.config({
      paths: {
        highcharts: '%s',
        exporting: '%s'
      }
    });
    require(['highcharts','exporting'], function(){
      $('#chart1').highcharts(%s);
    });
  </script>
  ''' %(js_name_1, js_name_2, json.dumps(chart1)))
  return html
    
def graph_task():
  data = read_task()
  data['datetime'] = pandas.to_datetime(data['created_at'])
  data['count'] = data['name'].count()
  data = data.groupby([data['datetime'].dt.year, data['datetime'].dt.month, data['datetime'].dt.day])['count'].count()
  data = pandas.DataFrame(data)
  return graph_render(data)

それで、graph_task() を呼び出すと

こんな感じに表示されます。
pandasのgroupbyで、日付ごとにグルーピングして
pandas_highchartsで、highchart用のjsonに変換。
それからhighchartsで、グラフを描画しています。

https://pypi.python.org/pypi/tasks-for-notebook
https://github.com/llby/tasks-for-notebook

こちらの方にも、そのうち追加したいと思います。

「ipython notebook」を使って簡単にタスク管理してみる。(2)

前回の続きです。
updateのところが、あまりにアレだったので
少し書き換えました。

def update_task(id, **kwargs):
  data = read_task()
  if kwargs.get('name'):
    data['name'][id] = kwargs.get('name')
  if kwargs.get('content'):
    data['content'][id] = kwargs.get('content')
  if kwargs.get('status'):
    data['status'][id] = kwargs.get('status')
  save_task(data)

キーワード引数にしてみました。

update_task(0, status='done')

こんな感じでステータスを更新出来ます。
1つ目の引数はIDです。

update_task(1, name='次のタスク【優先】', content='pythonで、コードを書く。')

こうすると名前と内容が更新出来ます。

そして削除は下記の感じです。

delete_task(1)

削除したIDは欠番になります。
(ただし、add_taskするとリセットされます。)

という訳で、PyPIに登録してみました。

pip install tasks-for-notebook

これでインストール出来ます。
使い方は下記の感じです。

from tasks_for_notebook import *
show_task()

ごちゃごちゃしたものが無くなって、すっきりします。

https://pypi.python.org/pypi/tasks-for-notebook
https://github.com/llby/tasks-for-notebook

もうちょっと機能追加してみたいと思います。
それでは、、、

「ipython notebook」を使って簡単にタスク管理してみる。

ipython notebook便利と思っていたんですが、
これで、そのままタスク管理も出来たらいいなと思って試しに作ってみました。
かなり簡単に作ったというのもありますが、サクッと出来てしまいます。
前回に続き、dataTablesも使っています。
データのCRUDには、pandasを使っています。
(notebook、pandasのインストールの説明は省略します。)

import pandas
from IPython.display import Javascript
from IPython.display import HTML
title_name = 'Tasks'
file_name = 'tasks.csv'
css_name = '//cdn.datatables.net/1.10.12/css/jquery.dataTables.min.css'
js_name = '//cdn.datatables.net/1.10.12/js/jquery.dataTables.min'
def read_task():
  if os.path.exists(file_name):
    return pandas.DataFrame.from_csv(file_name)
  else:
    return pandas.DataFrame()

def save_task(data):
  pandas.DataFrame(data).to_csv(file_name)

def add_task(name, content):
  data = read_task()
  df = pandas.DataFrame([{'name':name,'content':content,'status':'new'}], columns = ['name','content','status'])
  data = data.append(df, ignore_index=True)
  save_task(data)

def show_task():
  data = read_task()
  js = '''
    <link rel='stylesheet' type='text/css' href='%s'>
    <script>
      require.config({
        paths: {
          dataTables: '%s'
        }
     });
      require(['dataTables'], function(){
        $('.dataframe').DataTable();
      });
    </script>
  '''%(css_name, js_name)
  return HTML('<h2>%s</h2>'%(title_name) + data.to_html() + js)

def update_task(id, name, content, status):
  data = read_task()
  data['name'][id] = name
  data['content'][id] = content
  data['status'][id] = status
  save_task(data)

def delete_task(id):
  data = read_task()
  data = data.drop(id)
  save_task(data)

3つのセルに、これらをコピーして早速使ってみます。
4つ目のセルに下記を入力して、実行(Shift + Enter)してみましょう。

show_task()

まだ、何のタスクもありませんが
もうタスク管理っぽいものが出来ていますね。
5つ目のセルで、タスクを追加してみましょう。

add_task('最初のタスク','githubに、repositoryを準備する')

これを実行(Shift + Enter)した後で、
また4つ目のセルに戻って実行(Shift + Enter)します。

タスクが追加されました。
taskwarriorっぽい雰囲気ですね。https://taskwarrior.org/
これを繰り返していくと、タスクがどんどん追加されます。

あと、削除と更新も出来ますが
疲れてきたので、また次回に・・・

ipythonでdatatablesを使う

何かと便利なipythonですが、datatablesも使えます。
datatablesとは、https://datatables.net/
です。

多分見てもらう方が早いと思います。
早速使い方ですが、

from IPython.display import HTML
%%javascript
require.config({
  paths: {
    dataTables: '//cdn.datatables.net/1.10.12/js/jquery.dataTables.min'
  }
});
HTML('''
<link rel="stylesheet" type="text/css" href="http://cdn.datatables.net/1.10.12/css/jquery.dataTables.min.css">
<table id="example" class="display" cellspacing="0" width="100%">
  <thead>
    <tr>
      <th>Name</th>
      <th>Position</th>
      <th>Office</th>
      <th>Age</th>
      <th>Start date</th>
      <th>Salary</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Tiger Nixon</td>
      <td>System Architect</td>
      <td>Edinburgh</td>
      <td>61</td>
      <td>2011/04/25</td>
      <td>$320,800</td>
    </tr>
    <tr>
      <td>Garrett Winters</td>
      <td>Accountant</td>
      <td>Tokyo</td>
      <td>63</td>
      <td>2011/07/25</td>
      <td>$170,750</td>
    </tr>
    <tr>
      <td>Ashton Cox</td>
      <td>Junior Technical Author</td>
      <td>San Francisco</td>
      <td>66</td>
      <td>2009/01/12</td>
      <td>$86,000</td>
    </tr>
  </tbody>
</table>
<script>
  require(['dataTables'], function(){
    $('#example').DataTable();
  });
</script>
''')

とりあえず、これだけでも動きます。

デフォルトで、インクリメンタルサーチとページャが付きます。
他にもオプションで、いくつか機能があります。
CSVダウンロードとか便利で使っています。


今回のサンプルでは、tableタグを直書きしていますが
pandasのDataFrameから、「to_html」するとtableタグが出力されるので
それに、datatablesをかませるとかいう使い方も出来ます。


便利ですね。
それでは、、、

pythonのpandasとnotebookとstatsmodelとscipyを使ってデータ分析(8)

いよいよ最後ですね。指数近似曲線です。
さて、ここからが問題です。
これを最後に持ってきたのは、問題を先送りに・・・してました。

再度、こちらを参考にさせて頂いて
http://daisukekobayashi.com/blog/python-least-square-method-exponential-approximation/
とりあえずコードは、こんな感じになりました。

%matplotlib inline
import pandas
import numpy
import matplotlib.pyplot as plt
import statsmodels.formula.api as smf
import scipy.optimize
df = pandas.DataFrame({
        'x': [6.559112404564946264e-01,
                 6.013845740818111185e-01,
                 4.449591514877473397e-01,
                 3.557250387126167923e-01,
                 3.798882550532960423e-01,
                 3.206955701106445344e-01,
                 2.600880460776140990e-01,
                 2.245379618606005157e-01],
         'y': [1.397354195522357567e-01,
                 1.001406990711011247e-01,
                 5.173231204524778720e-02,
                 3.445520251689743879e-02,
                 3.801366557283047953e-02,
                 2.856782588754304408e-02,
                 2.036328213585812327e-02,
                 1.566228252276009869e-02]})
axes = []
fig = plt.figure(figsize=(15,6))
for i, title in enumerate(["ols fit", "Linear exp fit", "log fit", "parabora fit"]):
    axes.append(fig.add_subplot(2, 2, i+1))
    axes[i].sharey = axes[0]
    axes[i].plot(df['x'], df['y'], "ro")
    axes[i].set_title(title)
    axes[i].grid()

str = "Sample Data"
str1 = "Fitted Function:\n"

def r2_string(r):
    return "$R^{2} = %0.5f$" % (r)

def ols_string(a, b, c):
    str2 = "$y = %0.4f x %s %0.4f$\n" % (a, "+" if b >= 0 else "", b)
    return [str, str1 + str2 + r2_string(c)]

def exp_string(a, b, c):
    str2 = "$y = %0.4f e^{ %0.4f x}$\n" % (a, b)
    return [str, str1 + str2 + r2_string(c)]

def log_string(a, b, c):
    str2 = "$y = %0.4f ln(x) %s %0.4f$\n" % (a, "+" if b >= 0 else "", b)
    return [str, str1 + str2 + r2_string(c)]

def pab_string(a, b, c, d):
    str2 = "$y = %0.4f x^{2} %s %0.4f x %s %0.4f$\n" % (a, "+" if b >= 0 else "", b, "+" if c >= 0 else "", c)
    return [str, str1 + str2 + r2_string(d)]

def func_ols(a, b, x):
    return a * x + b

def func_exp(a, b, x):
    return a * numpy.exp(b * x)

def func_log(a, b, x):
    return a * numpy.log(x) + b

def func_pab(a, b, c, x):
    return a * x**2 + b * x + c

def square(x):
    return x ** 2

def fit_exp_linear(parameter, x, y):
    a = parameter[0]
    b = parameter[1]
    residual = numpy.log(y) - (numpy.log(a) + b * x)
    return residual

xx = numpy.arange(0.7, 0.2, -0.01)
parameter0 = [1, 1]

model1 = pandas.ols(y=df['y'], x=df['x'], intercept=True)
model2 = scipy.optimize.leastsq(fit_exp_linear, parameter0, args=(df['x'], df['y']))
model3 = smf.ols(formula='y ~ numpy.log(x)', data=df).fit()
model4 = smf.ols(formula='y ~ square(x) + x', data=df).fit()
#print model1
#print model3.summary()
#print model4.summary()

axes[0].plot(xx, func_ols(model1.beta.x, model1.beta.intercept, xx))
axes[1].plot(xx, func_exp(model2[0][0], model2[0][1], xx))
axes[2].plot(xx, func_log(model3.params['numpy.log(x)'], model3.params['Intercept'], xx))
axes[3].plot(xx, func_pab(model4.params['square(x)'], model4.params['x'], model4.params['Intercept'], xx))

axes[0].legend(ols_string(model1.beta.x, model1.beta.intercept, model1.r2), loc="upper left")
axes[1].legend(exp_string(model2[0][0], model2[0][1], 0), loc="upper left")
axes[2].legend(log_string(model3.params['numpy.log(x)'], model3.params['Intercept'], model3.rsquared), loc="upper left")
axes[3].legend(pab_string(model4.params['square(x)'], model4.params['x'], model4.params['Intercept'], model4.rsquared), loc="upper left")
plt.show()

こんな感じになります。
グラフ的には、エクセルと同じのようです。

今回は、「scipy.optimize.leastsq」を新たに使っています。
こちらの方が、「formula」に自由度が高いと思います。
(statsmodelの使い方が分かっていないだけかも知れませんが・・・)
「formula」の自由度から言うと、
「pandas.ols」<「smf.ols」<「scipy.optimize.leastsq」だと思います。


そして、R2は・・・
「R2-!!!」
と叫びたくなります。
出ていないですね・・・


検証に関しては、「pandas.ols」<「smf.ols」
という感じで、「scipy.optimize.leastsq」は?となります。

ちなみに、こうやると・・・

model2 = smf.ols(formula='numpy.log(y) ~ x', data=df).fit()
print model2.summary()

「R-squared」的には、エクセルと同じ値が出たりします。
でも、「x」や「Intercept」は違うのでダメですね・・・


誰か教えて・・・

pythonのpandasとnotebookとstatsmodelを使ってデータ分析(7)

さて、どんどんと行きたいと思います。
今回は、多項式近似曲線です。
早速書いてみます。

%matplotlib inline
import pandas
import numpy
import matplotlib.pyplot as plt
import statsmodels.formula.api as smf
df = pandas.DataFrame({
        'x': [6.559112404564946264e-01,
                 6.013845740818111185e-01,
                 4.449591514877473397e-01,
                 3.557250387126167923e-01,
                 3.798882550532960423e-01,
                 3.206955701106445344e-01,
                 2.600880460776140990e-01,
                 2.245379618606005157e-01],
         'y': [1.397354195522357567e-01,
                 1.001406990711011247e-01,
                 5.173231204524778720e-02,
                 3.445520251689743879e-02,
                 3.801366557283047953e-02,
                 2.856782588754304408e-02,
                 2.036328213585812327e-02,
                 1.566228252276009869e-02]})
axes = []
fig = plt.figure(figsize=(15,6))
for i, title in enumerate(["ols fit", "Linear exp fit", "log fit", "parabora fit"]):
    axes.append(fig.add_subplot(2, 2, i+1))
    axes[i].sharey = axes[0]
    axes[i].plot(df['x'], df['y'], "ro")
    axes[i].set_title(title)
    axes[i].grid()

str = "Sample Data"
str1 = "Fitted Function:\n"

def r2_string(r):
    return "$R^{2} = %0.5f$" % (r)

def ols_string(a, b, c):
    str2 = "$y = %0.4f x %s %0.4f$\n" % (a, "+" if b >= 0 else "", b)
    return [str, str1 + str2 + r2_string(c)]

def log_string(a, b, c):
    str2 = "$y = %0.4f ln(x) %s %0.4f$\n" % (a, "+" if b >= 0 else "", b)
    return [str, str1 + str2 + r2_string(c)]

def pab_string(a, b, c, d):
    str2 = "$y = %0.4f x^{2} %s %0.4f x %s %0.4f$\n" % (a, "+" if b >= 0 else "", b, "+" if c >= 0 else "", c)
    return [str, str1 + str2 + r2_string(d)]

def func_ols(a, b, x):
    return a * x + b

def func_log(a, b, x):
    return a * numpy.log(x) + b

def func_pab(a, b, c, x):
    return a * x**2 + b * x + c

def square(x):
    return x ** 2

xx = numpy.arange(0.7, 0.2, -0.01)

model1 = pandas.ols(y=df['y'], x=df['x'], intercept=True)
model3 = smf.ols(formula='y ~ numpy.log(x)', data=df).fit()
model4 = smf.ols(formula='y ~ square(x) + x', data=df).fit()
#print model1
#print model3.summary()
#print model4.summary()

axes[0].plot(xx, func_ols(model1.beta.x, model1.beta.intercept, xx))
axes[2].plot(xx, func_log(model3.params['numpy.log(x)'], model3.params['Intercept'], xx))
axes[3].plot(xx, func_pab(model4.params['square(x)'], model4.params['x'], model4.params['Intercept'], xx))

axes[0].legend(ols_string(model1.beta.x, model1.beta.intercept, model1.r2), loc="upper left")
axes[2].legend(log_string(model3.params['numpy.log(x)'], model3.params['Intercept'], model3.rsquared), loc="upper left")
axes[3].legend(pab_string(model4.params['square(x)'], model4.params['x'], model4.params['Intercept'], model4.rsquared), loc="upper left")
plt.show()

こんな感じで、グラフが以下のようになります。

多項式近似曲線は、「R-squared」が高いですね。
データにかなりフィットしています。

データが変動する場合に適した曲線です。たとえば、大量のデータについて利益と損失を分析する場合に便利です。

だそうです。
参考
https://support.office.com/ja-jp/article/%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AB%E6%9C%80%E9%81%A9%E3%81%AA%E8%BF%91%E4%BC%BC%E6%9B%B2%E7%B7%9A%E3%82%92%E9%81%B8%E6%8A%9E%E3%81%99%E3%82%8B-1bb3c9e7-0280-45b5-9ab0-d0c93161daa8

あと、予測にも適している気がします。
それは、そうですよね?
これはデータに合わせて、フィットさせているような感じなので・・・

それでは、また次回に・・・

pythonのpandasとnotebookとstatsmodelを使ってデータ分析(6)

前回の続きで、指数近似曲線といきたいところですが
ちょっと事情があって、対数近似曲線を先に引いてみたいと思います。

早速ですが、書いてみましょう。

%matplotlib inline
import pandas
import numpy
import matplotlib.pyplot as plt
import statsmodels.formula.api as smf
df = pandas.DataFrame({
        'x': [6.559112404564946264e-01,
                 6.013845740818111185e-01,
                 4.449591514877473397e-01,
                 3.557250387126167923e-01,
                 3.798882550532960423e-01,
                 3.206955701106445344e-01,
                 2.600880460776140990e-01,
                 2.245379618606005157e-01],
         'y': [1.397354195522357567e-01,
                 1.001406990711011247e-01,
                 5.173231204524778720e-02,
                 3.445520251689743879e-02,
                 3.801366557283047953e-02,
                 2.856782588754304408e-02,
                 2.036328213585812327e-02,
                 1.566228252276009869e-02]})
axes = []
fig = plt.figure(figsize=(15,6))
for i, title in enumerate(["ols fit", "Linear exp fit", "log fit", "parabora fit"]):
    axes.append(fig.add_subplot(2, 2, i+1))
    axes[i].sharey = axes[0]
    axes[i].plot(df['x'], df['y'], "ro")
    axes[i].set_title(title)
    axes[i].grid()

str = "Sample Data"
str1 = "Fitted Function:\n"

def r2_string(r):
    return "$R^{2} = %0.5f$" % (r)

def ols_string(a, b, c):
    str2 = "$y = %0.4f x %s %0.4f$\n" % (a, "+" if b >= 0 else "", b)
    return [str, str1 + str2 + r2_string(c)]

def log_string(a, b, c):
    str2 = "$y = %0.4f ln(x) %s %0.4f$\n" % (a, "+" if b >= 0 else "", b)
    return [str, str1 + str2 + r2_string(c)]

def func_ols(a, b, x):
    return a * x + b

def func_log(a, b, x):
    return a * numpy.log(x) + b

xx = numpy.arange(0.7, 0.2, -0.01)

model1 = pandas.ols(y=df['y'], x=df['x'], intercept=True)
model3 = smf.ols(formula='y ~ numpy.log(x)', data=df).fit()
#print model1
#print model3.summary()

axes[0].plot(xx, func_ols(model1.beta.x, model1.beta.intercept, xx))
axes[2].plot(xx, func_log(model3.params['numpy.log(x)'], model3.params['Intercept'], xx))

axes[0].legend(ols_string(model1.beta.x, model1.beta.intercept, model1.r2), loc="upper left")
axes[2].legend(log_string(model3.params['numpy.log(x)'], model3.params['Intercept'], model3.rsquared), loc="upper left")

plt.show()

こうすると以下の感じに、グラフが表示されます。


対数近似曲線は、「pandas.ols」ではなく「smf.ols」を使いました。
「smf」というのは、「statsmodels.formula.api」というモジュールです。
こちらも「model3.summary()」とすると、
こんな感じに表示されます。

これはセルの最後に、「model3.summary()」を評価させた画像ですが
notebookは、何でもテーブルに変換してくれて便利ですね。


今回は何故「smf.ols」を使ったかというと、「smf.ols」には「formula」を指定する事が出来るので
そのまま必要な情報が揃って便利だったからです。
(タイトルも変えました・・・w)


対数近似曲線は、

データの変化率が急速に増加または減少した後、横ばい状態になる場合に適しています。対数近似曲線では負の値と正の値を使用できます。

だそうです。

参考
https://support.office.com/ja-jp/article/%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AB%E6%9C%80%E9%81%A9%E3%81%AA%E8%BF%91%E4%BC%BC%E6%9B%B2%E7%B7%9A%E3%82%92%E9%81%B8%E6%8A%9E%E3%81%99%E3%82%8B-1bb3c9e7-0280-45b5-9ab0-d0c93161daa8

グラフを見ると、この言っている事が分かりますね。
また、線形近似曲線と比べると、フィットしていない事が分かります。
「R-squared」も若干低くなっています。
そして、エクセルとも数値的に同じ結果になりました。(ヤッター!)


あと、対数近似曲線は商品の売上げなんかに、フィットしやすいのかなー?
と思います。

それでは、また次回・・・