元ひよっこSEがフルスタックエンジニアを目指すブログ

大学院(情報系)修了後、新卒で大手SIer入社。のちに事業会社(WEB系)に転職。SIerから事業会社に転職してからの日常と学んだこととかを書いていこうかと思う。

【Python】【Deep Learning】Deep Learningの勉強をしてみる

今構築しているシステムで機械学習を使っているということもあって、同じチームの人からこんなのが公開されてるよ!と教えてもらったので、見てみる。
www.itmedia.co.jp

学生時代の研究テーマは機械学習を用いたものだったが、Deep Learningは触れたことがない。
東大の講義(?)で使われているものらしく、個人の学習であれば利用させていただけるそうだ。ありがたや。

Python環境のセットアップ

・anacondaのインストール

www.anaconda.com

#自分の場合は、Python 3.6 versionを入れた

■コンテンツを落としてくる

・下記からコンテンツをダウンロード
weblab.t.u-tokyo.ac.jp

7-zip形式なので、解凍する。

The Unarchiver

The Unarchiver

  • MacPaw Inc.
  • ユーティリティ
  • 無料


■実行
・解凍すると「weblab_dlb」フォルダがあるので、そのフォルダまで移動し下記コマンドを実行する。

jupyter notebook

講義資料が参照できたらOK。コードも▶︎|を押すことで実行できる。


 空いてる時間を使ってちょっとづつ勉強してみようと思う。

【Ruby】【Rubocop】Rubocopでコーディング規約をチェックする

 個人でコーディングしている時は特に意識することがなかったのだが、転職してコードを書く機会が増えてからはコーディング規約に気をくばる必要が出てきた。かといってまだコーディング規約を覚えられていないので、それを気にして書くのは疲れる。ということで、「rubocop」を使ってみる。

■インストール
まずは、インストールする

gem install rubocop

■コードチェック

テスト用に下記のプログラムを用意する。

# robocop.rb
#コメント
puts 'Rubocop使ってみた'

下記コマンドでコードをチェックできる。

$rubocop rubcop.rb

Inspecting 1 file
C

Offenses:

rubcop.rb:2:1: C: Layout/LeadingCommentSpace: Missing space after #.
#コメント
^^^^^
rubcop.rb:2:2: C: Style/AsciiComments: Use only ascii symbols in comments.
#コメント
 ^^^^

自動修正できるものは下記コマンドのようにオプションをつけることで自動修正される。

$ rubocop --auto-correct rubcop.rb
Inspecting 1 file
C

Offenses:

rubcop.rb:2:1: C: [Corrected] Layout/LeadingCommentSpace: Missing space after #.
#コメント
^^^^^
rubcop.rb:2:3: C: Style/AsciiComments: Use only ascii symbols in comments.
# コメント
  ^^^^

1 file inspected, 2 offenses detected, 1 offense corrected

「Style/AsciiComments」は英語でコメントが記載されているかどうかをチェックした結果だが、さすがに日本語でもコメントを書きたいって時には「.rubocop.yml」に下記を記載し、プロジェクトのルートディレクトリに配置する。

Style/AsciiComments:
  Enabled: false

これでStyle/AsciiCommentsはチェックされなくなる。その他の項目も設定値を変更したり、無効にしたりできる。

 ほとんど自動修正されてしまうが、修正された箇所がわかるので、コーディング規約も自然と覚えていけそうな気がする。

【Ruby】抽象クラスを作る

もともとAndroidのアプリを作っていたということもあってJavaを長くやっていたのですが、最近はrubyがメイン。
で抽象クラス作ろうと思ったら、rubyにはそんなものはなかった。

親クラスのメソッドで例外を投げることで、擬似的なことはできるらしい。

class Human
 def eat
  raise 'メソッドオーバライドして'
 end
end

class Taro < Human
def eat
  puts '食べる'
 end
end

class Jiro < Human
end

Taro.new.eat
Jiro.new.eat

eatメソッドで例外を投げるようにした。
Taroはeatメソッドをオーバライドしているが、Jiroはしてない。
その状態でeatを呼び出す。

食べる
a.rb:3:in `eat': メソッドオーバライドして (RuntimeError)
	from a.rb:17:in `<main>'

ほほーん。
しかし、Javaだとコンパイルの段階かEclipseがメソッド実装してないぞ的なことをエラーとして吐いてくれてた気がするのだけど、
これって呼ばれないと気がつかないんじゃない?
抽象メソッドの実装を強制するという意味ではどうなんだろうか・・・

