ためすう

pandas の head、tail を使ってみる

2019-06-26

やったこと

pandas で DataFrame のデータを確認してみます。

確認環境

$ ipython --version
6.1.0
$ jupyter --version
4.3.0
$ python --version
Python 3.6.2 :: Anaconda custom (64-bit)
print(pd.__version__)
0.20.3

調査

csv ファイルを読み込みます。

train = pd.read_csv("./train.csv")

head を使ってみる

デフォルトだと先頭から5行出力されます。

train.head()

tail を使ってみる

デフォルトだと最終行から5行出力されます。

train.tail()

参考

第10章 オブジェクトに代理を立てる: Proxy part1

2019-06-26

「Rubyによるデザインパターン」の読書メモです。

Proxy パターンは下記の問題の解決策となります。

  • オブジェクトへのアクセス制御
  • 場所に依存しないオブジェクトの取得方法の提供
  • オブジェクト生成の遅延

プロキシーが気にするのは、何かをすることが許されているのは誰で、許されていないのが誰なのかということです。

Proxy パターンの例

3つの問題について、解決させるように試みたコードです。

test.rb

class BankAccount
  attr_reader :balance

  def initialize(starting_balance=0)
    @balance = starting_balance
  end

  def deposit(amount)
    @balance += amount
  end

  def withdraw(amount)
    @balance -= amount
  end
end

require 'etc'
class BankAccountProxy
  def initialize(starting_balance, owner_name, &creation_block)
    @starting_balance = starting_balance
    @owner_name = owner_name
    @creation_block = creation_block
  end

  def balance
    check_access
    subject.balance
  end

  def deposit(amount)
    check_access
    subject.deposit(amount)
  end

  def withdraw(amount)
    check_access
    subject.withdraw(amount)
  end

  def check_access
    if Etc.getlogin != @owner_name
      raise "Illegal access: #{Etc.getlogin} cannot access account."
    end
  end

  def subject
    @subject || (@subject = @creation_block.call)
  end
end

account = BankAccount.new(100)
account.deposit(50)
account.withdraw(10)
p account.balance

account2 = BankAccountProxy.new(account.balance, 'hogehoge') { BankAccount.new(300) }
account2.deposit(50)
account2.withdraw(10)
p account2.balance

出力結果

$ ruby test.rb
140
340

第9章 ギャップを埋める: Adapter

2019-06-26

「Rubyによるデザインパターン」の読書メモです。

アダプタは既存のインターフェースと必要なインターフェースとの間の深い溝を橋渡しするオブジェクトです。

Adapter パターンの例

例えば、TextObject を表示する実装が既にあって、

フォーマットが異なる BritishTextObject に手を入れることができない場合にも

BritishTextObject を扱うことができます。

class Renderer
  def render(text_object)
    text = text_object.text
    size = text_object.size_inches
    color = text_object.color

    p text
    p size
    p color
  end
end

class TextObject
  attr_reader :text, :size_inches, :color

  def initialize(text, size_inches, color)
    @text = text
    @size_inches = size_inches
    @color = color
  end
end

class BritishTextObject
  attr_reader :string, :size_mm, :colour

  def initialize(string, size_mm, colour)
    @string = string
    @size_mm = size_mm
    @colour = colour
  end
end

class BritshTextObjectAdapter < TextObject
  def initialize(bto)
    @bto = bto
  end

  def text
    @bto.string
  end

  def size_inches
    @bto.size_mm / 4
  end

  def color
    @bto.colour
  end
end

t = TextObject.new('text2', 100, 'blue')
Renderer.new.render(t)

b = BritishTextObject.new('string', 300, 'green')
bto = BritshTextObjectAdapter.new(b)
Renderer.new.render(bto)

Ruby でクラス拡張するパターン

class Renderer
  def render(text_object)
    text = text_object.text
    size = text_object.size_inches
    color = text_object.color

    p text
    p size
    p color
  end
end

class TextObject
  attr_reader :text, :size_inches, :color

  def initialize(text, size_inches, color)
    @text = text
    @size_inches = size_inches
    @color = color
  end
end

class BritishTextObject
  attr_reader :string, :size_mm, :colour

  def initialize(string, size_mm, colour)
    @string = string
    @size_mm = size_mm
    @colour = colour
  end
