Machine Learning Lecture 2 - 機械学習

Machine Learning Lecture in Stanford Universityの第二回をもとに学習していきます。

今回のトピックは

  • linear regression
  • gradient descent

です。

supervised learning vol.2

前回ではsupervised learningで家屋の価格の予測について触れていました。まずはじめに実際の正確な価格を教えることで、家屋の広さと価格の関係について学習するようにし、正しい価格を予想するようにしました。

supervised learningでは他にも無人の自動車の例が面白いものして紹介されています。Machine Learning Lecture in Stanford Universityでは実際に自動車が学習する様子がムービーで見れます。

ちなみに自動車は次のような手順で無人で走れるように学習します。

  1. 実際に人が運転し、どの程度ハンドルをきるかを教える
  2. 正しい操縦の具合を学習する。
  3. 無人で運転できる。

3番の段階になっても学習は繰り返されそうですね。動画は少し古いものですが、人間の操縦を正しいものとして学習し正しい操縦をできるようになるという非常にわかりやすいsupervised learningの例であり、特にregression problemの例として紹介されていました。現在では"DARPA Grand Challenge"という無人自動車が砂漠を横断するのを競ってたりもするのですから、驚きです。

家屋の例に戻ってみます。講義の中のデータとして

Living area(feet^2)$(1000)
2104 400
1416 232
1534 315
852 178
1940 240

家のサイズと価格の関係をどのように予測するかというのが問題です。まずはじめに、これから頻繁に使用する記号の定義を上げておきます。

定義

  • m = #training examples(訓練集合)
  • x = "input" variables/features(入力変数)
  • y = "output" variable/"target" variable(目標変数)
  • (x,y) - training example
  • i'th training example = (x^i,y^i)

これをもとにしていきます。

次にsupervised learningで行っていく処理の流れをイメージで示します。

training set(訓練集合)からlearning algorithmを通してhypothesisを生み出します。このhypothesisに入力変数を入力すると、目標変数を出力します。家の売却のケースで言えば、new living area を入力することでestimated priceが出力されます。

hypothesisをどのように表現するかをあらかじめ決めます。

と表します。xはここでは入力変数であり、家のサイズのことです。回帰の問題に関して言えば1つ以上の要素をもつことが一般的によくあります。なので、家の売却に関しても入力変数をひとつ追加して、hの式を一般化したいと思います。

Living area(feet^2)#bedrooms$(1000)
2104 3 400
1416 2 232
1534 3 315
852 2 178
1940 4 240

サイズの他に、寝室の数のデータを得ました。式も更新します。x_1=size,x_2=#bedrooms

x_0=1と定義すると

となります。n=要素の数です。ここではsizeと#bedroomsの2つです。

どうやって最適なθを求めるためのかが重要になります。そもそもh(x)は家の価格を予測するためのものでした。なので、xを任意の値で固定したものと実際の値の誤差の最小化をするようなθを求めます。二重和誤差を用いて、最小化できるようなθをもとめます。

J(θ)について考えます。

Gradient Descent 最急降下法

J(θ)を最小化するためにGradient descentを見てみます。日本語では最急降下法と呼ばれています。

最急降下法の理解のためにMachine Learning Lecture in Stanford Universityで使われたイメージをキャプチャしておかりしています。

Gradient descentアルゴリズムでは初めの地点によって得られる結果は変わってきます。このイメージが立体的な陸地であることを想定して下さい。丘のようなものだと思えば良いと思います。そして自分が矢印で囲まれた地点にいると想像してみてください。最急降下法とはその地点から全体を見渡して、最も少ない工程で丘を下ることができるのはどの方向であるかを考えるようなものです。一回次の地点に移ったら、また同様に最小になる方向を探します。それを何回も繰り返していきます。最小のものを探すのはちょうどJ(θ)の最小を探すのと同じです。

最急降下法はスタート地点が異なると最終的な到着地点も異なります。図では左下のコーナーの部分が終点ですが、違う点からだと別の場所につきます。スタート地点によって、終点は全く異なる局所最適点となるのです。ある適当な初期値から初めて、繰り返し更新していくことで最適なパラメータを求めるのが最急降下法です。最急降下法でのパラメータの更新は次のように表せます。