【Ruby】標準出力でかっこよく進捗を表示する

 すごい長い時間処理をするプログラムを作っていたのですが、どこまで処理をできたかのフィードバックが欲しいと思い調べてみました。
標準出力で処理回数を表示してたのですがいかんせんイケてなかったので、イケてる表示方法を調べてみました。

普通に表示する

普通に進捗を表示してみる。

max = 10000
(1..max).each{|num|
  puts "#{num}/#{max} Progress rate: #{num*100/max}%"
}

下記のように残念な感じになる。

1/10000 Progress rate: 0%
2/10000 Progress rate: 0%
3/10000 Progress rate: 0%
4/10000 Progress rate: 0%
5/10000 Progress rate: 0%
6/10000 Progress rate: 0%
7/10000 Progress rate: 0%
8/10000 Progress rate: 0%
9/10000 Progress rate: 0%
10/10000 Progress rate: 0%
・
・
・
9990/10000 Progress rate: 99%
9991/10000 Progress rate: 99%
9992/10000 Progress rate: 99%
9993/10000 Progress rate: 99%
9994/10000 Progress rate: 99%
9995/10000 Progress rate: 99%
9996/10000 Progress rate: 99%
9997/10000 Progress rate: 99%
9998/10000 Progress rate: 99%
9999/10000 Progress rate: 99%
10000/10000 Progress rate: 100%

キャリッジリターン(\r)を使う

先頭に"\r"を付けると、標準出力が上書きされる。

max = 10000
(1..max).each{|num|
  print "\r#{num}/#{max} Progress rate: #{num*100/max}%"
 sleep(0.01)
}

下記のように進捗が1行で表示される。かっこいー。

3516/10000 Progress rate: 35%

【Ruby】RubyMineを日本語化する

RubyMineを使ってるんですが、日本語化したいなぁと思いちょっと調べて日本語化しました。

参考


IntelliJ や PhpStorm などの日本語化

上記の通りにやればいけました。

手順

Eclipse 日本語化 | MergeDoc Project (Pleiades プラグイン・ダウンロード)を落としてくる。

pleiades-mac.zipを解凍する。

③「pleiades-mac/plugins」配下のjp.sourceforge.mergedoc.pleiadesを「/Applications/RubyMine.app/Contents/plugins/」にコピー

④「/Users/ユーザ名/Library/Preferences/RubyMine2017.2/rubymine.vmoptions」に下記を追記する。

-javaagent:/Applications/RubyMine.app/Contents/plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar

⑤RubyMineを再起動する。

Android StudioとかEclipseの日本語化と同じやり方な気がするんだけど、どういう仕組みなんだろ。と思ったら、書いてた。

これは AOP (横断的関心事を解決するテクノロジー)で実行時にJavaクラスローダーをフックし、クラスをバイトコードレベルで動的に書き換えて対象のJavaアプリケーションを日本語化するもので、10年以上利用され、今も随時更新されています。
 
うんうん。まったくイメージが湧かないので、ちょっと時間ある時に勉強しようかな。
 

JetBrainsの製品はDataGripも使ってるんですが、こんな簡単にデータベース触れるんだなぁ。。。SIerにいた頃もSQL叩く機会は多かったんですが、spoolしてExcelに貼ってとかやってたなぁ。。。

個人で開発したAndroidアプリはどれくらいダウンロードされる(た)のか?

個人でのアプリ開発を始めた経緯など

 ちょうど大学在学中がiPhoneが登場し、皆が利用する端末がガラケーからスマートフォンに変化していくタイミングでした。当時、研究室に配属されたタイミングでもあったのですが、自分が大学で学んだ内容が世の中にどのような価値を提供できるのかイマイチわからず、プロダクトを公開することにしました。その際に作るプロダクトとして選んだのがAndroidのアプリでした。

 開発を始めたタイミングではAndroid 2.2の端末が市場に出回っていた時期でした。当時のAndroidはかなりもっさりしていました。当時は、IS03*1とかで開発をしていました。

 就職してからは、会社の規則で副業が禁止だったことやそもそも新規にプロダクトを外部に公開すること自体を会社に禁止されたことで新しいアプリの作成はできませんでした。学生時代に作ったアプリの更新をシコシコやっていたという感じです。