end

# 上記 BritishTextObject は require されているつもり
# 拡張
class BritishTextObject
  def text
    string
  end

  def size_inches
    size_mm / 4
  end

  def color
    colour
  end
end

t = TextObject.new('text2', 100, 'blue')
Renderer.new.render(t)

b = BritishTextObject.new('string', 300, 'green')
Renderer.new.render(b)

まとめ

繰り返しますが、コードはパターンにとってそれほど重要ではないということを覚えておいてください。意図が重要です。不適切なインターフェースを持つオブジェクトに困っていて、不適切なインターフェースを扱う痛みがシステム中に広がることを防ぎたい場合に限り、アダプタを選んでください。

第8章 命令を実行する: Command

2019-06-25

「Rubyによるデザインパターン」の読書メモです。

コマンドをクラスにするパターン

class SlickButton
  attr_accessor :command

  def initialize(command)
    @command = command
  end

  def on_button_push
    @command.execute if @command
  end
end

class SaveCommand
  def execute
    p "#{self.class}##{__method__}"
  end
end

save_button = SlickButton.new(SaveCommand.new)
save_button.on_button_push

コマンドをコードブロックにするパターン

コマンドは何か特定のことを行うコードの単純なラッパーで、唯一の存在理由は、適切なタイミングでコードを実行することです。

class SlickButton
  attr_accessor :command

  def initialize(&block)
    @command = block
  end

  def on_button_push
    @command.call if @command
  end
end

new_button = SlickButton.new do
  p "#{self.class}"
end

new_button.on_button_push

記録 + 戻るの例

class Command
  attr_reader :description

  def initialize(description)
    @description = description
  end

  def execute
  end

  def unexecute
  end
end

class CreateFile < Command
  def initialize(path, contents)
    super("Create file: #{path}")
    @path = path
    @contents = contents
  end

  def execute
    p "#{self.class}##{__method__}"
  end

  def unexecute
    p "#{self.class}##{__method__}"
  end
end

class DeleteFile < Command
  def initialize(path)
    super("Delete file: #{path}")
    @path = path
  end

  def execute
    p "#{self.class}##{__method__}"
  end

  def unexecute
    p "#{self.class}##{__method__}"
  end
end

class CopyFile < Command
  def initialize(source, target)
    super("Copy file: #{source} to #{target}")
    @source = source
    @target = target
  end

  def execute
    p "#{self.class}##{__method__}"
  end

  def unexecute
    p "#{self.class}##{__method__}"
  end
end

class CompositeCommand < Command
  def initialize
    @commands = []
  end

  def add_command(cmd)
    @commands << cmd
  end

  def execute
    @commands.each {|cmd| cmd.execute}
  end

  def unexecute
    @commands.reverse.each {|cmd| cmd.unexecute}
  end

  def description
    description = ''
    @commands.each {|cmd| description += cmd.description + "\n"}
    description
  end
end

cmds = CompositeCommand.new
cmds.add_command(CreateFile.new('file1.txt', 'hello world'))
cmds.add_command(CopyFile.new('file1.txt', 'file2.txt'))
cmds.add_command(DeleteFile.new('file1.txt'))

puts cmds.description
p '---'
cmds.execute
p '---'
cmds.unexecute

注意

Commandパターンのポイントは何を行うかの決定と、それの実行とを分離することです。

まとめ

Commandパターンでは、ある特定の動作を実行するオブジェクトを構築します。「特定」という部分が重要です。

第7章 コレクションを操作する: Iterator

2019-06-25

「Rubyによるデザインパターン」の読書メモです。

時々、個人の見解入りです。

集約オブジェクトがもとにある内部表現を公開せずに、その要素に順にアクセスする方法を提供する

外部イテレータ

class ArrayIterator
  def initialize(array)
    @array = array
    @index = 0
  end

  def has_next?
    @index < @array.length
  end

  def item
    @array[@index]
  end

  def next_item
    value = @array[@index]
    @index += 1
    value
  end
end

array = ['red','green', 'blue']
i = ArrayIterator.new(array)
while i.has_next?
  p "item: #{i.next_item}"
end

内部イテレータ

def for_each_element(array)
  i = 0
  while i < array.length
    yield(array[i])
    i += 1
  end
end