αはleraning rateといい日本語では学習係数と呼びます。これは一回の繰り返しでどれくらいパラメータを更新するかに影響を与えます。まずはtraining exampleが1つである場合について考えます。そして右辺の偏微分の部分について詳しく見ていきます。

これを先ほどの式に代入します。

αは学習係数と言いましたが、これは最急降下法で言えばどれほど大きなステップをとるかに影響すると言えます。あまり大きくすると発散してしまいますが、小さすぎると最適なパラメータを求めるための更新回数が多くなります。

ここまでtraning exampleが1つの場合のみ考えてきました。traning exmapleがm個ある場合についても見ていきます。

∑の部分を置き換えると、

となります。

収束するまで更新することによって、J(θ)を最小化するようなパラメータθを求めます。家屋の売却の例も最適なパラメータを探すことが重要になります。

Batch Gradient Descent と Stochastic Gradient Descent

これまで詳しく言うとこれはbatch gradient descentというものです。batch gradient descentではひとつのステップに対してすべてのtraining exampleを見ていました。これではtraining exampleの数が膨大になると、すべき処理も膨大なものとなります。

一方で、stochastic gradient descentはそれぞれのステップで各training examleを検証するだけです。そのためstochastic gradient descentはbatch gradient descentよりも最小となるようなθを見つけるのが速いことが多いです。このような理由からtraining exampleの数が多い時は、stochastic gradient descentが好まれます。

Machine Learning Lecture 1

スタンフォード大学のAnrew ng氏のmachine learning lectureを見て、機械学習について学習しています。今回はlecture1をもとに学習したことを書きます。

Machine Learning Lecture in Stanford University:https://itunes.apple.com/jp/itunes-u/machine-learning/id384233048

第一回に関していえば、事務連絡が若干入っていたりします(それがリアルな教室っぽく感じられます)。

Introduction of Machine Learning

機械学習は学問横断的であり、生物学、ロボット、自然言語処理など様々な分野に対して適用できる非常に強力な技術です。『Computer world』には"12 IT skills that employers can't say no to"という記事があがっており、その中でも機会学習は注目を浴びています。

it's about sort of the 12 most desirable skills in all of IT and all of information technology, and topping the list was actually machine learning.

と言われるほどに機会学習は重要視されています。機会学習は人工知能の初期の段階から成長してきました。20年程まえから機会学習は、コンピュータのための新たな処理能力の一種と捉えられてきました。特に人の手で書くことが困難であったり不可能なプログラムやアプリケーションに適用することができると考えられました。

例えば、曲線的な手書き文字を読み取ったり、ヘリコプターを飛行するプログラムを書くことは困難です。こういった課題に対して学習のアルゴリズムを適用すると非常に強力な効果を発揮します。

機械学習データマイニングにも適用することができ、強力な効果を発揮します。例えば、ITの発展により多くの病院が患者の種類、どんな問題を抱えているか、診断の予測、そして実際の結果はについて医学的な記録を蓄積しています。そして長年にわたってデータとして保存された記録に学習のアルゴリズムを適用することで、素の医学的記録を医学的知識という価値をもつものにし、診察の段階で医学的傾向を検出することも可能になります。

このように多岐にわたる分野で応用可能な機械学習ですが、僕らの生活にも浸透していたりします。クレジットカードの不正利用を検知に利用できますし、Amazonの"おすすめ機能"のようになじみのあるものもありますね。つまり気付くにしろ気づかないにしろ、僕達は何度も機械学習の恩恵にあずかっているわけです。機械学習について、もうちょっと深く見ていきます。

What is Machine Learning

Field of study that gives computers the ability to learn without being explicitly programmed.  Arthur Samuel(1959)

これは人工知能で有名な学者であるアーサー・サミュエルが機会学習を定義したものです。和訳すると明示的にプログラムすることなく、コンピュータに学習し行動させる科学の分野であるといったところでしょう。

アーサー・サミュエルはチェッカーというチェスボードを用いたゲームをプレイするプログラムを書き、数千ものゲームを行わせることで勝ちに結びつくパターンや負けのパターンを認識させたそうです。そして驚くべきことにそのプログラムはアーサー自身がプレイするよりもうまくチェッカーをプレイできるようになったのです。本人よりも強くなるというのは正しく学習しているといえますね。

そんな風にして機会学習というものがはじまっていったのです。こういう話って興奮しますよね。

ちなみにチェッカーはこんな感じ。