個人で開発したアプリのダウンロード数

作成したアプリのダウンロード数(2017年10月時点)は下記の通りです。

アプリ種類 ダウンロード数
ツール1 180万
ツール2 45万
ツール3 15万
ツール4 3万
ゲーム 4500

ダウンロードしてもらうために意識したこと・学んだこと

 リリースの順番に関しては、ダウンロード数の増加(表的には下から上)と同じです。作るたびに自分なりに問題点を考察し、改善していった感じです。その結果、リリースの度にどんどんダウンロード数が伸びていきました。   いろいろやってるうちにアプリのダウンロード数を伸ばすには、下記の観点が非常に重要であることに気がつきました。

①どうやってアプリをダウンロードしてもらうか?
 これは言われてみると、極めて当たり前なのですがアプリを作り始めた当初は全く考慮できていませんでした。具体的には、SEOだったり、アプリの紹介サイトで記事を書いてもらったり。どんなに良いモノを作ってもここが疎かになると、誰にも使ってもらえないです。ダウンロードされるチャネルを意識することで、ダウンロード数はぐんぐん伸びていきました。

②競合が多いか?少ないか?
 アプリの世界でも先行者利益というのは確実にあります。自分がアプリ開発を始めた時は、Androidユーザがどんどん増えていっているタイミングでした。それ故に、Google Playにアプリがそれほど存在しませんでした。これがかなり大きかったと思っています。特に、最初にリリースしたゲームのアプリは典型的な悪い例でした。まず、プロトを研究室のメンバに遊んでもらい面白いという評価を得てからリリースしたわけですが、ゲームはすでにレッドオーシャンでした。ユーザの目に止まらない。。。その結果、惨敗したわけです。。。

③それ本当に必要?
 どうしても技術ベースのボトムアップでモノづくりを始めると、「こんなことできるじゃん」という視点で開発をしてしまいガチです。これではダメでした。「ユーザが必要なものって何だろう?」という視点からスタートしないと開発者の自己満アプリで終了してしまいます。ユーザは必要のないアプリを検索もしないし、ダウンロードもしません。

  

 元々コーディングの知識があったということもありますが、アプリ開発で重要だと思ったことの中に技術的なことは一切ありません。アプリ開発をすることで「技術的にすごい物」と「多くの人に使われる物」が必ずしもイコールではないということを強く実感させられました。 まずは、本当にニーズがあるものか?競合は?といった視点から作る物を考える。実際にアプリを作ったら、ダウンロードしてもらうためのチャネルを用意する。これが抜けるとまるっきりダメでした。 時々、ストップウォッチやBMIのアプリを作ってアプリがかなりダウンロードをされた人を馬鹿にする人がいます。自分もどっちかというと、「そんなん俺でも作れるわ」とか思ってた感じだったのですが、アプリ開発を始めて考えが変わりました。競合がいないタイミングでニーズのあるものを作り公開できる行動力と洞察力が凄いのだと。

 こういった経験からプロダクト志向のエンジニアにはビジネスの視点は非常に重要と思っているのですが、現職のSIerの中だとこういった感覚を磨く業務があまりないのが残念なところです。

収入

上述の通り、現職で副業を禁止されているため現在は収入なしです。学生時代は月10万以上は広告収入がありました。おかげでバイトを辞めることができたので、学業にはだいぶ集中できました。親の扶養から外れて確定申告とかも結構面倒くさかったですが。

やりがい的な

 大学だとどうしてもインプットが中心になってしまうので、アウトプットの経験として現役の大学生とかにはおススメですね。しかも、ヒットすればバイトもしなくてもお金が入ってきます。案外アプリ作ってお金稼いでますって人はいないので、就活でも無双できます。よく考えるとすごいよこれ。メリットしかない。
 あとは、感謝のメールがいっぱい来ること。日本人もですが、外人が英語で「君のアプリで私のベイビーの最高のスマイルを撮影することができたぜ!サンキュー!!」とか、インドの人から「धन्यवाद」とかメールが来るわけです。自分のプロダクトで世界の誰かの役に立っているのは嬉しいですよね。大なり小なり世の中変えてやろうとか便利にしてやろうと思ってエンジニア(※)になったわけですから。

※仕事じゃなくて、趣味でやってるけど('ω')ノ

【Java】HashSetはぇぇぇーーーーってなった