a = [10, 20, 30]
for_each_element(a) { |element| p "The element is #{element}" }

外部イテレータと内部イテレータ

外部イテレータはクライアントが繰り返しを制御します。

内部イテレータは始めから終わりまで実行されます。

Enumerable モジュールを使う

class Account
  attr_accessor :name, :balance

  def initialize(name, balance)
    @name = name
    @balance = balance
  end

  def <=>(other)
    balance <=> other.balance
  end
end

class Portfolio
  include Enumerable

  def initialize
    @accounts = []
  end

  def each(&block)
    @accounts.each(&block)
  end

  def add_account(account)
    @accounts << account
  end
end

a1 = Account.new('account1', 200)
a2 = Account.new('account2', 400)
a3 = Account.new('account3', 600)

portfolio = Portfolio.new
arr = [a1, a2, a3]
arr.each do |a|
  portfolio.add_account(a)
end

p portfolio.any? {|account| account.balance > 500}
p portfolio.all? {|account| account.balance > 500}

コードブロックで判定条件を渡せます。

注意点

test.rb

array = ['red', 'green', 'blue', 'purple']

array.each do |color|
  p color
  if color == 'green'
    array.delete(color)
  end
end

出力結果

$ ruby test.rb
"red"
"green"
"purple"

blue がスキップされてしまいました

test.rb

def change_resistant_for_each_element(array)
  copy = Array.new(array)
  i = 0
  while i < copy.length
    yield(copy[i])
    i += 1
  end
end

array = ['red', 'green', 'blue', 'purple']
change_resistant_for_each_element(array){|color|
  p color
  if color == 'green'
    array.delete(color)
  end
}

配列を削除しても、全部捜査されました。

出力結果

$ ruby test.rb
"red"
"green"
"blue"
"purple"

pandas で csv 出力する

2019-06-24

やったこと

pandas で csv ファイルの出力をします。

確認環境

$ ipython --version
6.1.0
$ jupyter --version
4.3.0
$ python --version
Python 3.6.2 :: Anaconda custom (64-bit)
import pandas as pd
print(pd.__version__)
0.20.3

調査

to_csv を利用して csv ファイルを作成します。

引数の index は、出力したファイルに index を含むかどうかです。

data = {'state': ['Ohio', 'Nevada'],
       'year': [2000, 2001]}
df = DataFrame(data)
df.to_csv("hoge.csv", index=False)

出力された hoge.csv

state,year
Ohio,2000
Nevada,2001

参考

第6章 部分から全体を組み立てる: Composite

2019-06-24

「Rubyによるデザインパターン」の読書メモです。

時々、個人の見解入りです。

「全体が部分のように振る舞う」という状況を表すデザインパターン

コンポジットオブジェクトの役割

1つにコンポジットオブジェクトはコンポーネントとしての役割を持っています。その一方で、コンポジットオブジェクトはコンポーネントのコレクションとしての役割も持っています。

class Task
  attr_reader :name

  def initialize(name)
    @name = name
  end

  def get_time_required
    0.0
  end
end

class CompositeTask < Task
  def initialize(name)
    super(name)
    @sub_tasks = []
  end

  def add_sub_task(task)
    @sub_tasks << task
  end

  def remove_sub_task(task)
    @sub_tasks.delete(task)
  end

  def get_time_required
    time = 0.0
    @sub_tasks.each {|task| time += task.get_time_required}
    time
  end
end

class AddDryIngredientsTask < Task
  def initialize
    super('Add dry ingredients')
  end

  def get_time_required
    1.0
  end
end

class MixTask < Task
  def initialize
    super('Mix that better up!')
  end

  def get_time_required
    3.0
  end
end

class MakeBatterTask < CompositeTask
  def initialize
    super('Make batter')
    @sub_tasks = []
    add_sub_task(AddDryIngredientsTask.new)
    add_sub_task(MixTask.new)
  end
end

p MakeBatterTask.new.get_time_required

演算子を実装したバージョン

class Task
  attr_reader :name

  def initialize(name)
    @name = name
  end

  def get_time_required
    0.0
  end
end

