ためすう
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行まで表示されるようになりました。