詳細なルールが気になる方はwikipedia: チェッカーを参照してみてください。

もう少し形式的な定義もあります。

Well-posed Learning Problem: A computer program is said to learn from experience E with respect to some task T and some performance measure P, if its performance on T, as measured by P, improves with experiece E. Tom Mitchell(1998)

なんとなくリズムの良い定義です。あるタスクTを行いパフォーマンスを測定し、それを経験Eとして、そこから学習します。その経験Eからの学習によりパフォーマンスを向上させていきます。

Supervised Learning

supervised learningは機械学習のいち区分であり、日本語では"教師つき学習"などと呼ばれています。(和訳すると微妙にダサい感じがします。)アルゴリズムにあらかじめデータ・セットを与えておきそれをもとに学習していくのでsupervised learningと呼ばれています。

例えば、家屋を売却したい場合にいくらで売却すべきか知りたいとします。supervised learningでは基本的な前提条件が同じ(この場合では地区とかが同じ)で、家屋の広さによって価格がかわるような場合を想定します。あらかじめ家屋の広さと正確な価格のデータセットをいくつも与えておきます。そして、売りたい家屋の広さを入力すると予想価格を出力するというアルゴリズムです。

家屋の広さと正確な価格のデータセットを与えておき広さと価格の関係をアルゴリズムに学習させようとしていることからも、supervised learning/教師つき学習と呼ばれ理由がわかります。

Unsupervised Learning

unsupervised learningは"教師なし学習"という和訳があります。これは教師つき学習とは対照的に、データを与えるけれど、正しい値は与えません。先ほどの家屋の例でいえば価格を与えません。アルゴリズムが行うことは、与えられたデータ・セットの特徴から何らかの構造を見出し、クラスタに分類することです。

Machine Learning Lecture in Stanford Universityでは画像から3Dのモデルを作成したりunsupervised lerningを遺伝子のデータに適用した例などが紹介されています。

Reinforcement Learning

最後にreinforcement learningです。日本語では"強化学習"と呼ばれています。強化学習は連続したやりとりのなかで試行錯誤を通じて、学習させるものです。Machine Learning Lecture in Stanford Universityではヘリコプターを例に説明しています。ヘリコプターを自動で飛ぶようにプログラムするのは人には難しいので強化学習を適用します。ヘリコプターが墜落してしまうパターンと、うまく飛行できるパターンを教えこむことが必要です。

So every time your dog does something good, you say, "Good dog," and you reward the dog. Every time your dog does something bad, you go, "Bad dog,"

飼い犬をしつけるときにたとえているようです。強化学習では何が良い状態なのかを明確にしていないといけません。自分が求めている動作が明確にならないと、何を基準に連続した取り組みをしていけばいいのかがわからなくなってしまいます。

 

最後の方は、講義で出た例をあまり紹介していませんがこれらは映像と一緒にみた方が理解しやすいと思います。 次回はlecture2を書いていきます。lecture2から数式がけっこう出てきます。

RとRubyでデータ解析

Rの勉強に新鮮さを求めてRubyも混ぜました。RとRubyによるデータ解析入門を参考にしています。この本とにかく楽しいので、気分転換とかにいいと思います。一個一個のテーマが面白いのと、どういう意図でプログラムを書いたのか説明がしっかりとしているので、はまらないと思います。学習した内容だと本の内容になってしまうので、どんな感じかをざっくりと書きます。

RとRubyによるデータ解析入門

RとRubyによるデータ解析入門

 

オフィスとトイレの関係

オフィスとトイレの関係について解析してみたもの。イギリスのとあるオフィスで社員70人に対して男性用トイレ、個室2つと3つの小便器がある状態を想定していおり、トイレの数は妥当なものかを問題にしています。

このケースではモンテカルロシュミレーション法と呼ばれる手法を使用しています。

  1. プロセスあるいはシステムをモデル化する。
  2. ランダムな入力をつくり、モデルに適用する。
  3. 入力を与えるとモデルが出力する。
  4. 出力を分析して求める答えを導く。

この手順で行っています。

モデル化する部分をRubyで行っています。詳細なプログラムに関しては省きます。githubに上がってるようです。https://github.com/setoyama60jp/everyday

CSV.open('simulation.csv', 'w') do |csv|
  lbl = []
  population_range.step(10).each {|population_size| lbl << population_size}
  csv << lbl
  DURATION.times do |t|
     row = []
  	population_range.step(10).each do |population_size|
  	  row << data[population_size][t]
  	end
  	csv << row
  end
