ブログですが、下記に引っ越ししました。
RE:ENGINES https://re-engines.com/
徐々にこちらのブログ記事の一部は引っ越しをすると思います。
また、新しい記事の掲載や活動内容なども掲載をしておりますので、
新しいブログサイトのRE:ENGINESをよろしくお願いします。
2017年4月27日木曜日
2017年2月10日金曜日
Swift3でSCLAlertViewを使ってみた
こんにちは、onukiです。
今回はSwiftでフラットなデザインの
アニメーション付きアラートビューが扱える
SCLAlertViewを試してみたいと思います。
今回はSwiftでフラットなデザインの
アニメーション付きアラートビューが扱える
SCLAlertViewを試してみたいと思います。
準備
おなじみCocoaPodでインストールします。
pod 'SCLAlertView'
実装
今回はボタン付きのアラートを表示したいと思います。
まずはSCLAlertViewをインポートします。
import SCLAlertView
アラートビューを表示します、ボタンは二つ用意します。
let alertView = SCLAlertView()
//ボタンの追加
alertView.addButton("ボタン1") {
//タップ時の処理
print("ボタン1をタップしました")
}
alertView.addButton("ボタン2") {
print("ボタン2をタップしました")
}
//表示実行
alertView.showSuccess("ボタン付きアラート", subTitle: "説明")
そうするとこのように表示されます。
今回は基本的なボタン付きのアラートでしたが、
他にもテキスト入力できるもの、ボタンなしで時間指定で閉じるもの等
色々あるので、興味を持たれた方は作者のgithubを拝見してみてください。
2017年2月9日木曜日
はじめの一歩 -Rails ActiveRecord編- UPDATE2
どうも、はじめです。
前回はUPDATEについて書いてみました。
はじめの一歩 -Rails ActiveRecord編- UPDATE
今回はUPDATEの際readonlyやvalidationで更新ができなかった場合に関して書いていこうと思います。
はじめに
今回も前回と同じテーブルを使用しようと思います。
usersテーブル
[id: 1, user_name: 'Aさん'],
[id: 2, user_name: 'Bさん'],
[Id: 3, user_name: 'Cさん']
itemsテーブル
[id: 1, item_name: 'Rubyの本'],
[id: 2, item_name: 'Railsの本'],
[id: 3, item_name: 'PHPの本']
user_itemsテーブル(userが持っているitemを管理するテーブル)
[id: 1, user_id: 1, item_id: 1],
[id: 2, user_id: 1, item_id: 2],
[id: 3, user_id: 2, item_id: 3]
関連性
user : user_item => 1 : n
item : user_item => 1 : n
ではまず【readonly】で更新できなかった場合の対処法を書いてみます。
readonly
下のように更新をしてみます。
[id: 2, user_id: 1, item_id: 2]
↓
[id: 2, user_id: 1, item_id: 3]
手元でなかなかreadonlyになる状況を再現できなかったため以下の方法でreadonlyにしました。
user_item = UserItem.readonly(true)
この状態で変更しようとしても更新できません。
user_item.find(2).update(item_id: 3)
# ActiveRecord::ReadOnlyRecord: UserItem is marked as readonly
これだとreadonlyでrollbackされてしまいます。
モデルからインスタンスを取得する際にreadonlyをfalseにしてあげれば更新が可能になります。
user_item = UserItem.readonly(false)
user_item.find(2).update(item_id: 3)
次に【validation】でエラーになった場合です。
validation
ユーザーの登録の際、user_nameを入力必須にしていたとします。
入力必須のバリデーションを定義するにはUserモデルに対し以下のように定義します。
# app/models/user.rb
class User < ApplicationRecord
validates :user_name, presence: true
end
この状態でユーザー名を空で登録しようとするとエラーになります。
user = User.new
user.save
次のように記述することで一時的にバリデーションを無効にすることができます。
user = User.new
user.save(:validate => false)
最後に
validationを一時的に無効にすることは可能ですが、
今回例としてあげたのケースの場合、
DBでuser_nameにnot null制約がかかっているとバリデーションを無視することができても、
DBへの登録時にエラーになってしまいますので気をつけましょう。
次回はupdate_attributeとupdate_attributesを使ってみようと思います。
2017年2月8日水曜日
アニメーション
どうもーデザイナーのnottyです。
先日AirbnbDesignからAfter Effectsで作成したアニメーションをレンダリングして
iOS・Android・React Native向けのアニメーションに変換してくれる、『Lottie』が公開されました!
In the past, building complex animations for Android, iOS, and React Native apps was a difficult and lengthy process. You either had to add bulky image files for each screen size or write a thousand lines of brittle, hard-to-maintain code. Because of this, most apps weren’t using animation — despite it being a powerful tool for communicating ideas and creating compelling user experiences. One year ago, we set out to change that.複雑なアニメーションを作るためには、保守が大変で大量のコードを書かないといけない必要だったが、Lottieによって、それは変わりました。的なことが書かれています。
『Lottie introducing』
現在、私が使用しているアプリで
お気に入りや、ローディング、いいねボタンなど
いたるところにアニメーションが使用されています。
ユーザーにとって、ストレスにもなりうるウォークスルーなどに
見てて気持ちの良いアニメーションを作成すると非常に効果的かもしれません。
このライブラリがでて非常に良かったのですが、
それ以上に事業会社からこういった技術(デザイン)をシェアするという事に
毎回興奮します。日本からもこういうプロダクト(技術)などもっといっぱいでると良いなと思う次第でございます。
2017年2月7日火曜日
2017年2月6日月曜日
配牌からあがれる可能性を予測する!(その5 実際にテストしてみる)
テストに使用した配牌について
Youtubeであがっていた○凰のプレイ動画を1半荘分試しました。
結果
# 第一要素があがれる方、第二要素があがれない方
# 重み
[[-0.09800755 0.09915648] # 順子
[ 0.15426824 -0.17342399] # 対子
[-0.61190551 0.61323983]] # 暗刻
# バイアス
[-0.84420447 0.84420447]
この結果だけ見ると、対子の数があがれる方に寄与しているように見えます。
逆に暗刻があるとあがりにくいようです笑
ちょっとリャンメンやカンチャンの形も要素に入れた方が良かったかな、と後悔し始めておりますが、とりあえずこのまま進めたいと思います。
結果を記載しますが、配牌を記載するとおさまりきらないので、「あがれた」か「あがれなかった」を記載します。
逆に暗刻があるとあがりにくいようです笑
ちょっとリャンメンやカンチャンの形も要素に入れた方が良かったかな、と後悔し始めておりますが、とりあえずこのまま進めたいと思います。
結果を記載しますが、配牌を記載するとおさまりきらないので、「あがれた」か「あがれなかった」を記載します。
局 | 結果 | あがれる確率 | あがれない確率 |
---|---|---|---|
東1局 | あがれない | 17% | 83% |
東2局 | あがれない | 29% | 71% |
東3局 | あがれない | 7% | 93% |
東3局1本場 | あがれない | 17% | 83% |
東4局 | あがれない | 33% | 67% |
南1局 | あがれる | 20% | 80% |
南1局1本場 | あがれない | 26% | 74% |
南2局 | あがれない | 17% | 83% |
南3局 | あがれる | 26% | 74% |
南4局 | あがれる | 23% | 77% |
パッと見、ちゃんと予測できているようには見えないです。
よく考えたら、麻雀は4人のうち1人があがれるゲームなので、単純計算でアガれる確率は25%です。
教師データが足りないのかもしれないと思い、とりあえずプロの対局1局分追加してみました。
よく考えたら、麻雀は4人のうち1人があがれるゲームなので、単純計算でアガれる確率は25%です。
教師データが足りないのかもしれないと思い、とりあえずプロの対局1局分追加してみました。
結果②
# 第一要素があがれる方、第二要素があがれない方
# 重み
[[ 0.17258578 -0.17396835] # 順子
[ 0.20088727 -0.20564398] # 対子
[-0.33262621 0.34681625]] # 暗刻
# バイアス
[-1.07893278 1.07893278]
先ほどとは重みが変わり、順子もアガれる確率に寄与するようになりました。
それではこちらのパラメータをもとに同じテストデータで実験してみます。
比較しやすいよう先ほど求めた結果を①とし、アガれない確率のみ記載します。
それではこちらのパラメータをもとに同じテストデータで実験してみます。
比較しやすいよう先ほど求めた結果を①とし、アガれない確率のみ記載します。
局 | 結果 | 結果①のアガれない確率 | 結果②のアガれない確率 |
---|---|---|---|
東1局 | あがれない | 83% | 73% |
東2局 | あがれない | 71% | 64% |
東3局 | あがれない | 93% | 92% |
東3局1本場 | あがれない | 83% | 80% |
東4局 | あがれない | 67% | 72% |
南1局 | あがれる | 80% | 85% |
南1局1本場 | あがれない | 74% | 79% |
南2局 | あがれない | 83% | 80% |
南3局 | あがれる | 74% | 79% |
南4局 | あがれる | 77% | 73% |
結果の方も変化しました。
10局のうち、6局の「アガれない確率」が下がっています。
つまり「アガれる確率」が上昇しています。
このことから、結果①の時点では、「アガれる」可能性を過少評価していることが考えられます。
10局のうち、6局の「アガれない確率」が下がっています。
つまり「アガれる確率」が上昇しています。
このことから、結果①の時点では、「アガれる」可能性を過少評価していることが考えられます。
おわりに
今後の目標としては、
とりあえず、まずは教師データを作成するのが楽になるインターフェースを実装したいと思います。
参考のソースコードはこちらになります。
https://github.com/naoki85/python_mahjong
- 教師データを増やす
- レイヤーのノードを追加(リャンメン、カンチャン、ペンチャン)の数
とりあえず、まずは教師データを作成するのが楽になるインターフェースを実装したいと思います。
参考のソースコードはこちらになります。
https://github.com/naoki85/python_mahjong
2017年2月4日土曜日
Swift3でLTMorphingLabelを使ってみた
こんにちは、onukiです。
今回はLTMorphingLabelというライブラリが
面白そうなので使ってみました。
今回はLTMorphingLabelというライブラリが
面白そうなので使ってみました。
LTMorphingLabelとは
ラベルのテキスト変更時にエフェクトをつけてくれるライブラリです。
作者のgithubにエフェクトのサンプルがあるのですが、
見ているだけで試してみたい欲に駆られますね。
準備
今回はCocoaPodsで追加します。
ただし、現在Swift3ではブランチの指定をしないと
ビルドが通らないみたいなので気をつけて下さい。
pod 'LTMorphingLabel', :git => 'https://github.com/lexrus/LTMorphingLabel.git', :branch => 'swift3'
実装
まずはLTMorphingLabelをimportします。
import LTMorphingLabel
StoryboardにUILabelを適当に用意し
ClassにLTMorphingLabelを指定してください。
それをIBOutlet接続します。
エフェクトの定義を行います。
これでmorphingLabelのtextを変更すると
エフェクトがかかるようになります。
これだけだとイマイチエフェクトの切り替わりを実感できないのでTimerで
morphingLabelのtextを更新するようにしてみたいと思います。
実装も簡単ですし、見た目も素晴らしいので色々使ってみたいですね。
@IBOutlet weak var morphingLabel: LTMorphingLabel!
エフェクトの定義を行います。
morphingLabel.morphingEffect = .evaporate
エフェクトの種類、サンプルに関しては作者のgithubを参照してください。これでmorphingLabelのtextを変更すると
エフェクトがかかるようになります。
これだけだとイマイチエフェクトの切り替わりを実感できないのでTimerで
morphingLabelのtextを更新するようにしてみたいと思います。
@IBOutlet weak var morphingLabel: LTMorphingLabel!
//表示制御用タイマー
private var timer: Timer?
//String配列のindex用
private var index: Int = 0
//表示するString配列
private let textList = ["シンプルであることは、", "複雑であることよりも", "難しい"]
override func viewDidLoad() {
super.viewDidLoad()
// エフェクトの定義
morphingLabel.morphingEffect = .evaporate
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
//タイマーの追加
timer = Timer.scheduledTimer(timeInterval: 3.0,
target: self,
selector: #selector(update(timer:)), userInfo: nil,
repeats: true)
timer?.fire()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
timer?.invalidate()
}
func update(timer: Timer) {
//ここでtextの更新
morphingLabel.text = textList[index]
index += 1
if index >= textList.count {
index = 0
}
}
これでLTMorphingLabelのエフェクトを堪能できると思います。実装も簡単ですし、見た目も素晴らしいので色々使ってみたいですね。
2017年2月3日金曜日
Swift3でTTTAttributedLabelリンク表示の指定をやってみた
こんにちは、onukiです。
以前、TTTAttributedLabelでのリンク表示を紹介しましたが
今回は応用でLabelにリンクを表示したくない時などに使える
リンク表示の指定をやって見たいと思います。
実行するとこのような表示になります。
「URL」をタップすると以下のメソッドが呼ばれます。
遷移するURLを画面に表示しないので色々使えると思います。
以前、TTTAttributedLabelでのリンク表示を紹介しましたが
今回は応用でLabelにリンクを表示したくない時などに使える
リンク表示の指定をやって見たいと思います。
準備
前回の記事を参照してください。
実装
今回は表示の文字列から「URL」の部分をタップできるようにします。
//リンクをタップできるように設定
linkLabel.enabledTextCheckingTypes = NSTextCheckingResult.CheckingType.link.rawValue
//リンクのタップを制御するために設定
linkLabel.delegate = self
let label = "URLをタップできます。"
linkLabel.text = label
//labelから“URL”を部分を選択
let range = NSRange.init(location: 0, length: 3)
//タップした時の接続先
let url = URL(string: "https://www.google.co.jp/")
//TTTAttributedLabelにリンクを指定
linkLabel.addLink(to: url, with: range)
実行するとこのような表示になります。
「URL」をタップすると以下のメソッドが呼ばれます。
func attributedLabel(_ label: TTTAttributedLabel!, didSelectLinkWith url: URL!) {
print(url)//url => https://www.google.co.jp/
}
遷移するURLを画面に表示しないので色々使えると思います。
2017年2月2日木曜日
はじめの一歩 -Rails ActiveRecord編- UPDATE
どうも、はじめです。
前回はJOINについて書いてみました。
はじめの一歩 -Rails ActiveRecord編- SELECT4
今回はUPDATEに関して書いていこうと思います。
はじめに
今回も前回と同じテーブルを使用しようと思います。
usersテーブル
[id: 1, user_name: 'Aさん'],
[id: 2, user_name: 'Bさん'],
[Id: 3, user_name: 'Cさん']
itemsテーブル
[id: 1, item_name: 'Rubyの本'],
[id: 2, item_name: 'Railsの本'],
[id: 3, item_name: 'PHPの本']
user_itemsテーブル(userが持っているitemを管理するテーブル)
[id: 1, user_id: 1, item_id: 1],
[id: 2, user_id: 1, item_id: 2],
[id: 3, user_id: 2, item_id: 3]
関連性
user : user_item => 1 : n
item : user_item => 1 : n
UPDATEを行うには主に以下の二つの方法があります。
・saveメソッドを使用する。
・updateメソッドを使用する。
でははじめに【saveメソッド】を使用した方法から書いていきます。
save
user_itemsを以下のように変更したいと思います。
[id: 3, user_id: 2, item_id: 3]
↓
[id: 3, user_id: 3, item_id: 3]
1.変更したいモデルインスタンスを取得
user_item = UserItem.find(3)
2.変更したい値を代入
user_item.user_id = 3
3.代入が完了したら登録
user_item.save
以上の手順でupdateが完了します。
2で複数のカラムを変更することも可能です。
次に【updateメソッド】を使用した方法を書いてみます。
update
updateでも同様にuser_itemsを以下のように変更したいと思います。
[id: 3, user_id: 2, item_id: 3]
↓
[id: 3, user_id: 3, item_id: 3]
updateメソッドを使用する際も2つの方法があります。
一つはsaveメソッドと同じように変更したいモデルインスタンスを取得し、
updateという流れになります。
user_item = UserItem.find(3)
user_item.update(user_id: 3)
もう一つは一度変数にインスタンスを取得するという工程を飛ばす方法です。
UserItem.find(3).update(user_id: 3)
どれも結果は同じになります。
まとめ
updateをする際変更したいレコードがreadonlyになっていた場合や、
validation等の関係で更新が失敗する場合があります。
その場合の対処法等を次回書いてみようと思います。
2017年2月1日水曜日
作業用BGMについて
デザイナーの nottyです。今日は普段、作業する際に聞く音楽を紹介したいと思います。
音楽を聴くと捗る場合や、逆に捗らない時もあります。
どんな時に聴いているかも記載するので、参考になればと思います。
こういう音楽は特に集中すると聴こえなくなります。
【日本語ラップ MIX】DJ KRO
TOKYO AFTERNOON JAPANESE HIPHOP MIX
Nujabes - Modal Soul
出演するDJが流す曲、主にイベントで流れる曲を聴いて作成します。
サウンドクラウドでDJを検索するとMIXが上がっていたりします。
他にもゲームのデザインをした時は名作ゲームの音楽を聴いてました。
ブレスト/資料作成系
気分をあげたり、リラックスしたり感情の浮き沈みがあるタスクの時は
Spotify
・気分によってプレイリストを選択
Prime music
・プライムラジオで垂れ流し
と使い分けています。
他にも
ジ・居酒屋サウンド
http://413tmks.s3.amazonaws.com/izakayasound/index.html
おと風景
http://otofukei.com/
などの環境音を作業用BGMにします。
気分に合わせて、捗る音楽をチョイスできるのもスキルだと思うので、
普段聴かない音楽を聴いてタスクへ向かうのも良いのではないでしょうか。
個人的にはEDMをガンガンにかけて体を揺らしながらデザインがしたいものです。
音楽を聴くと捗る場合や、逆に捗らない時もあります。
どんな時に聴いているかも記載するので、参考になればと思います。
ルーチンワーク系
主にMIXをかけています。同じトーン,テンポが続く曲は繰り返し行う作業系に向いてると思います。またMIXなので変化があり、飽きずに聴くことができます。こういう音楽は特に集中すると聴こえなくなります。
【日本語ラップ MIX】DJ KRO
TOKYO AFTERNOON JAPANESE HIPHOP MIX
Nujabes - Modal Soul
クリエイティブ系
製作する内容にあわせて音楽を変えています。クラブイベントのフライヤーを作成するときは、出演するDJが流す曲、主にイベントで流れる曲を聴いて作成します。
サウンドクラウドでDJを検索するとMIXが上がっていたりします。
他にもゲームのデザインをした時は名作ゲームの音楽を聴いてました。
ブレスト/資料作成系
気分をあげたり、リラックスしたり感情の浮き沈みがあるタスクの時は
Spotify
・気分によってプレイリストを選択
Prime music
・プライムラジオで垂れ流し
と使い分けています。
他にも
ジ・居酒屋サウンド
http://413tmks.s3.amazonaws.com/izakayasound/index.html
おと風景
http://otofukei.com/
などの環境音を作業用BGMにします。
気分に合わせて、捗る音楽をチョイスできるのもスキルだと思うので、
普段聴かない音楽を聴いてタスクへ向かうのも良いのではないでしょうか。
2017年1月31日火曜日
Gemのバージョンをプロジェクトごとに分ける方法
こんにちは。h_ono_222です。
複数のアプリケーションを同時に開発している場合、同じGemでもそれぞれのアプリケーションごとにバージョンを分けたい場合があると思います。
今回はその方法を紹介します。
以上です。
複数のアプリケーションを同時に開発している場合、同じGemでもそれぞれのアプリケーションごとにバージョンを分けたい場合があると思います。
今回はその方法を紹介します。
1. 空のプロジェクトを作成する
$ mkdir test_app && cd test_app
$ bundle init
Writing new Gemfile to /Users/user_name/test_app/Gemfile
2. Gemfileを修正する
# gem "rails"のコメントアウトを外します。3. インストール先を指定してbundle install
$ bundle install --path vendor/bundle
Fetching gem metadata from https://rubygems.org/
Fetching version metadata from https://rubygems.org/
Fetching dependency metadata from https://rubygems.org/
Resolving dependencies....
# 〜中略〜
Bundle complete! 1 Gemfile dependency, 38 gems now installed.
Bundled gems are installed into ./vendor/bundle.
4. アプリケーションを作成する
$ bundle exec rails new .
exist
create README.md
create Rakefile
create config.ru
create .gitignore
conflict Gemfile
Overwrite /Users/DevWork/Documents/test_app/Gemfile? (enter "h" for help) [Ynaqdh] Y # Yを入力してEnter
force Gemfile
# 〜中略〜
Bundle complete! 15 Gemfile dependencies, 62 gems now installed.
Bundled gems are installed into ./vendor/bundle.
run bundle exec spring binstub --all
* bin/rake: spring inserted
* bin/rails: spring inserted
以上です。
2017年1月30日月曜日
配牌からあがれる可能性を予測する!(その4 勾配を求める際に詰まったこと)
こんにちは、Taroです。
前回の記事の記事の続きになります。
配牌からあがれる可能性を予測する!(その3 学習の実装)
本日は学習を実装する上で、すぐに理解できなかった勾配算出に関わる部分をまとめたいと思います。
前回の記事の記事の続きになります。
配牌からあがれる可能性を予測する!(その3 学習の実装)
本日は学習を実装する上で、すぐに理解できなかった勾配算出に関わる部分をまとめたいと思います。
前回の訂正
損失値を算出して、グラフ化しておりましたが、1回ごとの平均値として算出しておりませんでした。
そのため、実際にどれくらいの誤差が生じているか分かりづらかったため、平均値で図をプロットするよう修正しました。
差分はこちらです。
https://github.com/naoki85/python_mahjong/commit
そのため、実際にどれくらいの誤差が生じているか分かりづらかったため、平均値で図をプロットするよう修正しました。
差分はこちらです。
https://github.com/naoki85/python_mahjong/commit
勾配法について
ある重み、バイアスパラメーターのときの、損失関数の勾配(傾き)を求め、傾きが小さくなるようパラメーターを変化させる手法とのことです。
機械学習はこの最適パラメーターを求めるのが1つの命題となっています。
ただ、パラメーターを決めると一口で言っても無限に近い数値の海から探さなければいけません。
ここで本の中で使っていた例えは、思わずへ〜、と頷いてしまいました。
文中ででてくるSGDは、確率的勾配降下法という手法の略です。
機械学習はこの最適パラメーターを求めるのが1つの命題となっています。
ただ、パラメーターを決めると一口で言っても無限に近い数値の海から探さなければいけません。
ここで本の中で使っていた例えは、思わずへ〜、と頷いてしまいました。
文中ででてくるSGDは、確率的勾配降下法という手法の略です。
ここに風変わりな冒険家がいます。彼は広大な乾燥地帯を旅しながら、日々深い谷底を求めて旅を続けています。
~~中略~~
しかも、彼は、厳しい”制約”を2つ自分に課しています。ひとつは地図を見ないこと、もうひとつは目隠しをすることです。
~~中略~~
この困難な状況で重要となってくるのが、地面の「傾斜」です。
~~中略~~
そこで、今いる場所で一番傾斜がきつい方向に進もうというのが、SGDの戦略です。
「ゼロから作るDeep Learning」第6章より引用
勾配を算出する関数について
さて、実際に勾配を算出する段になりまして、少し理解が追いつきませんでした。
例えば、損失関数に対する微分は下記のようになります。(本の中の式)
(Pythonではlambda式で一行で書けるようですが、あえてこちらで記載します。)
fをWに関して微分して勾配を求めます。
ここで、高校数学程度の知識しかない私はこう思いました。
あれ、fをWに関して微分しても、Wが要素になってないから0なんじゃないか、と。
とりあえずこの疑問は置いておいて、本を読み進めていくと、どう考えても勾配を0として計算しているようには見えませんでした。
Wをどこかで関わらせているのかと思い、勾配を求める関数をちゃんと読んでみました。
恥ずかしながら、ここで引っかかり、いまいち以降の処理を理解できておりませんでした。
もし、こちらの本で勉強していて、同じような場所で詰まっているという方がいらっしゃれば、参考にしていただければ、と思います。
例えば、損失関数に対する微分は下記のようになります。(本の中の式)
# xはテストデータ、tは教師データです。
# lossは損失関数です。
def f(W):
return net.loss(x, t)
ここで関数fはxとtから求める損失関数、f(W)でWに関する関数になります。(Pythonではlambda式で一行で書けるようですが、あえてこちらで記載します。)
fをWに関して微分して勾配を求めます。
ここで、高校数学程度の知識しかない私はこう思いました。
あれ、fをWに関して微分しても、Wが要素になってないから0なんじゃないか、と。
とりあえずこの疑問は置いておいて、本を読み進めていくと、どう考えても勾配を0として計算しているようには見えませんでした。
Wをどこかで関わらせているのかと思い、勾配を求める関数をちゃんと読んでみました。
# 実際に呼んでいるコード
# net.Wはネットワーククラスが持つ重みの値(クラスプロパティ)
dW = numerical_gradient(f, net.W)
def numerical_gradient(self, f, x):
h = 1e-4
grad = np.zeros_like(x)
it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
while not it.finished:
idx = it.multi_index
tmp_val = x[idx]
# ここでプロパティの値を上書きしている!
x[idx] = float(tmp_val) + h
fxh1 = f(x)
x[idx] = tmp_val - h
fxh2 = f(x)
grad[idx] = (fxh1 - fxh2) / (2*h)
# ここで元に戻している!
x[idx] = tmp_val
it.iternext()
return grad
つまり、重みパラメーターをクラスに持たせることで、微分式内で値を暫定的に書き換えて処理をさせています。恥ずかしながら、ここで引っかかり、いまいち以降の処理を理解できておりませんでした。
もし、こちらの本で勉強していて、同じような場所で詰まっているという方がいらっしゃれば、参考にしていただければ、と思います。
2017年1月28日土曜日
iOS SwiftでS3への画像アップロード
こんにちは、Hiroです。今回はSwiftでAWSのS3へ画像をアップロードする方法について、ブログを書きたいと思います。
AWS Cognitoでの認証が本来は望ましいのですが、今回は簡単にIAMユーザを作成し、ACCESS KEYとSECRET ACCESS KEYを利用した方法で紹介したいと思います。アプリをリリースする場合は、AWS Cognitoを利用するか、IAMユーザの場合は、アクセス権限を十分に絞ってください。
AWS上での準備については、省略しますが下記の2つを準備してください。IAMユーザについては、作成したS3のバケットへアップロード(PutObject)できる権限を付与しておく必要があります。
Podfileに下記を記載して、インストールします。
冒頭で記載したとおり、今回はIAMユーザでの認証を行います。accessKeyとsecretKeyにはAWSで作成したIAMユーザのものを設定してください。
下記の処理は、S3で画像などをアップロードする前に1度だけ実行するようにします。
S3へ投稿するファイルは、一時的に端末内に保存して、そのURLをS3のSDKに指定する必要があります。
下記のメソッドで、S3へのアップロードする画像が保存されているURLを取得できます。
下記のメソッドでS3へアップロードができます。下記のメソッドを呼ぶ前には、上記で記載している認証の設定を事前に実行する必要があります。
また、「uploadRequest?.bucket」にはAWS上で作成したバケット名を指定し、「uploadRequest?.key」にはS3上に保存したいファイル名を指定します。 なお、ファイル名は「test/hello.jpg」とするとAWSコンソールなどから見た際にtestフォルダ内にhello.jpgファイルが保存されているように見えるので、ファイルをまとめて管理したい場合には、「test/」などのプレフィックスをつけるとよいでしょう。
AWS Cognitoでの認証が本来は望ましいのですが、今回は簡単にIAMユーザを作成し、ACCESS KEYとSECRET ACCESS KEYを利用した方法で紹介したいと思います。アプリをリリースする場合は、AWS Cognitoを利用するか、IAMユーザの場合は、アクセス権限を十分に絞ってください。
AWS上での事前準備
AWS上での準備については、省略しますが下記の2つを準備してください。IAMユーザについては、作成したS3のバケットへアップロード(PutObject)できる権限を付与しておく必要があります。
- S3にバケットを作成
- IAMユーザの作成(上記のバケットへの「s3:PutObject」権限あり)
CocoaPodsでAWS SDKをインストールをする
Podfileに下記を記載して、インストールします。
use_frameworks!
pod 'AWSS3'
$ pod install
認証の設定をする
冒頭で記載したとおり、今回はIAMユーザでの認証を行います。accessKeyとsecretKeyにはAWSで作成したIAMユーザのものを設定してください。
下記の処理は、S3で画像などをアップロードする前に1度だけ実行するようにします。
import AWSCore
...
...
func configureService() {
let credentialsProvider = AWSStaticCredentialsProvider(accessKey: "your access key", secretKey: "your secret key")
let serviceConfiguration = AWSServiceConfiguration(region: AWSRegionType.apNortheast1, credentialsProvider: credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = serviceConfiguration
}
UIImageを保存して、URLを取得する
S3へ投稿するファイルは、一時的に端末内に保存して、そのURLをS3のSDKに指定する必要があります。
下記のメソッドで、S3へのアップロードする画像が保存されているURLを取得できます。
private func generateImageUrl(_ uploadImage: UIImage) -> URL {
let imageURL = URL(fileURLWithPath: NSTemporaryDirectory().appendingFormat("upload.jpg"))
if let jpegData = UIImageJPEGRepresentation(uploadImage, 80) {
try! jpegData.write(to: imageURL, options: [.atomicWrite])
}
return imageURL
}
S3へアップロードする
下記のメソッドでS3へアップロードができます。下記のメソッドを呼ぶ前には、上記で記載している認証の設定を事前に実行する必要があります。
また、「uploadRequest?.bucket」にはAWS上で作成したバケット名を指定し、「uploadRequest?.key」にはS3上に保存したいファイル名を指定します。 なお、ファイル名は「test/hello.jpg」とするとAWSコンソールなどから見た際にtestフォルダ内にhello.jpgファイルが保存されているように見えるので、ファイルをまとめて管理したい場合には、「test/」などのプレフィックスをつけるとよいでしょう。
import AWSS3
...
...
public func uploadImage(_ uploadImage: UIImage) {
let transferManager = AWSS3TransferManager.default()
let uploadRequest = AWSS3TransferManagerUploadRequest()
uploadRequest?.bucket = "your S3 bucket name"
uploadRequest?.key = "your file name on S3"
uploadRequest?.body = generateImageUrl(uploadImage)
transferManager?.upload(uploadRequest).continue({ (task: AWSTask) -> Any? in
if task.error != nil || task.exception != nil {
// エラー
}
return nil
})
}
2017年1月27日金曜日
Swift3でDateからその月の月末のDateを取得
こんにちはonukiです。
今回はSwift3でDateの月末が何日か取得したかったので
備忘録がてら、私が行った方法を紹介したいと思います。
上記では現在日時からDateを作成し、その月の月末にしてるので
例えば2017年1月に実行した場合下記のフォーマットで整形しprintすると「20170131」になります。
今回はSwift3でDateの月末が何日か取得したかったので
備忘録がてら、私が行った方法を紹介したいと思います。
実装
var date = Date()
let calendar = NSCalendar(identifier: NSCalendar.Identifier.gregorian)!
// 年月日時分秒のNSComponents
var comp = calendar.components([.year, .month, .day, .hour, .minute, .second], from: date as Date)
// 月初の0時0分0秒に設定
comp.day = 1
comp.hour = 0
comp.minute = 0
comp.second = 0
// ここでcalendar.date(from: comp)!すれば月初のDateが取得できます
// その月が何日あるかを計算します
let range = calendar.range(of: .day, in: .month, for: date as Date)
let lastDay = range.length
// ここで月末の日に変えます
comp.day = lastDay
// Dateを作成
let retDate = calendar.date(from: comp)!
上記では現在日時からDateを作成し、その月の月末にしてるので
例えば2017年1月に実行した場合下記のフォーマットで整形しprintすると「20170131」になります。
let formatter = DateFormatter()
formatter.dateFormat = "yyyyMMdd"
let dateStr: String = formatter.string(from: retDate as Date)
print(dateStr)
2017年1月26日木曜日
はじめの一歩 -Rails ActiveRecord編- SELECT4
どうも、はじめです。
前回はJOINについて書いてみました。
はじめの一歩 -Rails ActiveRecord編- SELECT3
今回も引き続きJOINに関する内容ですが、JOINでも3つ以上のテーブルの結合について書いていこうと思います。
はじめに
3つ以上のテーブルの結合なので、結合できるテーブルを3つ用意します。
usersテーブル
[id: 1, user_name: 'Aさん'],
[id: 2, user_name: 'Bさん'],
[Id: 3, user_name: 'Cさん']
itemsテーブル
[id: 1, item_name: 'Rubyの本'],
[id: 2, item_name: 'Railsの本'],
[id: 3, item_name: 'PHPの本']
user_itemsテーブル(userが持っているitemを管理するテーブル)
[id: 1, user_id: 1, item_id: 1],
[id: 2, user_id: 1, item_id: 2],
[id: 3, user_id: 2, item_id: 3]
関連を説明すると以下のようになります。
user : user_item => 1 : n
item : user_item => 1 : n
それでは前回使用したincludesを使用して書いていこうと思います。
取得
・Aさんが持っているアイテムを全て取得したい場合
user_items = User.includes(user_items: :item).find(1)
上記のように記述することで以下のようなSQLが実行されます。
SELECT `users`.* FROM `users` WHERE `users`.`id` = 1;
SELECT `user_items`.* FROM `user_items` WHERE `user_items`.`id` in (1,2);
SELECT `items`.* FROM `items` WHERE `items`.`id` in (1,2);
joinsの場合も同様の書き方となります。
表示
アイテム名を表示したい場合は以下のようにします。
user_items.user_items.each do |user_item|
p user_item.item.item_name
end
# => 'Rubyの本'
# => 'Railsの本'
さらにテーブルが増えた場合
itemsにcategoryテーブルを関連付けして色々なパターンで取得をしてみたいと思います。
以下のような関連性でitemsに対し、categoriesテーブルを作成します。
items : category => n : 1
itemsテーブル
[id: 1, item_name: 'Rubyの本', category_id: 1],
[id: 2, item_name: 'Railsの本', category_id: 1],
[id: 3, item_name: 'PHPの本', category_id: 2]
categoriesテーブル
[id: 1, category_name: 'Ruby'],
[id: 2, category_name: 'PHP']
パターン1
・Aさんが持っているアイテムのカテゴリーまで取得したい場合
User.includes(user_items: {item: :category}).find(1)
パターン2
・"Rubyの本"のカテゴリーと持っているユーザーを取得したい場合
Item.includes(:category, {user_items: :user}).find(1)
まとめ
以下のような関連性だった場合
a:b:c => 1:n:1
c:d =>n:1
隣接しているテーブルを複数結合したい場合はのように「,」でつなげることができます。
B.includes(:a, :c)
二つ隣のテーブルの情報を取得する場合は「:」を向かい合わせに記述をします。A.includes(b: :c)
さらに深いテーブルの情報を取得する場合は{}を使用しますA.includes(b: {c: :d})
前回も記述をしたように
3つ以上のテーブルを結合する場合でもテーブル名は
複数系、単数系を意識しなければいけませんので注意してください。
以上でSELECT系(JOIN系)を終了し、
次回からはUPDATEに入ろうと思います。
2017年1月25日水曜日
360度カメラ買いました
どうもー。デザイナーのnottyです。
今年から、NowDevelopingに参加しました。どうぞお見知り置きを 〜
さて、話は変わりまして、最近360度カメラを購入しました。※この記事は360度カメラの模索中のメモです
購入した経緯
正直、まだまだVRが普及するとは思えませんが、360度カメラはWebでコンテンツを見るときに全体の雰囲気や様子を掴めるので使いどころによっては、効果があると思います。(旅行先,不動産,水族館,フェス,山頂,クラブetx...)
今年から、NowDevelopingに参加しました。どうぞお見知り置きを 〜
さて、話は変わりまして、最近360度カメラを購入しました。※この記事は360度カメラの模索中のメモです
THETA SC という機種です。
購入した経緯
正直、何も考えずに買いました。
だから使い道を探るため毎日持ち歩き、撮影しています。
自分の顔やいろんな人の顔が映ってしまうので、公式からですが、
こんな感じの写真が撮れます。
こんな感じの写真が撮れます。
撮った後、写真を見るのが楽しくなるプロダクトです。
技術的に相性が良いのはVRに当たるのかな?
360度カメラのコンテンツはまだまだ面白いのが生まれると感じています。
みたいなWebVRフレームワークが登場したり(2015年で古いですが...)
VRの空間?に絵を描いたり(これ半端ないす)
2017年となった今では情報がたくさんあって、デバイスの性能も良くなったので、利用する人、モノ作りする人は、VRへの参入障壁が低くなったと思います。
今年はVRコンテンツが増えるのか
正直、まだまだVRが普及するとは思えませんが、360度カメラはWebでコンテンツを見るときに全体の雰囲気や様子を掴めるので使いどころによっては、効果があると思います。(旅行先,不動産,水族館,フェス,山頂,クラブetx...)
世の中にあったコンテンツを提供できるように、先回りして技術を知っておく事によって、タイミング良く出せると思います。
今年は研究も兼ねて360×◯◯のようなコンテンツに挑戦します。
_以上
2017年1月24日火曜日
macOS SierraにDocker for Macをインストールしてみる
こんにちは、h_ono_222です。
今回はmacOS SierraにDocker for Macをインストールしてみました。
・OS X El Capitan 10.11以降のOS(10.10.3 Yosemiteは限定的にサポート)
・4GB以上のRAM
・version 4.3.30より前のVirtualBoxがインストールされていないこと
無事にnginxが起動しました。
今回は以上です。
今回はmacOS SierraにDocker for Macをインストールしてみました。
要求スペック
・2010年以降に製造されたMac・OS X El Capitan 10.11以降のOS(10.10.3 Yosemiteは限定的にサポート)
・4GB以上のRAM
・version 4.3.30より前のVirtualBoxがインストールされていないこと
1. Docker for Macのインストール
下記のサイトにアクセスし、Get Docker for Mac[stable]をクリックしてDocker.dmgをダウンロードします。
https://docs.docker.com/docker-for-mac/
Docker.dmgをダブルクリックし、表示されたFinderのDockerアイコンをApplicationsにドラッグ&ドロップします。
Dockerが起動し、メニューバーにDockerのアイコンが表示されます。
Terminalを起動し、Docker commandを入力してみます。
https://docs.docker.com/docker-for-mac/
Docker.dmgをダブルクリックし、表示されたFinderのDockerアイコンをApplicationsにドラッグ&ドロップします。
2. Dockerを起動する
Dockerをダブルクリックするとポップアップが表示されるのでOKを選択し、自分のMacにログインする際のパスワードを入力します。Dockerが起動し、メニューバーにDockerのアイコンが表示されます。
Terminalを起動し、Docker commandを入力してみます。
Users-MacBook-Pro:Desktop User$ docker version
Client:
Version: 1.13.0
API version: 1.25
Go version: go1.7.3
Git commit: 49bf474
Built: Wed Jan 18 16:20:26 2017
OS/Arch: darwin/amd64
Server:
Version: 1.13.0
API version: 1.25 (minimum version 1.12)
Go version: go1.7.3
Git commit: 49bf474
Built: Wed Jan 18 16:20:26 2017
OS/Arch: linux/amd64
Experimental: true
3. サーバを起動する
Users-MacBook-Pro:Desktop user$ docker run -d -p 80:80 --name webserver nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
5040bd298390: Pull complete
d7a91cdb22f0: Pull complete
9cac4850e5df: Pull complete
Digest: sha256:33ff28a2763feccc1e1071a97960b7fef714d6e17e2d0ff573b74825d0049303
Status: Downloaded newer image for nginx:latest
61a7880cc6d001376f222cb3214c457c3d625720a5111a72dba14415a0d2d40f
無事にnginxが起動しました。
今回は以上です。
2017年1月23日月曜日
配牌からあがれる可能性を予測する!(その3 学習の実装)
前回の記事はこちらです。
配牌からあがれる可能性を予測する!(その2 教師データの作成)
配牌からあがれる可能性を予測する!(その2 教師データの作成)
前回の訂正
CSVファイルからの読み込み時、String型になってしまうので、Int型にキャストしなければなりませんでした。
差分はこちらになりますが、その中でリスト内包記述というfor文を1行で書くように修正しております。
差分はこちらになりますが、その中でリスト内包記述というfor文を1行で書くように修正しております。
# 修正前
tmp_hand = []
for tile in range(0, 12):
tmp_hand.append(row[tile])
# 修正後
tmp_hand = [int(tile) for tile in row]
学習の実装開始
今回より学習機能をつけていきたいと思います。
基本的には、「ゼロから作るディープラーニング」の手順で論理を進めています。
(誤差を求め、その誤差の微分値からパラメータを求める。)
ソースコードはこちらになります。
https://github.com/naoki85/python_mahjong
基本的には、「ゼロから作るディープラーニング」の手順で論理を進めています。
(誤差を求め、その誤差の微分値からパラメータを求める。)
ソースコードはこちらになります。
https://github.com/naoki85/python_mahjong
matplotlib について
その前に、グラフを描画する便利ライブラリであるmatplotlibの準備をしておきます。
まだそこまで複雑なグラフはいらないので、基本的な書き方で大丈夫そうです。
今回はX軸はループの回数、Yは誤差(教師データとの誤差とします。)
まだそこまで複雑なグラフはいらないので、基本的な書き方で大丈夫そうです。
今回はX軸はループの回数、Yは誤差(教師データとの誤差とします。)
# xの値を1ずつ定義
x = range(0, 100)
# ループごとに誤差を格納しておく
y = loss_array
plt.xlabel("x")
plt.ylabel("loss")
plt.plot(x, y)
plt.show()
ためしに作ってみた図はこちらです。
ループ回数を重ねるごとに、誤差がちいさくなっていることが分かります。
ただし、こちらの正当性はまだ確認できていないので、実際に次回は学習後の重み、バイアスを使用してテストしてみます。
ただし、こちらの正当性はまだ確認できていないので、実際に次回は学習後の重み、バイアスを使用してテストしてみます。
学習結果の保存について(pickleモジュール)
学習結果はpickle形式で保存しました。
pickleは「漬物」という意味で、オブジェクトをそのまま保存してくれます。(ピクルスのことか、と覚えました。)
はじめはCSV形式にしようと思ったのですが、いちいち分解して保存するのも、取り出すときに再度辞書型にするのも面倒です。
例えば、下記の結果を保存するとします。
pickleは「漬物」という意味で、オブジェクトをそのまま保存してくれます。(ピクルスのことか、と覚えました。)
はじめはCSV形式にしようと思ったのですが、いちいち分解して保存するのも、取り出すときに再度辞書型にするのも面倒です。
例えば、下記の結果を保存するとします。
{'W': [1, 2, 3], 'b': [4, 5]}
これを特に前処理なしで下記のように保存(漬物)にしてしまいます。(基本的なファイルの読み書きと同じ感じです。)with open(pickle_filepath, 'wb') as f:
writer = pickle.dump(results, f)
取り出すときも下記のようにかけば、なんとびっくりそのまま取り出せます。with open(pickle_filepath, 'rb') as f:
params = pickle.load(f)
{'W': [1, 2, 3], 'b': [4, 5]}
そのため、重み、バイアスの値は教師データとは異なりpickleで管理することとしました。
おわりに
まだ私自身、微分して最適な重みを求める「勾配法」について、 腑に落ちていないところがあるので、
そちらを理解して、実装を踏まえて書きたいと思います。
そちらを理解して、実装を踏まえて書きたいと思います。
2017年1月21日土曜日
配牌からあがれる可能性を予測する!(その2 教師データの作成)
こんにちは、Taroです。
前回の記事の記事の続きになります。
配牌からあがれる可能性を予測する!(その1 推論処理)
次回は学習を実装する、と記載しましたが、その前に教師データを取得する方法を実装したいと思います。
今回はDeep LearningというよりはPythonの勉強といった感じです。
前回の記事の記事の続きになります。
配牌からあがれる可能性を予測する!(その1 推論処理)
次回は学習を実装する、と記載しましたが、その前に教師データを取得する方法を実装したいと思います。
今回はDeep LearningというよりはPythonの勉強といった感じです。
教師データの選定
麻雀のようなギャンブルにおいて、教師になるデータは何なのか?
考え出すとキリがなさそうなので、ひとまずプロの対局からデータを作成しました。
プロであれば、(もちろん技術や個性、状況で異なってくるとは思いますが)あがりやすい配牌は必ず仕上げてくれるはずです。
そのため、Youtubeでプロの対局を見続けました(ある種これが苦行かもしれません笑)。
余談ですが、個人的に好きなプロ雀士は土田浩翔プロです。
考え出すとキリがなさそうなので、ひとまずプロの対局からデータを作成しました。
プロであれば、(もちろん技術や個性、状況で異なってくるとは思いますが)あがりやすい配牌は必ず仕上げてくれるはずです。
そのため、Youtubeでプロの対局を見続けました(ある種これが苦行かもしれません笑)。
余談ですが、個人的に好きなプロ雀士は土田浩翔プロです。
CSVファイルの作成
教師データはCSVファイルにまとめます。
今回必要なデータは、 配牌 と 結果 なので、下記のようにまとめました。
今回必要なデータは、 配牌 と 結果 なので、下記のようにまとめました。
tile_1 | tile_2 | tile_3 | tile_4 | tile_5 | tile_6 | tile_7 | tile_8 | tile_9 | tile_10 | tile_11 | tile_12 | tile_13 | win | loss |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
11 | 13 | 17 | 21 | 25 | 27 | 29 | 31 | 31 | 31 | 35 | 43 | 47 | 1 | 0 |
このデータを読み込んでいきたいと思います。
CSVファイルの読み込み
Pythonの
(というよりこれくらいしか分からない。。。)
csv
モジュールを利用して簡単に実装します。(というよりこれくらいしか分からない。。。)
def load_trainig_data(self):
u"""
CSVファイルから教師データを読み込み、データを返します。
@return array
[0]で教師データの配牌、[1]で結果を返します
"""
with open('csv/training_data.csv', 'r', newline='') as csvfile:
reader = csv.reader(csvfile)
header = next(reader)
hand = []
results = []
for row in reader:
tmp_hand = []
for tile in range(0, 12):
tmp_hand.append(row[tile])
results.append([row[13], row[14]])
hand.append(tmp_hand)
return hand, results
このメソッドをMyHandクラスに追加しました。
from my_hand import *
my_hand = MyHand()
input_data, results = my_hand.load_trainig_data()
print(input_data)
[['47', '26', '17', '21', '47', '12', '42', '43', '34', '15', '45', '37'], ['42', '42', '41', '17', '39', '21', '39', '15', '37', '11', '11', '21'], ['47', '35', '22', '22', '23', '26', '12', '13', '17', '18', '39', '38'], ['22', '24', '24', '25', '28', '31', '32', '33', '13', '13', '14', '16'], ['41', '47', '31', '12', '29', '18', '45', '34', '19', '22', '18', '39'], ['46', '15', '15', '16', '16', '47', '45', '11', '43', '32', '34', '27'], ['41', '41', '43', '44', '44', '17', '14', '13', '13', '23', '23', '33'], ['35', '38', '39', '39', '23', '25', '26', '27', '28', '16', '42', '42'], ['45', '47', '39', '44', '43', '21', '36', '27', '13', '32', '39', '16'], ['21', '28', '32', '35', '21', '23', '35', '12', '18', '37', '45', '14'], ['12', '14', '15', '17', '41', '44', '34', '35', '22', '23', '23', '26'], ['24', '24', '29', '31', '32', '36', '37', '38', '39', '13', '17', '47']]
print(results)
[['0', '1'], ['1', '0'], ['0', '1'], ['0', '1'], ['0', '1'], ['0', '1'], ['1', '0'], ['0', '0'], ['1', '0'], ['0', '0'], ['0', '0'], ['0', '0']]
これだとちょっと分かりづらいので、1つ目の要素だけ抜き出します。
print(input_data[0])
['47', '26', '17', '21', '47', '12', '42', '43', '34', '15', '45', '37']
print(results)
['0', '1']
これで、教師データが読み込めました。
(これで正しいのかは置いておきます笑)
(これで正しいのかは置いておきます笑)
Jupyter Notebookで書いてみたよ!
Jupyterという単語は見たことがあったのですが、ずっとライブラリの1つだと思っていました笑。
実はエディタのようで、データサイエンティストの人などが、実際に実行したプログラムを確認しながら文章を書いたりするもののようです。
Anacondaをインストールすると一緒についてきます。
詳しいことは諸先輩方が記述しておりますので、割愛しますが、本記事も下図のように書きました。
実はエディタのようで、データサイエンティストの人などが、実際に実行したプログラムを確認しながら文章を書いたりするもののようです。
Anacondaをインストールすると一緒についてきます。
詳しいことは諸先輩方が記述しておりますので、割愛しますが、本記事も下図のように書きました。
プロジェクト上に配置しておけば、自作のコードも読み込んで実行してくれます。
Python以外の言語もサポートしているようなので、コードと実行結果をブログにのせたいときは使用を検討しても良いのではないでしょうか?
Python以外の言語もサポートしているようなので、コードと実行結果をブログにのせたいときは使用を検討しても良いのではないでしょうか?
2017.01.21 追記
何も考えずに、Jupyterが生成してくれたソースコードを貼り付けたら、Google bloggerのCSSなどを上書きしてしまったようで、不都合が生じました。
急いで書き直したので、結局普通になってしまいました。。。笑
ブログなどに貼り付けるときは事前に検討が必要です。
急いで書き直したので、結局普通になってしまいました。。。笑
ブログなどに貼り付けるときは事前に検討が必要です。
おわりに
今回のソースコードは下記になります。
Jupyter Notebookで作成したファイルは.ipynb拡張子で保存されています。
https://github.com/naoki85/python_mahjong
次回は、今度こそ学習ロジックの実装をしたいと思います!
Jupyter Notebookで作成したファイルは.ipynb拡張子で保存されています。
https://github.com/naoki85/python_mahjong
次回は、今度こそ学習ロジックの実装をしたいと思います!
第3回書きました!
配牌からあがれる可能性を予測する!(その3 学習の実装)
配牌からあがれる可能性を予測する!(その3 学習の実装)
2017年1月20日金曜日
Swift3でTTTAttributedLabelの文字列からリンク表示をやってみた
こんにちはonukiです。
今回はTTTAttributedLabelを使用し、
文字列からリンクを表示、リンクタップ制御を
Swiftでの実装方法を書いてこうと思います。
今回はTTTAttributedLabelを使用し、
文字列からリンクを表示、リンクタップ制御を
Swiftでの実装方法を書いてこうと思います。
TTTAttributedLabelとは
リッチなテキストを表示するためのUILabelの機能を拡張するOSSです。
その機能の一つに文字列からリンクを検出してくれる機能があるので
今回は主にその部分の実装についてになります。
準備
インストールにはCocoaPodsを使用します。
pod 'TTTAttributedLabel'
それと、TTTAttributedLabelはObjective-Cで書かれているので
Bridging-Header.hにimportしてください。
#import <TTTAttributedLabel/TTTAttributedLabel.h>
実装
まずはTTTAttributedLabelをimportします
import TTTAttributedLabel
StoryboardにUILabelを適当に用意し
ClassにTTTAttributedLabelを指定してください。
それをIBOutlet接続します。
@IBOutlet weak var linkLabel: TTTAttributedLabel!
テキストのリンクをタップできるように設定します。
linkLabel.enabledTextCheckingTypes = NSTextCheckingResult.CheckingType.link.rawValue
リンクを含むテキストをセットします。
linkLabel.text = "URLにタップできます。\nhttps://www.google.co.jp/"
そうするとこのような表示になります。
このままだとタップが検知できないので
TTTAttributedLabelDelegateを設定します。
class ViewController: UIViewController, TTTAttributedLabelDelegate {
TTTAttributedLabelのDelegateを設定します。
linkLabel.delegate = self
テキスト内のリンクがタップされた場合、以下のメソッドが呼ばれます。
func attributedLabel(_ label: TTTAttributedLabel!, didSelectLinkWith url: URL!) {
//処理
}
これで、文字列からリンクを表示、リンクタップ制御ができたと思います。
2017年1月19日木曜日
はじめの一歩 -Rails ActiveRecord編- SELECT3
どうも、はじめです。
前回はActiveRecordのSELECTについて書いてみました。
はじめの一歩 -Rails ActiveRecord編- SELECT2
今回はActiveRecordのデータの取得(SELECT)の中でもJOIN系に関して書いていこうと思います。
はじめに
booksテーブルに以下のデータが登録済みであることを前提とします。
[id: 1, title: ‘Rubyの本’, publisher_id: 1],
[id: 2, title: ‘Railsの本’, publisher_id: 1],
[Id: 3, title: ‘PHPの本’, publisher_id: 2]
今回はJoin系のメソッドについて書いていくので、
booksに対し多対1で紐づくpublishersテーブルを以下のように用意します。
[id: 1, publisher_name: '出版社1'],
[id: 2, publisher_name: '出版社2']
joins
joinsはinner joinでの結合を行います。
Books.joins(:publisher)
# SELECT `books`.* FROM `books` INNER JOIN `publishers` ON `publishers`.`id` = `books`.`publisher_id`
出版社名を表示したい場合は以下のように表示をすることができます。
例としてbooksテーブルのID:1のレコードで取得してみます。
book = Book.joins(:publisher).find(1)
p book.publisher.publisher_name
# '出版社1'
※joinsを使用するとreadonlyとなるため更新ができないと
いろいろなところで目にしましたが、手元で確認をしたところreadonlyはfalseとなっていました。
ちなみにRailsのバージョンは5.0.0.1です。
バージョンによるものか環境によるものかはわかりませんが、
実際に使用する場合は一度確認をしてみるべきだと思います。
joinsを使用した状態でwhereを使用したい場合は以下のように書くことができます。
# Bookの情報で検索を行いたい場合
Book.joins(:publisher).where(title: ‘Railsの本’)
# Publisherの情報で検索を行いたい場合(以下の二つは同じ内容が実行されます)
Book.joins(:publisher).where(publishers: {publisher_name: '出版社1'})
Book.joins(:publisher).where("publishers.publisher_name = '出版社1'")
mergeを使用するとActiveRecord::Relationを使用して検索することもできます。Book.joins(:publisher).merge(Publisher.where(publisher_name: '出版社1'))
※後で記述するincludesでは使用できませんでした。使用できない理由はこの後書かせていただきます。
includes
includesは結合先のテーブルと結合元のテーブルに対し
別々にクエリを実行してデータを取得します。
Book.includes(:publisher)
# SELECT `books`.* FROM `books`
# SELECT `publishers`.* FROM `publishers` WHERE `publishers`.`id` IN (1, 2)
表示の仕方はjoinsと同じです。
book = Book.joins(:publisher).find(1)
p book.publisher.publisher_name
# '出版社1'
それぞれに対して別々にクエリを実行していることから、
指定したデータがBookに存在していない場合はPublisherに対するクエリは実行されません。
Book.joins(:publisher).find(4)
# SELECT `books`.* FROM `books` WHEHE `books`.`id` = 4
includesを使用した状態でwhereを使用したい場合は、
どのカラムで検索するかによって実行されるSQLの内容が変わってくるので注意が必要です。
実際に違いを見てみます。
検索条件のパターンとして以下の2つをあげます。
1.Book内の情報で検索をする
2.Publish内の情報で検索をする
実際に試してみます。1.Book内の情報で検索をする
Book.includes(:publisher)where(title: ‘Railsの本’)
# SELECT `books`.* FROM `books` WHERE `books`.`title` = "Railsの本"
# SELECT `publishers`.* FROM `publishers` WHERE `publishers`.`id` = 1
こちらは条件指定をしない場合と変わりません。2.Publish内の情報で検索をする
Book.includes(:publisher)where(publishers: {publisher_name: '出版社1'})
# SELECT `books`.`id, `books`.`title`, `books`.`publisher_id`, `publishers`.`id`, `publishers`.`publisher_name`
# FROM `books` LEFT OUTER JOIN `publishers` ON ``publishers`.`id` = `books`.`publisher_id`
# WHERE `publishers`.`publisher_name` = "出版社1"
このように結合先のテーブル情報で検索を行うと"LEFT OUTER JOIN"を使った結合が行われます。includesでmergeを使用した場合以下のようなSQLが実行されます。
Book.includes(:publisher).merge(Publisher.where(publisher_name: '出版社1'))
# SELECT `books`.* FROM `books` WHERE `publishers`.`publisher_name` = "出版社1"
クエリが各テーブル毎に発行されているためこのようなクエリが生成されるのだと思います。最後に
今回のJOIN系に関して個人的に大変だと思ったのはテーブル名の記述です。
joinsやincludesで指定するテーブル名ですが、
自分から見て結合するテーブルがどのような関連性を持っているかによって
記述するテーブル名が変わってきます。
・自分から見て結合先のテーブルが一つしか存在しない場合(Bookから見たPublishのような関係) 単数系のテーブル名で指定する。 ・自分から見て結合するテーブルのデータが複数存在する場合(Publishから見たBookのような関係) 複数形のテーブル名で指定する。
また、結合先のテーブル情報でwhereを使用する場合は
複数形のテーブル名で指定をします。
今回書ききれなかったこともあるので、次回もJOIN系の続きを書きます。
2017年1月17日火曜日
サイバーセキュリティ入門 後編
こんにちは、h_ono_222です。
今回のドトール会のテーマは「サイバーセキュリティ入門: 私たちを取り巻く光と闇」の「4. インターネットにおけるサイバー攻撃」についてです。
4. インターネットにおけるサイバー攻撃
ここでは、有名な攻撃手法とその手口について書かれています。
具体的には、
- DoS(DDoS)攻撃
- 標的型攻撃
- クロスサイトスクリプティング(XSS)
- SQLインジェクション
- DNSキャッシュポイズニング
- クロスサイトリクエストフォージェリ(CSRF)
など(個人的な観点に基づいて抜粋しました)です。
上記の攻撃手法について簡単に説明します。
(1) DoS(DDoS)攻撃
DOSはDenial of Serviceの略語です。
攻撃目標(Webサイトなど)に対してリクエストを大量に送りつけ、サーバのメモリやCPUを浪費させて処理能力を低下させたり、
ネットワークを過負荷にすることにより攻撃目標のサービスを妨害します。
DDoSはDistributed DoSの略語で、分散DoSとも呼ばれます。
ボットネットワーク(ボットに感染した複数のホストにより構成されたネットワーク)から攻撃目標に対して一斉にリクエストを送りつける攻撃です。
(2)標的型攻撃
攻撃目標をある程度絞って行う攻撃で、一般的にはマルウェアやSPAMなどの迷惑メールを介して行われます。
標的型攻撃でのメールは攻撃目標が関心をもっている、あるいは、関係あると思わせるような内容が記載されていることが多々あります。
しかし、標的型攻撃では攻撃者がある程度攻撃対象の情報を持っていなければならず、送られたメールから攻撃者を特定できる場合もあるため、近年では減少傾向にあります。
(3)クロスサイトスクリプティング(XSS)
ウェブサイトに対する攻撃手法の代表とも言われるほどメジャーな攻撃方法です。
攻撃者は文字列を入力させるフォーム(例えばコメント欄など)に対してJavaScriptコードを入力します。
これにより、サニタイジング(入力された文字列をエスケープし無害な文字列に変換すること)がしっかりされていないサイトでは、任意のJavaScriptコードを実行できてしまいます。
(4)SQLインジェクション
フォームに対して不正な文字列を入力することで、攻撃対象のデータベースを制御する攻撃です。
例えば、ログインフォームに下記のような入力を行います。
(2)標的型攻撃
攻撃目標をある程度絞って行う攻撃で、一般的にはマルウェアやSPAMなどの迷惑メールを介して行われます。
標的型攻撃でのメールは攻撃目標が関心をもっている、あるいは、関係あると思わせるような内容が記載されていることが多々あります。
しかし、標的型攻撃では攻撃者がある程度攻撃対象の情報を持っていなければならず、送られたメールから攻撃者を特定できる場合もあるため、近年では減少傾向にあります。
(3)クロスサイトスクリプティング(XSS)
ウェブサイトに対する攻撃手法の代表とも言われるほどメジャーな攻撃方法です。
攻撃者は文字列を入力させるフォーム(例えばコメント欄など)に対してJavaScriptコードを入力します。
これにより、サニタイジング(入力された文字列をエスケープし無害な文字列に変換すること)がしっかりされていないサイトでは、任意のJavaScriptコードを実行できてしまいます。
(4)SQLインジェクション
フォームに対して不正な文字列を入力することで、攻撃対象のデータベースを制御する攻撃です。
例えば、ログインフォームに下記のような入力を行います。
user_name = hogehoge
password = 'OR'A' = 'A
これにより発行されるSQLは下記のようになります。
SELECT * FROM users WHERE user_name = hogehoge AND password = ''OR 'A' = 'A'
ORの後ろの'A' = 'A'は真となるためログインに成功してしまいます。
(6)DNSキャッシュポイゾニング
DNSは大本であるルートサーバ、対象ドメインを管理する権威DNSサーバ(プライマリサーバ)、
キャッシュサーバ(セカンダリサーバ)から構成されています。
ユーザはまずキャッシュサーバに問い合わせを行います。
問い合わせたドメインがキャッシュにない場合、キャッシュサーバはルートサーバに問い合わせを行い、その後、委任されたDNSサーバを辿って最終的な権威DNSサーバに問い合わせを行います。
攻撃者はキャッシュサーバが問い合わせを行っている間に、キャッシュサーバに対して偽のDNSレスポンスを連続的に送ります。
キャッシュサーバは送られてきた偽のレスポンスを正規のレスポンスとして受け入れます。
その結果、そのドメインにアクセスしたユーザは偽のアドレスに誘導されてしまいます。
(7)クロスサイトリクエスをフォージェリ(CSRF)
攻撃者はまず、脆弱性を持つウェブサイトを見つけ出し、不正なプログラムを仕込むなどの改ざんを行います。
次に、匿名掲示板やメールなどを通じて改ざんしたサイトに誘導します。
改ざんしたサイトにアクセスが有ると、仕込んだ不正なプログラムをユーザ(ブラウザなど)に送り込み支配します。
攻撃者の命令がインターネットを通じて発行されると、支配したブラウザなどを通し別のサイトなどへ不正なリクエストを送ります。
本来被害者であるはずのユーザが加害者になってしまうところがこの攻撃の脅威です。
本日は以上です。
(6)DNSキャッシュポイゾニング
DNSは大本であるルートサーバ、対象ドメインを管理する権威DNSサーバ(プライマリサーバ)、
キャッシュサーバ(セカンダリサーバ)から構成されています。
ユーザはまずキャッシュサーバに問い合わせを行います。
問い合わせたドメインがキャッシュにない場合、キャッシュサーバはルートサーバに問い合わせを行い、その後、委任されたDNSサーバを辿って最終的な権威DNSサーバに問い合わせを行います。
攻撃者はキャッシュサーバが問い合わせを行っている間に、キャッシュサーバに対して偽のDNSレスポンスを連続的に送ります。
キャッシュサーバは送られてきた偽のレスポンスを正規のレスポンスとして受け入れます。
その結果、そのドメインにアクセスしたユーザは偽のアドレスに誘導されてしまいます。
(7)クロスサイトリクエスをフォージェリ(CSRF)
攻撃者はまず、脆弱性を持つウェブサイトを見つけ出し、不正なプログラムを仕込むなどの改ざんを行います。
次に、匿名掲示板やメールなどを通じて改ざんしたサイトに誘導します。
改ざんしたサイトにアクセスが有ると、仕込んだ不正なプログラムをユーザ(ブラウザなど)に送り込み支配します。
攻撃者の命令がインターネットを通じて発行されると、支配したブラウザなどを通し別のサイトなどへ不正なリクエストを送ります。
本来被害者であるはずのユーザが加害者になってしまうところがこの攻撃の脅威です。
本日は以上です。
2017年1月16日月曜日
配牌からあがれる可能性を予測する!(その1 推論処理)
こんにちは、Taroです。
日増しに寒くなってきましたね。
今年もセンター試験は大寒波とかニュースでやっていましたが、毎年そうなのでタイミングが悪いんですかね?
ゼロから作るDeep Learningを読んでいます
最近、趣味かつ独学ではありますが、Deep Learningの勉強をしています。
「ゼロから作るDeep Learning」は初心者でも分かりやすい本だと思います。
(知識がない私でも頑張ってなんとかついていっています笑)
しかし、(私自身に知識がないためだとは思いますが)いまいちピンときません。
ピンとこないというのは、意味が分からないということではなく、「実際にこれをどうやって使うんだろう」というところです。
あれこれ悩んだ結果、簡単なネットワークを自分で作ってみようと思いつきました。
せっかくなら自分の興味のある麻雀をベースに、
配牌を入力して、あがれるかあがれないか予測する
モデルを作ってみたいと思います。
ソースコードも公開していきますが、Deep LearningどころかPythonも初心者なので、ぜひご指導をお願いしますm(_ _)m
麻雀は知らないけど、Deep Learningとか興味ある、という方でも読んでいただけるようにしていきます。
とりあえず設計
配牌(はじめに配られる手札のようなもの)から、アガリの確率を求めるために必要なファクターは何か、真剣に考えてみました(それはもう、プログラムを書いているとき以上に)。
また、あまりに複雑すぎるファクターだと私が実装できない可能性があり、かつ本筋を見失いかねないので、以下の3つの要素としました。
- 配牌時に存在する順子の数
- 配牌時に存在する対子の数
- 配牌時に存在する暗刻の数
これら3つの要素を算出し、それぞれに対して重み(W)を掛けて、最終的な総和からアガれるかアガれないか予測します。
ちょっと私の説明が下手なきらいもあるので、図にしたいと思います。
データの扱い
例えば、下記のような配牌があります(一番右の牌は無視してください笑)。
このときの入力値はリスト型で、
input_data = [14, 15, 19, 23, 25, 25, 32, 37, 39, 39, 43, 43, 47]
と渡します。
順子の数は0、対子の数が3つ、暗刻の数が0です。
そのため、
X1 = 0
X2 = 3
X3 = 0
とします。
ここで、それぞれに対して重みWを掛けます。
重みは、それぞれのファクターがどれだけ寄与しているか示す値です。
この重みを今後学習させて、最適な値を探していきます。
今回は適当な値を渡しておきます。
そして、最後にそれらを足し合わせて結論を導きます。
結論を導く際に、バイアスで閾値を設定しますが、こちらも今後の学習で値を決めていくので、今回は適当な値を入れます。
最終的には下記のように出力させたいと思います。
result = [0.50407631, 0.49592369]
第一要素がアガれる確率、第二要素がアガれない確率と考えます。
今回は適当な値を入れたので、フィフティフィフティみたいな中途半端なことになっておりますが、今後の学習で立派な予想屋になってもらいます!
次回は、学習を実装していきたいと思います。
できれば完成までお付き合いください!
最後に、ソースコードはこちらになりますので、よろしければご覧ください。
https://github.com/naoki85/python_mahjong
2017年1月14日土曜日
Rails5 alias_method_chain is deprecated.
こんにちは、Hiroです。
直近のプロジェクトでは、Rails5を使っているのですが、利用しているgem関連で下記のような警告が大量に出力されるので、少し調べてみました。
(「./bin/rails c」や「./bin/bundle exec rspec」を実行すると大量に出力されます。)
まず、deprecatedになった「alias_method_chain」ですが、下記のように利用します。
実行結果を下記に記載しますが、置き換わっているのがわかると思います。
早速、「Module#prepend」の使い方ですが下記のように使います。
そのため、HelloWithWorldモジュールのメソッド内でsuperを呼び出すことで元々のメソッドを呼び出すことができます。
実行結果とancestorsメソッドで継承関係を表示しておきます。HelloWithWorldがHelloUserの前にあるのがわかると思います。
Rails5にしたものの、全てのgemに対して、この警告を消すための書き換えの対応をしていくのは大変。
ただ、この出力が目障りという方は、「config/application.rb」に下記を書けば、消すことができますが、自己責任でお願いしますね。
deprecatedなメソッドは、今後のアップデートで利用できなくなることもありますので、しっかりと理解した上で利用し、可能であれば、置き換えていくようにしましょう。
直近のプロジェクトでは、Rails5を使っているのですが、利用しているgem関連で下記のような警告が大量に出力されるので、少し調べてみました。
(「./bin/rails c」や「./bin/bundle exec rspec」を実行すると大量に出力されます。)
DEPRECATION WARNING: alias_method_chain is deprecated.
これは、Rails5からはActiveSupportの「alias_method_chain」がdeprecatedになり、代わりに「Module#prepend」を使うように促しています。alias_method_chainとは
まず、deprecatedになった「alias_method_chain」ですが、下記のように利用します。
class HelloUser
def hello
puts 'Hello'
end
def hello_with_world
hello_without_world
puts 'World'
end
alias_method_chain :hello, :world
end
上記のコードは、「alias_method」を使った場合は、下記と同等になります。
class HelloUser
def hello
puts 'Hello'
end
def hello_with_world
hello_without_world
puts 'World'
end
alias_method :hello_without_world, :hello
alias_method :hello, :hello_with_world
end
helloメソッドがhello_with_worldメソッドに置き換わり、元々のhelloメソッドはhello_without_worldメソッドとして使えるようになります。実行結果を下記に記載しますが、置き換わっているのがわかると思います。
[1] pry(main)> hello_user = HelloUser.new
[2] pry(main)> hello_user.hello
Hello
World
[3] pry(main)> hello_user.hello_without_world
Hello
Module#prependとは
早速、「Module#prepend」の使い方ですが下記のように使います。
class HelloUser
def hello
puts 'Hello'
end
end
module HelloWithWorld
def hello
super
puts 'World'
end
end
HelloUser.prepend(HelloWithWorld)
prependされたHelloWithWorldモジュールは継承関係上で、HelloUserクラスより手前に位置することになり、helloメソッドを
オーバーライドしたような形になります。そのため、HelloWithWorldモジュールのメソッド内でsuperを呼び出すことで元々のメソッドを呼び出すことができます。
実行結果とancestorsメソッドで継承関係を表示しておきます。HelloWithWorldがHelloUserの前にあるのがわかると思います。
[1] pry(main)> hello_user = HelloUser.new
[2] pry(main)> hello_user.hello
Hello
World
[3] pry(main)> HelloUser.ancestors
=> [HelloWithWorld,
HelloUser,
ActiveSupport::ToJsonWithActiveSupportEncoder,
Object,
PP::ObjectMixin,
RequireAll,
ActiveSupport::Dependencies::Loadable,
JSON::Ext::Generator::GeneratorMethods::Object,
ActiveSupport::Tryable,
Kernel,
BasicObject]
モンキーパッチなどを書くときに利用することになると思います。(モンキーパッチなんて書かずに、githubにプルリクする方がよいですが)とりあえず、DEPRECATION WARNINGの出力をなくしたい
Rails5にしたものの、全てのgemに対して、この警告を消すための書き換えの対応をしていくのは大変。
ただ、この出力が目障りという方は、「config/application.rb」に下記を書けば、消すことができますが、自己責任でお願いしますね。
require_relative 'boot'
require 'rails/all'
# TODO: DEPRECATION WARNING: alias_method_chain is deprecated
ActiveSupport::Deprecation.silenced = true
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
...
...
deprecatedなメソッドは、今後のアップデートで利用できなくなることもありますので、しっかりと理解した上で利用し、可能であれば、置き換えていくようにしましょう。
2017年1月13日金曜日
Swift3でMapKitの複数のピンを一括で表示・削除する方法
こんにちは、onukiです。
今回はMapKitでピンを一括で表示・削除する方法について、
例えばカテゴリーごとにピンを表示したい、
カテゴリー切り替え時にピンをごっそり入れ替えたいみたいな使い方がしたかったのですが
以外と調べても出てこなかったので備忘録がてら書いておきます。
今回はMapKitでピンを一括で表示・削除する方法について、
例えばカテゴリーごとにピンを表示したい、
カテゴリー切り替え時にピンをごっそり入れ替えたいみたいな使い方がしたかったのですが
以外と調べても出てこなかったので備忘録がてら書いておきます。
やり方
大体、ピンの表示方法を調べると以下のような書き方が出てきます。
let annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2DMake(37.331652997806785, -122.03072304117417)
self.mapView.addAnnotation(annotation)
これだと入れ替えが面倒なので今回は以下のようにします。
まず、グローバル変数にMKAnnotationの配列を用意します。
var annotationArray: [MKAnnotation] = []
マップにMKAnnotationを追加します。
for coordinate in coordinateArray! {
let annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2DMake(coordinate.latitude, coordinate.longitude)
annotationArray.append(annotation)
}
self.mapView.addAnnotations(annotationArray)
設定したピンを削除したい時は、こうすると先ほど設定したピンを全削除できます。
self.mapView.removeAnnotations(annotationArray)
これで複数のMKAnnotation配列を用意してやり、
用途に応じてremoveとaddをしてやれば
複数のピンの入れ替えが出来るようになります。
2017年1月11日水曜日
Google Developers LaunchPad Build Tokyo 2016に参加してきました。
昔のイベントレポートだが、メモに貼り付けているだけだと忘れるので備忘録的にレポートを書きます。
2016.10.7に私はGoogle Developers LaunchPad Build Tokyo 2016に参加してきました。
2016.10.7に私はGoogle Developers LaunchPad Build Tokyo 2016に参加してきました。
イベント内容
Google Developers LaunchPad Build は、アプリデベロッパー・デザイナーの方に向けたイベントです。今回のイベントでは、Material Design を中心としたデザインが、アプリやサービスにおいていかに重要になるかについてのセッションを行います。GoogleがMaterial Designについて、他社の活用事例や守るべきルールなどを発表するイベントです。
プログラム一部(私が特に良かったと感じたセッション)
- アプリデザインで守るべき 25 のルール
- Material Design Fireside Chat(マテリアルデザインを導入している企業のセッション) マネーフォワード,Fril,C CHANNEL,Famm等の聞いたことのある企業の方がセッションに参加していました。
当日のタイムテーブル
アプリデザインで守るべき 25 のルール
アプリ内のコンバージョンを増やすため、そのためのユーザー体験をどう改善していくかなどの守るべきルールを紹介するプログラムです。
25個すべて書くのは、ボリューミーになってしますので、個人的にピックアップ(驚きや新たな発見)したのをご紹介します。
- 日本のユーザー半数近く、ストアのレビューを参考にしてインストール。
- 平均36個のアプリが入っていて、1ヶ月に2個インストールし、1個アンインストールしている。
- アプリが高評価であるほど高収益 – 星2→3になると9倍 星3→4になると4倍
- 迷子にならないナビゲーション
- インストールして何をユーザーが期待するかを考え、機能を適切に見せてあげることが大事。
- アプリを立ちげ5分以内に「いいな!」と思わなければユーザーは立ち去る
- 丁寧な操作説明
まれにユーザーによって意味を間違える。「クレジットカードをスキャンしてください」というアナウンスに対して、カメラ撮影してほしいところ、端末の上にクレジットカードを置いて待機していた(スキャンできると勘違い)人が103人中3人。 - 納得感のあるユーザビリティ
- アイコンだけのボタンは良くない。テキストラベルを補充しよう。
- 「☆」アイコンも人によって「お気に入り」「ランキング」などなど全ての人が同じ解釈をするとは限らないから説明大事。
ユーザーの視点に関して、細かく説明されているので非常に参考になりました。ユーザー目線と思って作ったモノが実際にはユーザーにとって障壁が高かったり、文化の違い等で思ったように解釈されてない部分にハッとさせられました。
全てご紹介できなかったですが動画で見れます。
Material Design Fireside Chat
マテリアルデザインを導入している企業のセッションです。導入した経緯、導入してどうなったかなど、普段聞けない話が聞けました。
共通していた話題をピックアップして紹介します。
共通していた話題をピックアップして紹介します。
マテリアルデザイン導入のきっかけ
- 知ってて当たり前だったので自然と導入
- リニューアルのタイミングで導入。ちょうど発表されたところだった。
存在は知っていて、タイミングが来た時に導入したという印象。
エンジニアもデザイナーもマテリアルデザインについて話し合う文化?自然と話題にでて、導入に至ったそうです。主観ですがトレンドを追ったり、意識の高いメンバーがいると自然と導入する流れがあるのかな?と思いました。
エンジニアもデザイナーもマテリアルデザインについて話し合う文化?自然と話題にでて、導入に至ったそうです。主観ですがトレンドを追ったり、意識の高いメンバーがいると自然と導入する流れがあるのかな?と思いました。
マテリアルデザイン導入してどうなったか?
- 保守が圧倒的に楽になった
- 課金率が上がった
保守(改修)のタスクが楽になって、工数が削減できたと声が上がっていました。
ある程度要素が決まっているページに関しては、デザイナーがカンプを起こさないで、エンジニアだけで完結できるようになったそうです。
他にも、同じユーザー体験を提供できタブレットや様々な端末に対応できて課金率が上がったそうです。
マテリアルデザインによって、開発とユーザーにもメリットをもたらしてくれたという話が聞けました。
ある程度要素が決まっているページに関しては、デザイナーがカンプを起こさないで、エンジニアだけで完結できるようになったそうです。
他にも、同じユーザー体験を提供できタブレットや様々な端末に対応できて課金率が上がったそうです。
マテリアルデザインによって、開発とユーザーにもメリットをもたらしてくれたという話が聞けました。
まとめ
マテリアルデザインのメリットや守るべきルール、他にもテクニカルの部分もありましたが、今回のイベントを通じて、マテリアルデザインに関する知見が深まりました。信頼できる数値や導入してよかったメリットなども聞けたので、これを元にマテリアルデザインに挑戦(導入)してみては良いと思います。
こういったデザインの考え方やメリットなどは開発陣が積極的に声をあげて広めていくのが大事だと思いました。
こういったデザインの考え方やメリットなどは開発陣が積極的に声をあげて広めていくのが大事だと思いました。
ぼやき
iOSとAndroidを同じデザインでやるのは、短期的にはデザイナーのみの工数は削減できるが、中・長期的にみたときに、保守改修や機能追加などする際には、工数が膨れ上がってしまいます。
プラットフォームにあったデザインをキチン提供できるといいな。
プラットフォームにあったデザインをキチン提供できるといいな。
どこにいっても通用するデザイナーなれるように頑張ろう!!
2017年1月10日火曜日
はじめの一歩 -Rails ActiveRecord編- SELECT2
どうも、はじめです。
前回はActiveRecordのSELECTについて書いてみました。
はじめの一歩 -Rails ActiveRecord編- SELECT
今回も引き続きActiveRecordのデータの取得(SELECT)に関して書いていこうと思います。
はじめに、
前回と同様に以下のデータが登録済みであることを前提とします。
[id: 1, name: ‘名前1’, mail: ‘111@xxx.xxx’],
[id: 2, name: ‘名前2’, mail: ‘222@xxx.xxx’],
[Id: 3, name: ‘名前3’, mail: ‘333@xxx.xxx’]
前回記述したallやwhereを使用してデータの取得をした場合、
ActiveRecord::Relationというクラスのオブジェクトが返却されます。
取得したレコードが1件だけであったとしても使用する際は以下のように記述する必要があります。
user = User.where(id: 1)
p user[0][:name]
# => '名前1'
上記のように1件のみの取得と確定している場合でも[0]をつけなくてはなりません。今回は1件のみを取得する方法を書いていきたいと思います。
find
findはIDの直指定でレコードを取得することができます。
実行文と実行結果は以下のようになります。
user = User.find(2)
p user.mail
# => ‘222@xxx.xxx’
findでもし存在しないIDを指定した場合は例外が発生します。ちなみにIDの複数指定も可能です。
複数のIDを指定する際は以下のように配列で複数のIDを指定します。
user = User.find([2,3])
p user[0][:name]
# => '名前2'
p user[1][:name]
# => '名前3'
こちらは以下のようにwhereで取得した場合と同じ結果になります。user = User.where(id: [2,3])
find_by
findの場合はIDしか指定できませんでしたが、
他のカラムでの検索で1件のみ取得したい場合はfind_byを使用します。
user = User.find_by(name: '名前1', mail: ‘111@xxx.xxx’)
p user.id
# => 1
find_byでの検索はSQLの末尾に[limit 1]を追加して検索をしてくれるので、検索結果が複数あった場合でもヒットした中の一番最初のレコード1件のみを取得してくれます。
上記のように複数条件を指定することもできますが、すべてAND条件での検索となります。
find_byでIDを指定することもできますが、
findとの違いとしましては、検索結果が0件だった場合に例外ではなくnilを返します。
first
firstはを実行した場合は[order by `id` asc limit 1]が実行されます。
引数で数値を渡してlimitの数を指定することもできます。
user = User.first
user.id
# => 1
user = User.first(2)
user[1][:name]
# => '名前2'
最後に、
今後もしばらくデータの取得に関して書いていこうと思っております。
次回はjoin系を書いてみようと思っております。
carrierwave-awsを使ってS3に画像をアプロードする
こんにちは、h_ono_222です。
今回はcarrirewave-awsを使ってS3に画像をアップロードする方法を紹介します。
今回はcarrirewave-awsを使ってS3に画像をアップロードする方法を紹介します。
目次
- carrierwave-awsとは
- gemをインストールする
- initializerの設定
1. carrierwave-awsとは
carrierwave-awsはfogに似たgemで、Amazon S3へのアップロード機能を提供します。
carrierwaveでS3などのストレージ画像をアップロードするにはfogがよく使われると思いますが、
AWSへのアクセスをaws-sdkに統一するために、今回carrierwave-awsを利用しました。
GitHubのリポジトリはこちら
carrierwaveでS3などのストレージ画像をアップロードするにはfogがよく使われると思いますが、
AWSへのアクセスをaws-sdkに統一するために、今回carrierwave-awsを利用しました。
GitHubのリポジトリはこちら
2. gemをインストールする
下記のgemをインストールします。
# Gemfile
gem 'carrierwave'
gem 'carrierwave-aws'
3. initializerの設定
carrierwaveの設定を行います。()
# Gemfile
CarrierWave.configure do |config|
if Rails.env.production?
config.storage = :aws
config.aws_bucket = 'data.hoge.upload'
config.aws_acl = 'public-read'
# The maximum period for authenticated_urls is only 7 days.
config.aws_authenticated_url_expiration = 60 * 60 * 24 * 7
# Set custom options such agit s cache control to leverage browser caching
config.aws_attributes = {
expires: 1.week.from_now.httpdate,
cache_control: 'max-age=604800'
}
# aws credential
config.aws_credentials = {
# 今回はIAM ロールを使用するため記載しない
# access_key_id: ENV.fetch('AWS_ACCESS_KEY_ID'),
# secret_access_key: ENV.fetch('AWS_SECRET_ACCESS_KEY'),
region: 'ap-northeast-1' # Required
}
else
# テスト時はローカルにファイルを保存する
config.storage = :file
end
end
設定は以上です。
アップローダの方で特に意識することなく、S3へファイルをアップロードできました。
アップローダの方で特に意識することなく、S3へファイルをアップロードできました。
2017年1月9日月曜日
同じレコードがないときだけインサートする!
あるアイテムを持っていない人だけ、別のアイテムをあげたい!
もしくはその逆で、あるアイテムを持っている人に追加でアイテムをあげたい!
そういうことってないでしょうか?
先日、僕がそのような状況になり、四苦八苦しておりました。
本日は復習をかねて、調べた内容を記述していきたいと思います。
本日は主に下記の基本的なところを書きたいと思います。
まずはテスト用のテーブル、レコードを作成しておきます。
実はMySQLのリファレンスを読んだのですが、いまいちピンとこなかったので、実際に似たテーブルを作成して試してみました。
具体的には下記の組み合わせです。
まずは、EXIST句、NOT EXISTS句です。
リファレンスはこちらになります。
これは、その条件のものが存在していればTRUEを、存在していなければFALSEを返し、TRUEのものだけ取得してくれます。
(NOT EXIST句は逆です。)
下記に例を示しますが、storesの中で街にないものは「スーパー」だけです。
次に、INSERT ... SELECT...構文です。
リファレンスはこちらになります。
これは、SELECTで引っ張ってきた値を使用してINSERT文を作成します。
具体的には下記です。
良い例が思いつかなかったため、storesから全件取得し、それをcitiesに突っ込みます。
ここから本題になります。
想定としては、ある街に全ての店が進出してきた!ということにします。(意味が分かりませんが笑)
当然、既に存在している店もあるので、その店はインサートしないようにしたいです。
NOT EXISTS句とINSERT ... SELECT ...構文を併用して下記のように書きます。
(例として、渋谷にセブンイレブンとファミリーマートがきたということにします。セブンは既に存在しています。)
SELECT Syntax
私自身は特に省略しても違和感はありませんが、Oracle データベースなどを扱っていた方々は 記述するのが当たり前のようです。
とりあえずSQL文はできましたが、これだとレコード数が少ない場合は良いのですが、
レコード数が多くなると面倒なので、ストアドプロシージャを使用してループ文を作りたいと思います。
ストアドプロシージャは機会があればいろいろ試して、ブログにしたいと思いますが、 ←よく分かっていないだけ
参考資料を下記に載せておきます。
CREATE PROCEDURE and CREATE FUNCTION Syntax
はじめてのMySQL ストアドプロシージャ・ストアドファンクション
余談ですが、登録したRegisterAllStoresWithCityをリセットするには下記コマンドになるそうです。
もしくはその逆で、あるアイテムを持っている人に追加でアイテムをあげたい!
そういうことってないでしょうか?
先日、僕がそのような状況になり、四苦八苦しておりました。
本日は復習をかねて、調べた内容を記述していきたいと思います。
内容
本日は主に下記の基本的なところを書きたいと思います。
- EXISTS / NOT EXISTS
- INSERT ... SELECT...
- 上記2つを合わせて
準備
まずはテスト用のテーブル、レコードを作成しておきます。
実はMySQLのリファレンスを読んだのですが、いまいちピンとこなかったので、実際に似たテーブルを作成して試してみました。
CREATE TABLE cities(id int(11) NOT NULL AUTO_INCREMENT, name varchar(32) NOT NULL DEFAULT '0', PRIMARY KEY (id)) DEFAULT CHARSET=utf8;
CREATE TABLE stores(id int(11) NOT NULL AUTO_INCREMENT, name varchar(32) NOT NULL DEFAULT '0', PRIMARY KEY (id)) DEFAULT CHARSET=utf8;
CREATE TABLE cities_stores(id int(11) NOT NULL AUTO_INCREMENT, city_id int(11) NOT NULL DEFAULT 0, store_id int(11) NOT NULL DEFAULT 0, PRIMARY KEY (id)) DEFAULT CHARSET=utf8;
INSERT INTO cities (id, name) VALUES (1, '渋谷'),(2, '新宿'),(3, '池袋');
INSERT INTO stores (id, name) VALUES (1, 'セブンイレブン'),(2, 'ファミリーマート'),(3, 'ローソン'),(4, 'ミニストップ'),(5, 'サークルK'), (6, 'スーパー');
INSERT INTO cities_stores (city_id, store_id) VALUES (1, 1), (1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 1), (3, 3), (3, 5);
cities(街)、stores(店)、cities_stores(街と店の紐付け)を作成し、それぞれの街にいくつかの店があるとします。具体的には下記の組み合わせです。
渋谷 | セブン、ファミマ、ローソン |
---|---|
新宿 | ローソン、ミニストップ、サークルK |
池袋 | セブン、ローソン、サークルK |
どこにもない | スーパー |
EXISTS / NOT EXISTS
まずは、EXIST句、NOT EXISTS句です。
リファレンスはこちらになります。
これは、その条件のものが存在していればTRUEを、存在していなければFALSEを返し、TRUEのものだけ取得してくれます。
(NOT EXIST句は逆です。)
下記に例を示しますが、storesの中で街にないものは「スーパー」だけです。
# 1. cities_storesに存在する場合
SELECT DISTINCT name FROM stores
WHERE EXISTS (SELECT * FROM cities_stores WHERE cities_stores.store_id = stores.id);
セブン、ファミマ、ローソン、ミニストップ、サークルK |
# 2. cities_storesに存在しない場合
SELECT DISTINCT name FROM stores
WHERE NOT EXISTS (SELECT * FROM cities_stores WHERE cities_stores.store_id = stores.id);
スーパー |
INSERT ... SELECT...
次に、INSERT ... SELECT...構文です。
リファレンスはこちらになります。
これは、SELECTで引っ張ってきた値を使用してINSERT文を作成します。
具体的には下記です。
良い例が思いつかなかったため、storesから全件取得し、それをcitiesに突っ込みます。
INSERT INTO cities (name) SELECT stores.name FROM stores;
ご想像の通り、これでまるっとcitiesのレコードが増えます。SELECT * FROM cities;
id | name |
---|---|
1 | 渋谷 |
2 | 新宿 |
3 | 池袋 |
4 | セブンイレブン |
5 | ファミリーマート |
6 | ローソン |
7 | ミニストップ |
8 | サークルK |
9 | スーパー |
同じレコードがないときだけインサートする!
ここから本題になります。
想定としては、ある街に全ての店が進出してきた!ということにします。(意味が分かりませんが笑)
当然、既に存在している店もあるので、その店はインサートしないようにしたいです。
NOT EXISTS句とINSERT ... SELECT ...構文を併用して下記のように書きます。
(例として、渋谷にセブンイレブンとファミリーマートがきたということにします。セブンは既に存在しています。)
# セブンの場合、もう渋谷にあるのでインサートされない
INSERT INTO cities_stores (city_id, store_id)
SELECT target_city_id, target_store_id FROM dual
WHERE NOT EXISTS(SELECT * FROM cities_stores WHERE city_id = 1 AND store_id = 1);
# ファミマの場合、まだ渋谷にないのでインサートされる
INSERT INTO cities_stores (city_id, store_id)
SELECT target_city_id, target_store_id FROM dual
WHERE NOT EXISTS(SELECT * FROM cities_stores WHERE city_id = 1 AND store_id = 2);
dualはテーブルを参照する必要のない場合に使用するダミーテーブルで、WHERE句を指定したい場合などに入れる必要があるそうです。SELECT Syntax
私自身は特に省略しても違和感はありませんが、Oracle データベースなどを扱っていた方々は 記述するのが当たり前のようです。
とりあえずSQL文はできましたが、これだとレコード数が少ない場合は良いのですが、
レコード数が多くなると面倒なので、ストアドプロシージャを使用してループ文を作りたいと思います。
ストアドプロシージャは機会があればいろいろ試して、ブログにしたいと思いますが、 ←よく分かっていないだけ
参考資料を下記に載せておきます。
CREATE PROCEDURE and CREATE FUNCTION Syntax
はじめてのMySQL ストアドプロシージャ・ストアドファンクション
DELIMITER //
CREATE PROCEDURE RegisterAllStoresWithCity(IN target_city_id INT)
BEGIN
DECLARE target_store_id INT;
DECLARE max_id_stores INT;
SET target_store_id = 1;
SET max_id_stores = (SELECT MAX(id) FROM stores);
WHILE target_store_id <= max_id_stores DO
INSERT INTO cities_stores (city_id, store_id)
SELECT target_city_id, target_store_id FROM dual
WHERE NOT EXISTS(SELECT * FROM cities_stores WHERE city_id = target_city_id AND store_id = target_store_id);
SET target_store_id = target_store_id + 1;
end WHILE;
END
//
DELIMITER ;
これでRegisterAllStoresWithCity()が登録されたので、下記で呼び出し、インサートしてみます。CALL RegisterAllStoresWithCity(1);
これで、渋谷に全ての店が出店できました!SELECT cs.id, c.name, s.name FROM cities_stores cs INNER JOIN cities c ON cs.city_id = c.id INNER JOIN stores s ON cs.store_id = s.id;
id | cities.name | stores.name |
---|---|---|
1 | 渋谷 | セブンイレブン |
2 | 渋谷 | ファミリーマート |
3 | 渋谷 | ローソン |
25 | 渋谷 | ミニストップ |
26 | 渋谷 | サークルK |
27 | 渋谷 | スーパー |
DROP PROCEDURE IF EXISTS RegisterAllStoresWithCity;
2017年1月7日土曜日
はじめの一歩 -Rails ActiveRecord編- SELECT
どうも、はじめです。
あけましておめでとうございます。
今年もよろしくお願いいたします。
さて前回はActiveRecordのINSERTについて書いてみました。
はじめの一歩 -Rails ActiveRecord編- INSERT
今回はActiveRecordのデータの更新(update)について書こうと思っていましたが、
先にデータの取得(select)について書いてみようと思います。
データの取得をしたい場合
モデルに登録されているすべてのデータを取得したい場合はallを、
検索をしたい場合はwhereを使用します。
Userモデルに以下でデータを登録したとします。
[id: 1, name: ‘名前1’, mail: ‘111@xxx.xxx’],
[id: 2, name: ‘名前2’, mail: ‘222@xxx.xxx’],
[Id: 3, name: ‘名前3’, mail: ‘333@xxx.xxx’]
all
User.all
# [Id: 1, name: ‘名前1’, mail: ‘111@xxx.xxx’],
# [Id: 2, name: ‘名前2’, mail: ‘222@xxx.xxx’],
# [Id: 3, name: ‘名前3’, mail: ‘333@xxx.xxx’]
where
User.where(id: 2)
# [Id: 2, name: ‘名前2’, mail: ‘222@xxx.xxx’]
allの場合は指定したモデルに登録されているデータをすべて取得することができます。whereの場合はwhere()内に「カラム名: 検索したい値」を指定することで、
指定した値で検索した結果を取得することができます。
複数条件で検索をしたい場合
複数の条件でデータの取得を行いたい場合はwhereにて条件を複数指定します。
Idが2と3のレコードを取得したい場合は以下のようにidに対し配列で条件を指定します。
User.where(id: [2, 3])
# [Id: 2, name: ‘名前2’, mail: ‘222@xxx.xxx’],
# [Id: 3, name: ‘名前3’, mail: ‘333@xxx.xxx’]
複数カラムを指定したい場合は以下のように指定します。
User.where(id: 2, name: ‘名前2’)
# [Id: 2, name: ‘名前2’, mail: ‘222@xxx.xxx’]
このように指定した場合はAND条件で検索されるので注意が必要です。最後に、
OR条件での検索や、AND条件でも他の記述方法があったりと
他にもデータの抽出には種類があるため、
次回も引き続きSELECT関連を書いていこうと思います。
2017年1月6日金曜日
iOS10のWKWebViewとUIWebViewでhttpでの通信を許容する方法
こんにちは、onukiです。
対応が必須になったATS(NSAppTransportSecurity)ですが
こちらの対応を行うとhttpでの通信は行えなくなります。
ただし、iOS10のWKWebViewとUIWebViewに限りInfo.plistにキーを追加するだけで
httpでの通信を許容してくれるので今回はそちらの紹介をします。
対応が必須になったATS(NSAppTransportSecurity)ですが
こちらの対応を行うとhttpでの通信は行えなくなります。
ただし、iOS10のWKWebViewとUIWebViewに限りInfo.plistにキーを追加するだけで
httpでの通信を許容してくれるので今回はそちらの紹介をします。
ATS(NSAppTransportSecurity)とは
Cocoa keys
簡単に言ってしまうとiOS9以上で以下の通信にhttpの通信が使えなくなります
- WKWebView
- UIWebView
- NSURLSession
- NSURLConnection
httpでの通信を許容するには
iOS10よりATSに関して新たなキー「NSAllowsArbitraryLoadsInWebContent」が追加されました。
このキーはWebViewを利用してウェブコンテンツを表示している場合、
その内容に関してはhttpでの通信を許容するというものです。
その内容に関してはhttpでの通信を許容するというものです。
設定方法
Info.plistの「App Transport Security Settings」に
「NSAllowsArbitraryLoadsInWebContent」を追加し値を「YES」にする
「NSAllowsArbitraryLoadsInWebContent」を追加し値を「YES」にする
注意
タイトルからiOS10としてきましたが、
「NSAllowsArbitraryLoadsInWebContent」は現状、iOS10のみ有効になります。
このキーを設定していてもiOS9ではWebViewでのhttp通信は弾かれてしまいます。
登録:
投稿 (Atom)