class CompositeTask < Task
  def initialize(name)
    super(name)
    @sub_tasks = []
  end

  def <<(task)
    @sub_tasks << task
  end

  def [](index)
    @sub_tasks[index]
  end

  def []=(index, value)
    @sub_tasks[index] = value
  end

  def remove_sub_task(task)
    @sub_tasks.delete(task)
  end

  def get_time_required
    time = 0.0
    @sub_tasks.each {|task| time += task.get_time_required}
    time
  end
end

class AddDryIngredientsTask < Task
  def initialize
    super('Add dry ingredients')
  end

  def get_time_required
    1.0
  end
end

class MixTask < Task
  def initialize
    super('Mix that better up!')
  end

  def get_time_required
    3.0
  end
end

class MakeBatterTask < CompositeTask
  def initialize
    super('Make batter')
    @sub_tasks = []
    @sub_tasks << AddDryIngredientsTask.new
    @sub_tasks << MixTask.new
  end
end

p MakeBatterTask.new.get_time_required

pandas の read_csv を使ってみる

2019-06-24

やったこと

pandas で csv ファイルを読み込みます。

確認環境

$ ipython --version
6.1.0
$ jupyter --version
4.3.0
$ python --version
Python 3.6.2 :: Anaconda custom (64-bit)
import pandas as pd
print(pd.__version__)
0.20.3

調査

read_csv

csv ファイルを読み込みます。

train = pd.read_csv("./train.csv")

戻り値は下記です。

DataFrame or TextParser

shape

shape を使って、行数と列数を確認します。

train.shape

(114321, 133)

size

train.size

15204693

参考

第5章 変更に追従する: Observer part2

2019-06-24

「Rubyによるデザインパターン」の読書メモです。

時々、個人の見解入りです。

注意点

Observerパターンを使うときに発生する問題の多くは、更新の頻度とタイミングについてです。

実際に何か変更されたのでなければ、おそらくオブザーバに通知すべきではありません。

変更された時のみ通知を送るようにするパターン

require 'observer'

class Payroll
  def update(changed_employee)
    puts("#{changed_employee.name}のために小切手を切ります!")
    puts("彼の給料はいま#{changed_employee.salary}です!")
  end
end

class Employee
  include Observable

  attr_reader :name, :title, :salary

  def initialize(name, title, salary)
    @name = name
    @title = title
    @salary = salary
  end

  # 変更があった時だけ、通知を送るようにします
  def salary=(new_salary)
    if @salary == new_salary
      nil
    end

    @salary = new_salary
    changed
    notify_observers(self)
  end
end

fred = Employee.new('Fred', 'Crane Operator', 3000)
payroll = Payroll.new
fred.add_observer(payroll)

fred.salary = 3000
fred.salary = 3100

変更をまとめて通知するパターン

require 'observer'

class Payroll
  def update(changed_employee)
    puts("#{changed_employee.name}のために小切手を切ります!")
    puts("title: #{changed_employee.title}")
    puts("彼の給料はいま#{changed_employee.salary}です!")
  end
end

class Employee
  include Observable

  attr_reader :name, :title, :salary

  def initialize(name, title, salary)
    @name = name
    @title = title
    @salary = salary
  end

  def salary=(new_salary)
    if @salary == new_salary
      nil
    end

    @salary = new_salary
  end

  def title=(new_title)
    if @title == new_title
      nil
    end
    @title = new_title
  end

  def changes_complete
    changed
    notify_observers(self)
  end
end

fred = Employee.new('Fred', 'Crane Operator', 3000)
payroll = Payroll.new
fred.add_observer(payroll)

fred.title = 'superman'
fred.salary = 9000
fred.changes_complete

Jupyter Notebook で全ての行を表示する

2019-06-23

やったこと

Jupyter Notebook で行数が多いデータを表示する時、省略されてしまうことがあります。

全部表示してみます。

ちなみに列数が多い場合は下記で対応できます。

確認環境

$ ipython --version
6.1.0
$ jupyter --version
4.3.0
$ python --version
Python 3.6.2 :: Anaconda custom (64-bit)
print(pd.__version__)
0.20.3

調査

csv ファイルを読み込みます。

train = pd.read_csv("./train.csv")
train.dtypes

出力は省略

最大の表示行数を 150 に設定します。

# 現在の設定確認
print(pd.get_option("display.max_rows"))
pd.set_option('display.max_rows', 150)

60

これで150行まで表示されるようになりました。

参考