end

と記述することによって、データをcsv形式で出力しています。

このようにcsvで出力されます。このあとRを使って分析をしていくわけですが分析から価値ある答えを見つけるために統計的な考え方や、機械学習の考え方が必要になってくるようです。

分析ってイメージがあいまいでしたが、どういう流れでやっているかがわかるので非常に良いです。

ひとまずRとRubyによるデータ解析入門がすごく楽しいです。本当はもっと細かく書きたいのですが、ぼちぼち出かける時間なので一旦ここまで。

Rのための統合開発環境RStudioを使ってみる。

まずはRStudioをインストールします。公式ページからダウンロードできます。macwindows,Linuxでも動くし、オープンソースでフリーなので助かります。アイコンがすごく丸っこくてなんかかわいらしいです。Rがguiっぽくつかえて便利そうです。詳しいインストール方法や画面の説明はRStudio事始めというスライドがわかりやすいです。それではRStudioを触っていきます。

Excelからデータを読み込む

nameheightweightsex
taro 168.5 69.5 M
jiro 172.8 75.0 M
hanako 159.0 56.5 F

このデータをRStudioに取り込みます。excelならばcsvに変換して保存します。RStudioを開いたら右上の方にある、Import DatasetからFrom Text Fileを選択します。csvにしたファイルを選択するだけです。

今回はデータ読み込んだだけですね。。

RをGUIっぽくも使えるし、まだまだ便利な機能ありそうなんで試してまた書きます。

(結局、完全に風邪引いてしまいました。体調管理も実力のうちと部活やってた時はよく言われたのを思い出しました。)

Rにcsvを読み込む時に出たエラー:incomplete final line found by readTableHeader on

どうでも良いけど、乾燥のせいか鼻の奥の方に嫌な予感のする痛みが出ています。 体調管理には気を付けたいところです。

さて朝からRにCSVを読み込もうとしてるけどエラーが出ています。

nameheightweightsex
taro 168.5 69.5 M
jiro 172.8 75.0 M
hanako 159.0 56.5 F

このような内容のcsvファイルを読み込むと、

> read.csv("data1.csv")
    name height weight sex
1   taro  168.5   69.5   M
2   jiro  172.8   75.0   M
3 hanako  159.0   56.5   F
 警告メッセージ: 