競技プログラミング始めました

 

 仕事でコード書く機会があまりにないので、ストレスが溜まってきた。ということで、AtCoderあたりやろうかなーと。また、スマホのアプリでも作りたいんですが、時間がかかるのとリハビリもかねてまずはコード書くことから始めました。

AtCoder Beginner Contest 073

 過去問とかやってみてもCまでは何一つ悩むことなく、解ける感じでした。

しかし、今回Cでつまってしまった。はずかしー。言語はとりあえずJava

 

abc073.contest.atcoder.jp

 

こんな感じ。 

・A September 9 ふっ ちょろいぜ。OK!

・B Theater ふっ ちょろいぜ。OK!

・C Write and Erase ふっ ちょろいぜ。あれ、おわんないぞ・・・

           TLE!ん?実行時間制限超過?

 

いやー実行時間なんて気にして実装したことなんてないわー。

とりあえず、下記で書いた。

 

 

import java.util.ArrayList;
import java.util.Scanner;
 
 
public class Main 
{
 
	public static void main(String[] args) 
	{
		Scanner sc = new Scanner(System.in);
		int N = sc.nextInt();
 
		ArrayList A = new ArrayList();
		
		for(int i=0;i<N;i++)
		{
			int a_i=sc.nextInt();
			boolean find = false;
			for(int j=0;j<A.size();j++)
			{
				if(a_i==A.get(j))
				{
					find=true;
					A.remove(j);
					break;
				}
			}
			
			if(!find)
			{
				A.add(a_i);
			}
		}
		sc.close();
		
		System.out.println(A.size());
	}
 
}

 

 

上記は、TLE(実行時間制限超過)。
これあれかーーー。二重ループの中が重いやつかー。二分探索にしよ。でWiki見て理解して載ってたC言語Javaに書き換えて作ったのが下記。

 

 

 

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
 
 
public class Main 
{
 
	public static void main(String[] args) 
	{
		Scanner sc = new Scanner(System.in);
		int N = sc.nextInt();
 
		LinkedList A = new LinkedList();
		
		for(int i=0;i<N;i++)
		{
			int a_i=sc.nextInt();			
			int index= binary_search(A,a_i,0,A.size()-1);			
			if(index==-1)
			{
				A.add(a_i);
				Collections.sort(A);
			}
			else
			{
				A.remove(index);
			}
		}
		sc.close();
		
		System.out.println(A.size());
	}
	
	final static int KEY_NOT_FOUND =-1;
	
	static int binary_search(List list, int key, int imin, int imax) 
	{
	    if (imax < imin) 
	    {
	        return KEY_NOT_FOUND;
	    }
	    else
	    {
	        int imid = imin + (imax - imin) / 2;
	        if (list.get(imid) > key)
	        {
	            return binary_search(list, key, imin, imid - 1);
	        }
	        else if (list.get(imid) < key)
	        {
	            return binary_search(list, key, imid + 1, imax);
	        }
	        else
	        {
	            return imid;
	        }
	    }
	}
}

 

びっくりするくらい何も変わらない。final付けたり、 ArrayListをLinkedListに変えたりもじもじしたんだけど、ちょっとしか早くならない。もじもじしてたら、終わってしまった。Javaで解けてる人の解答みるとHashSet*1を使ってる。でHashSet使って作り直したのが、下記。

 

import java.util.HashSet;
import java.util.Scanner;
 
 
public class Main 
{
 
	public static void main(String[] args) 
	{
		Scanner sc = new Scanner(System.in);
		int N = sc.nextInt();
		
		HashSet A = new HashSet();
 
		for(int i=0;i<N;i++)
		{
			int a_i=sc.nextInt();					
			if(!A.contains(a_i))
			{
				A.add(a_i);
			}
			else
			{
				A.remove(a_i);
			}
		}
		sc.close();
		
		System.out.println(A.size());

	}
}

ハッシュはぇぇぇーーー!!ACになった!!間に合わなかったけどwww

なんでもかんでもListにぶち込むのはよくないと。趣味でやってるとこういうところの感度が磨かれない気がする。重複した値を格納できないので、使い道が限定されるような気もするけど、勉強になった。

 

余談

というか、Java競技プログラミングってどうなんでしょうね。

遅くて不利な気もするけど。

 

あと、5分で全部解いてる人とかどういうことwww

自前である程度定型的な部分のコードを用意しているとしても早すぎるwww

おそるべし競技プログラミングの世界