In read.table(file = file, header = header, sep = sep, quote = quote,  :
  incomplete final line found by readTableHeader on 'data1.csv'

こんなエラーというか警告がでます。で結局取り込めていない。

> data1
 エラー:  オブジェクト 'data1' がありません 

調べてみて、いくつか対策してみたけど直らず。

解決しちゃいたいけど、出かける時間なので一旦、退散します。夜は忘年会なのでちょっと取り組むの遅くなりそうです。

追記

帰宅したので今朝引っかかった問題に取り組む。じつは読み込めていなかったわけではなく。読み込んだあとのデータ名を指定していなかったということでした。

> sample1 <- read="" csv="" data1="" :="" in="" table="" file="file," header="header," sep="sep," quote="quote," incomplete="" final="" line="" found="" by="" readtableheader="" on=""> sample1
    name height weight sex
1   taro  168.5   69.5   M
2   jiro  172.8   75.0   M
3 hanako  159.0   56.5   F
sample1 <- read="" csv="" data1="" pre="">
でsample1にいれるということを明示しているわけですね。これ書かないと、エラーになるの当然だな。
警告に関してはstackoverflowを眺めてたらそれっぽいのありました。
readTableHead is the c-function that gives the error. It tries to read in the first n lines (standard the first 5 ) to determine the type of the data. The rest of the data is read in using scan(). So the problem is the format of the file.

確かに行数が多いのだと警告も出なかった。

> sample2 <- read="" csv="" data2=""> sample2
    name height weight sex
1   taro  168.5   69.5   M
2   jiro  172.8   75.0   M
3 hanako  159.0   56.5   F
4   taro  168.5   69.5   M
5   jiro  172.8   75.0   M
6 hanako  159.0   56.5   F

さすがに眠いので寝ます。明日の朝はデータの扱い方をもう少し見ていきますかね。

参照:'Incomplete final line' warning when trying to read a .csv file into R

R入門-その2

昨日はひつじ数えて眠ったので、その続きからやっていきます。

Collatzの問題

1937年にドイツの数学者Collatz(コラッツ)が,「ある数が偶数なら2で割り,奇数なら3倍して1を足す。これを繰り返すとすべての数は1になるだろう」と予想しましたが,だれもそれを証明することができていません。

という問題ですが、これはプログラムで解くとすぐにできそうです。ざっくりと言葉で書くと、whileかforを使って、ループで処理を行います。その処理はifを使って条件分岐させ、2で割った時のあまりが0の場合には2で割り、それ以外(奇数)の場合には3倍して1を足します。

collatz = function(n){
  cat(n)
  while(n>1){
    if(n %% 2 == 0){
      n = n / 2
    }
    else{
      n = n * 3 +1
    }
    cat("→",n)
  }
}

とこのようにかけます。whileとかifとかさらっと出てきたけど、特に注意することはないと思う。n %% 2はnを2で割った時のあまりですから、この余りが0ならばnは偶数になります。n %% 2 == 0の論理値がtrueならば、ifの処理が実行されます。引数を渡して実行してやると、うまくいくのがわかります。

> collatz(11)
11→ 34→ 17→ 52→ 26→ 13→ 40→ 20→ 10→ 5→ 16→ 8→ 4→ 2→ 1

データを読み込む

やっとデータを扱えます。警察庁のHPから公表されている統計データをダウンロードしてきます。交通事故統計(平成25年11月末)を使ってみます。変数xに年間合計を代入します。

x = scan(pipe("pbpaste"))

enterを押さない状態でexcelの取得したい範囲をコピーした状態でターミナルに戻りenterを押します。

>  x = scan(pipe("pbpaste"))
Read 16 items
> x
 [1] 9214 9012 9073 8757 8396 7768 7425 6927 6403 5782 5197 4968 4922 4663 4411
[16] 3883

Read 16 itemsと16の要素を読み込んでいます。xを表示してみると正しく読み込めていました。同様に変数tに年代を取り込んでみても良いのですが、ひとつずつならんだものならば、

x = 1998:2013

の方が簡単です。今思ったのですが、元号は平成、昭和などかわることがありますから、西暦の方が分析するときには気にせずできて楽そうです。

plot(t, x, type="o")

plotはRで作図する時に頻繁に使われる関数です。機能も多く、折れ線グラフや散布図なども描くことができます。引数typeによって形式を選ぶことができます。

plotの形式
引数機能
type="p" 点プロット(デフォルト)
type="l" 線プロット(折れ線グラフ)
type="b" 点と線のプロット
type="c" "b" において点を描かないプロット
type="o" 点プロットと線プロットの重ね書き
type="h" 各点から x 軸までの垂線プロット
type="s" 左側の値にもとづいて階段状に結ぶ
type="S" 右側の値にもとづいて階段状に結ぶ
type="n" 軸だけ描いてプロットしない(続けて低水準関数でプロットする場合)

ラベルをつけて描くために

plot(t, x, type="o", pch=16, xlab="年", ylab="死者数(人)")

としてやると年などのラベルがつくはずが

と画像のように文字化けしています。文字化けさせないためにはフォントを指定してあげるとokだそうです。

par(family="HiraMaruProN-W4")

で文字化けは解消されます。font-familyは適当。ついでに図のタイトルをつけて描画すると

plot(t, x, type="o", pch=16, xlab="年", ylab="死者数(人)",main="交通事故死者数の推移") 

うまくいきました。

データフレーム

> 身長 = c(168.5, 172.8, 159.0)
> 体重 = c(69.5, 75.0, 56.5)

このようなデータがふたつあったときにデータフレームが非常に有効です。そもそもデータフレームはdata.frame クラスを持つ要素であり、異なるデータ型でも複数の要素をひとつの変数として持つことができます。2次元配列のように見え、行と列は必ずラベルをもつという特徴があります。ラベルがあることによりラベルでの操作を可能にしてくれます。例えば、

> 身長 = c(168.5, 172.8, 159.0)
> 体重 = c(69.5, 75.0, 56.5)

というようなデータがあった時に、データフレームにまとめると効率的に扱えることがあります。

> X = data.frame(身長, 体重)
> X
   身長 体重
1 168.5 69.5
2 172.8 75.0
3 159.0 56.5

行の名前が1,2,3となっていますが、これを変更することもできます。row.namesで引数にデータフレームをとれば

> row.names(X)=c("太郎", "次郎", "花子")
> X
      身長 体重
太郎 168.5 69.5
次郎 172.8 75.0
花子 159.0 56.5

ここまでで一旦切って、次につなげます。

*参照:Rの初歩

R入門-その1

インストールしたRを触って慣れていこうかと思います。まずは慣れることから。調べてみると手始めにちょうど良さそうなのを発見しました。Rの初歩を参考にしてやっていきます。最初はなぞるだけ。

計算

四則演算は、[足すが+,引くが-,かけるが*,割るが/]です。例えば

> 1+1
[1] 2
> 3*3/6+2-1
[1] 2.5

という感じで計算ができます。ちなみに割るの"/"が小数点を含めて結果を出力してくれてます。

> pi
[1] 3.141593

これは円周率。どんなタイミングで使うのか今はまだわかりません。

変数も使えます。

> x = 3.14
> x
[1] 3.14

変数xに3.14という値を代入してみます。そのあとでxを呼び出すと3.14と代入した値が出力されます。普段から触れている変数と同じ感じがします。結果の前にいつも付いている、[1]は添字のことだそうです。Rでは添字が1から始まるんですね。

> x = 1:30
> x
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
[26] 26 27 28 29 30

こうするとよくわかります。この場合はx[1]=1で、x[26] = 26 となります。

ベクトル

(ちょっと寄り道ぽくなりますが、気になったので書いておきます。) Rでは一般的に値はベクトルらしいのですが、これってどういうことなのかいまいちピンときません。調べてみたところ

R では実数,複素数,文字列,論理数などの基本的データを一つずつ単独で扱う代わりに,同じ型のデータをいくつかまとめたベクトルと呼ばれる形で取り扱っている.よって,今までの例では数値や文字列を一つずつ単独で扱っているかのように説明してきたが,実際には R はこれらの基本的データを,要素の個数が一つだけのベクトルとして扱っていたわけである.例えば,以下の計算は要素がひとつのベクトル同士の足し算を行っていることになる.
1 + 2
[1] 3 
1 + 2 だから単に 3 と返せばよいだけのはずだが,よく見ると [1] が前についている.小難しく云えば 1×1 のベクトル (1) と 1×1 のベクトル (2) の足し算を行って,結果として 1×1 のベクトル (3) が返ってきたことになる.[1] は『ベクトルの一つめの要素』という意味である.

[*参照:12. ベクトルの作成 | ベクトルとは]

この説明が一番しっくり来た気がします。特に「小難しく云えば 1×1 のベクトル (1) と 1×1 のベクトル (2) の足し算を行って,結果として 1×1 のベクトル (3) が返ってきたことになる.」がもやっとしてた部分を解消してくれたような。ただ自分の言葉でうまく説明できないので、ちょっと時間をおいて考えなおしてみます。

ベクトルの作成:c()

ベクトルを作成するときは基本的にc()関数を使用します。

> c(1.0, 2.0, 3.0, 4.0, 5.0)
[1] 1 2 3 4 5

> x = c(1.0, 2.0, 3.0, 4.0, 5.0)
> x[2]
[1] 2
> x + 10
[1] 11 12 13 14 15

c(1.0, 2.0, 3.0, 4.0, 5.0)では長さ5のベクトルを作成しています。配列のような感じがします。変数xにいれて10を足すと、個々の要素ごとに演算が行われているのがわかります。本当に基礎的なところを一旦終えて、次は基礎かためのpracticeに取り組んでみます。

ひつじがnひき

帰ってきたのちょっと遅かったのですでに眠いけど、ひつじを数えます。

for (i in 1:10) cat("ひつじが", i, "ひき\n")

forを使って1:10のベクトル内で要素を変数iに代入して、for文中のcatを実行しています。最後の要素まできたところで、ループを終えます。

> hitsuji = function(n) { for (i in 1:n) cat("ひつじが", i, "ひき\n") }

この書き方ならば引数を渡してやれば、その値までを実行してくれます。

>  hitsuji(20)
ひつじが 1 ひき
ひつじが 2 ひき
・
・
・
ひつじが 19 ひき
ひつじが 20 ひき

これはn=20の場合です。ひとまずひつじのせいにして寝ます。

*参照