はじめに

About Me

興味ない人もいると思うのでクリックで展開します 藤原ゼミ5期生の新井です。経済学部を卒業した後に経済学修士課程に進み、主にRを使って研究とバイト(リサーチアシスタント・リサーチスタッフ)をしてきました。Pythonは、画像から文字を認識してExcelファイルに書き出すコードしか書いたことがありません。Rでは諸々の定量分析の他に、webスクレイピングや文字列の形態素解析、スライドやこういったHTMLの作成などを行なってきました。経済モデルのイテレーションにはMATLABを使ってました。

R and Python

RあるいはR言語とは、統計処理に特化したプログラミング言語のことです。回帰分析やt検定などの統計分析に加えて、webスクレイピングやメール送信なども行うことができます。
こういった作業が行えるのは、パッケージという拡張機能がユーザーによって作成・シェアされているからです。
よく比較される言語として、Pythonがあります。Pythonもまた、ユーザーが作るパッケージ等で機能拡張されています。
機械学習ではPython一強な昨今ですが、Rにも機械学習用のパッケージはあるし、最終的には自分で色々作ることになるので、基本的には「極めればRもPythonも一緒」と言われています。じゃあ、一般ユーザーとしてはどちらを使えば良いか?ということになりますが、これはやりたい作業内容や本人のスキルによるので、参考として以下に私なりにPythonと比較した際のRの長所短所を書いていきます。

  • 書くのがかなり簡単
  • 環境構築も簡単
  • あまり大きな変化がない
  • 統計分析のパッケージや情報が豊富(統計学者のユーザーが多い?)
  • OCRなど、Pythonに精度で劣る分野がある
  • ユーザーが少ないことと、「R」という名前の短さから、うまく情報が出てこない時がある
  • 要素のindexが1から始まるので、他言語をやる時混乱しやすい

がっつりプログラミングを勉強せずに統計分析がしたいならRで良いと思います。
プログラミングも勉強して、色々手広くやりたいならPythonの方が良いかもしれません。
どっちかをやっておけば、もう片方のコードもなんとなくはわかったりします。

Introduction

Rの導入は
http://ryotamugiyama.com/2020/08/03/rinstall/
https://yukiyanai.github.io/jp/resources/
あたりを参考にしてみてください。以前、Windowsユーザーを中心にRの導入段階で大混乱が起きました。
特にOnedriveと同期している方々は、トラブルが起きる確率が高いのでインストール前に上記記事に目を通すことを勧めます。

Word

  • オブジェクト
    数値や表、文字など、Rに出てくるもの全般を指します。
  • 関数
    Rではほとんどの作業を、関数(function)を使って実行します。Excelのsumなどと同じです。基本的に 関数名(引数) という形をとります。自分で関数を作ることも可能です。
  • 引数
    「ひきすう」と読みます。関数を使う時に指定する物のことです。例えば合計を計算するsumでは、何の合計を計算したいか指定する必要がありますが、その「何の」を引数として()の中に入力します。Xというオブジェクトの合計を計算したいなら sum(X) です。その他にも、欠損値 NA を無視するためのオプション na.rm=TRUE など、様々な引数が関数ごとにあります。
  • クラス
    Rにおけるオブジェクトの分類です。例えば数字なら double 、文字なら character 、 表なら table です。このクラスによってできることが変わっていきます。
    例えば double なら平均や合計が計算できますが、 character の平均や合計は計算することができません。反対に、特定の文字を抽出したり、文字をつなげたりするには、 character クラスが適しています。R等では、 1 という数字と、 1 という文字が明確に区別されることには注意が必要です。
    クラスは class(オブジェクト名) で調べられるので、処理がうまくいかない時にはチェックしてみましょう。
    もし OBJ というオブジェクトが、 double であって欲しいのに character になってしまっていたら、 OBJ <- as.double(OBJ) とすれば数値として再認識してくれます。ただし、カンマやスペースなどが入ってしまっていると、うまく数値に直せなくて欠損値 NA になってしまったりします。
  • コンソール
    コードの入力・実行をし、その結果が表示される場所のことです。
  • スクリプト
    コードが書いてあるファイルのことです。 .R という拡張子のものをRでは使います。基本的にコードはコンソールに直接打ち込まず、スクリプトの形で書いて実行していきます。これは、作業する度にいちいちコードを書かなくて良いようにする、後でコードが間違っていないか確認できるようにする、といった意味があります。

Keyboard Shortcuts

Rstudioでは様々なキーボードショートカットが使えて、快適なコーディングには欠かせないものになっています。
Alt + Shift + K などで確認できるので、積極的に習得しましょう。
個人的なお勧めは

  • Ctrl(Command) + Shift + R セクションの挿入
  • Ctrl(Command) + Shift + O スクリプトの目次の表示
  • Alt + - 代入演算子 <- の挿入
  • Ctrl(Command) + Alt + R スクリプト全体の実行

などです。環境によってキーに差があるかもしれません。ご了承・ご確認ください。

Working Directory

PCのファイルが入っている場所のことをディレクトリと呼びます。
DocumentsとかDownloadsとかもディレクトリの一つです。
ワーキングディレクトリ(以下、wd)とは、R(に限らず様々なソフト)が作業を行う場所を指します。
具体的には、デフォルトのファイルの保存先や、ファイルを探す場所などがwdとなります。
MATLAB等ではより顕著かつ分かりやすいですが、多くのソフトや言語ではファイルの名前が指定された時に、PC全体からそのファイルを探し出す、ということはしてくれません。具体的にファイルがどこにあるか(ファイルパスと呼びます)を教えるか、wdに見つけて欲しいファイルを入れておく必要があります。
自分のRがwdをどこに設定しているかは、getwd()というコマンドで確認できます。

getwd()
> [1] "/Users/KosukeA/Documents/RA/REAS"

この場合ですと、Documents内のRAフォルダの中のREASというフォルダがwdになっています。
例えばこのフォルダ内に Data.csv というファイルがあるならば、 read.csv("Data.csv") というコマンドで簡単にデータが読み込めます。
それに対して、もしDocumentsの中に Data.csv があるならば、Rがファイルの場所を理解できるように、 read.csv("/Users/KosukeA/Documents/Data.csv") としなければいけません。ファイルパスの確認方法はOSごとに異なりますが、getwd()の結果を参考にして手入力するのが楽な時も多いです。
ファイルを保存したりする場合も同様で、 何もつけずに write.csv(file,"DATA.csv") とすれば fileDATA.csv という名前でREASというフォルダに保存されますが、これをDocumentsに保存したいならば write.csv(file,"/Users/KosukeA/Documents/DATA.csv") としなくてはいけません。

いちいちこう入力するのは面倒なのに加えて、コードを間違えた時に大事なファイルを上書きしてしまうと大変なので、R用のフォルダを作り、そこをwdとして、必要なデータ等はそこにコピーして作業することを推奨しています。
余談ですが、私はRprojectという機能を使って作業内容別にwdとするフォルダを作っています。gitによるバージョン管理ができたり何かと便利ですが、ややこしいのでワードだけ紹介して省略します。
では、どうやってwdを指定するかですが、こちらは setwd("ファイルパス") で行えます。実際にDownloadsをwdにしてみましょう。

setwd("/Users/KosukeA/Downloads")
getwd()
> [1] "/Users/KosukeA/Downloads"

getwd() の結果が”/Users/KosukeA/Downloads”に変わりました。無事にwdを変更できています。

Packages

Rにはパッケージと呼ばれる拡張機能のようなものがたくさん存在し、それをインストールすることで様々なことができるようになります。
パッケージのインストール方法は色々とありますが、Rstudioでは画面上のメニューから Tools > Install Packages をするのが一番楽なのではないかと思います。
ただし、この方法でインストールできるのは CRAN と呼ばれるサイトに含まれるメジャーなものだけなので、マイナーなパッケージを使いたい時は自分で別途入手手段を探さないといけません。
インストールしたパッケージは、 library(パッケージ) というコマンドを使うか、 パッケージ名::関数名 とすることで使うことができます。
基本的には前者を使う方が楽ですが、複数のパッケージで共通の名前を持つ関数が存在する場合、後者の書き方をする必要が出てきたりします。
例えば lag はパッケージ plmdplyr に含まれているので、dplyrlag を確実に使いたい時は dplyr::lag() とします。
ちなみに後で紹介する %>%tidyverse というパッケージなどに含まれる拡張機能です。
後々使うのでここで有効化しておきましょう。

library(tidyverse)

Gloval Environment

Rでは行った作業の結果に名前をつけて、Rの中で繰り返し使用することができます。別途保存作業を行わない限り、PC内にはデータとして保存されません。
こうしてR内に保存された数列やデータ表などは、グローバル変数と呼ばれます。Rstudioでは右上のGlobal Environment で一覧を確認できます。
名前の付け方としては一般的に、 付けたい名前 <- 保存したい作業 という書き方をします。
(付けたい名前 = 保存したい作業 でも大体の場合うまくいきますが、一部の作業では代用できません。)
例えば、まだ何も保存していない状態で、 DATA と打ってもエラーが出ますが、

DATA
> Error in try(DATA) :  オブジェクト 'DATA' がありません

DATA <- 1を実行してから DATA と打つと、DATAの中身である1を返してくれます。

DATA <- 1
DATA
> [1] 1

for loop

プログラミング言語では、繰り返し処理として for が使われます。
Rでは、 for ( i in vector ) {...} というような書き方をします。この時、 i vector の中身を一つずつ順番に代入して、 {…} という処理を繰り返し行うことになります。具体例を一つ書いてみましょう。

for (i in 1:3){
  print(i)
}
> [1] 1
> [1] 2
> [1] 3

ここで、1:3 は1から3までの1ずつ増える数列です。5から8が良ければ 5:8 と書きます。
また、print(i) は i を画面に出力するというコマンドです。
結果として、「iを画面に出力する」という動作を、「iに1,2,3を順番に代入して」行うことができました。

if

また、大体のプログラミングでは if で条件を指定して動作を行うことが多いです。
Rでは if ( CONDITION ) {...} みたいな書き方をします。CONDITIONが満たされるなら {…} を実行する、といった具合です。 ここでは有名なFizz Buzz問題を for と if を使って解いてみましょう。Fizz Buzz問題とは、

  • プログラムを書けるか確認する簡単なクイズ
  • 与えられた数列に対して、3の倍数をFizzに、5の倍数をBuzzに置き換える
  • ただし、両方の倍数である(15の倍数である)場合は Fizz Buzz とする

というものです。例えば1から15の数列(Rだと1:15)にFizz Buzzを適用するなら、正解は
“1,2,Fizz,4,Buzz,Fizz,7,8,Fizz,Buzz,11,Fizz,13,14,Fizz Buzz”
となります。
まずは1から15の数列にtestという名前を付けておきます。

test <- 1:15

では、ファーストステップとして、3の倍数をFizzに置き換えてみましょう。

  • 「 i に1から15を順に代入して」
  • 「もし i が3の倍数という条件が満たされるなら」
  • 「 Fizz に置き換える」

という考え方でコードにしていきます。順に、

  • for (i in 1:15)
  • if (i%%3==0)
  • test[i] <- "Fizz"

という書き方をします。ここで二列目の i%%3 は i を 3 で割った余りを計算し、
test[i] はtestの中身のうち i 番目を指します。これに <- "Fizz" でFizzという文字を入れているわけです。
なお、文字列は”“で囲わないと、その名前のグローバル変数だと解釈されるので、DATAの時と同じように、そんなオブジェクトはないと怒られます。
実行して結果を見てみましょう。

for (i in 1:15) {
  if (i %% 3 == 0) {
    test[i] <- "Fizz"
  }
}

test
>  [1] "1"    "2"    "Fizz" "4"    "5"    "Fizz" "7"    "8"    "Fizz" "10"  
> [11] "11"   "Fizz" "13"   "14"   "Fizz"

これを5の倍数、15の倍数についても同じようにすれば、Fizz Buzz問題はクリアです。
置き換え作業をするだけでこんなにコードを書くのか、と思う方もいるかもしれませんが、短く書くこともできるのでご安心ください。Fizz Buzzも存外奥が深いんです。

map_chr(1:15,~{if (.%%15==0) "Fizz Buzz" else if (.%%5==0) "Buzz" else if (.%%3==0) "Fizz" else .})
>  [1] "1"         "2"         "Fizz"      "4"         "Buzz"      "Fizz"     
>  [7] "7"         "8"         "Fizz"      "Buzz"      "11"        "Fizz"     
> [13] "13"        "14"        "Fizz Buzz"

else

A=B なら処理1を、そうでないなら処理2を実行したい場合は、 else を使います。
1から4の数字について、奇数なら Odd 偶数なら Even と表示するコードを書いてみましょう。

for (i in 1:4){
if (i%%2==1) {
  print("Odd")
} else {
  print("Even")
}
}
> [1] "Odd"
> [1] "Even"
> [1] "Odd"
> [1] "Even"

ところで { } は、複数行にわたる処理を一塊のものとして扱う際に使います。
条件を満たした時に実行して欲しい処理が複数ある場合などは、どこからどこまで実行して欲しいかの明文化が必要です。

Logical Value

ところで if の中では == を等号として使っていました。イコールが2つ並んでいる場合は、「等号が成立するか否か」が返されます。
こういった場合に返される、命題が真か偽かを示す値を、論理値(logical value) と呼びます。
== 以外にも例えば、

  • != 等号が成立しないかどうか
  • %in% 含まれるかどうか
  • !A%in%B AがBに含まれないかどうか
  • is.numeric() 数字かどうか

など、論理値を返すものはたくさんあります。返り値は常に TRUE か FALSE です。

"Doraemon"=="Nobita"
> [1] FALSE
"Doraemon"!="Nobita"
> [1] TRUE
6%in%1:15
> [1] TRUE
!6%in%1:15
> [1] FALSE
is.numeric("Doraemon")
> [1] FALSE

また、論理和 (A or B) は | 、論理積 (A and B) は & を使います。

1+2==3 | 1+3==3
> [1] TRUE
1+2==3 & 1+3==3
> [1] FALSE

 

ところで、 ベクトル == 数値 を実行すると、「ベクトルの各要素が数値と一致するか」を要素ごとに判定して、TRUE/FALSEのベクトルを返します。
ベクトル == ベクトル だと、第i成分が一致するかどうかの判定を各iで判定して、やはりTRUE/FALSEのベクトルが返ってきます。)
この応用で、 Vector1[Vector2 == 数値] などを実行して、Vector1の成分のうち、Vector2 = 数値 が成立するインデックスに位置するものだけを抽出することができます。
例として、以下の2つのベクトルを使って見てみましょう。

 Vector1 Vector2
       1       1
       2       2
       3       3
       4       1
       5       2
       6       3
       7       1
       8       2
       9       3
      10       1

Vector2 = 1 が成立する行にある、Vector1 の 値を抽出します。

Vector1[Vector2==1]
> [1]  1  4  7 10

こういった作業は、例えば西暦2015年以降は1になるようなダミー変数を作りたい時など、何か指標に基づいて別の指標に手を加えたり、別の指標を作成したりしたい時に便利になってきます。

なお、論理値に関して細かいことを言うと、if はかっこの中が TRUE なら実行する、という仕組みになっています。
こういった仕組みをたまに活かして行うのがwhileループです。

while loop

一定の条件が満たされている限り動作を繰り返す、という処理を while を使って行うことができます。
while ( CONDITION ) {...} で CONDITION が満たされている( = TRUEである)間、 {…} が繰り返されます。
for では繰り返し作業の回数が vector の要素の個数で決まりますが、while はコードを書いた時点では何回繰り返すか決まっていません。
そのため、一定の水準を満たすまで何回もトライするような場合によく使われます。
例として、厚さ0.09mmのコピー用紙を何回折ったら月に届くか while を使って計算してみましょう。
月までの距離は384400000000mmで、紙は1回折るごとに厚さ thickness が2倍になります。
計算方法として、紙の厚さが月までの距離より小さい限り、紙を折って厚さを2倍にするのを繰り返すことにします。
折った回数は、whileループをする度に count を1ずつ増やすことでカウントします。

thickness <- 0.09
count <- 0
while(thickness<384400000000){
  count <- count + 1 
  thickness <- thickness*2
}
print(count)
> [1] 42
print(thickness)
> [1] 395824185999

42回で月までの距離を超えることを確認できました。
なお、手動で止めるまで動作を繰り返し続けて欲しい場合などは、 while(TRUE) とすることで無限ループになり、自動化等ができます。 タイポなどで上のコードを thicknes <- thickness*2 とかにしてしまった場合も、永遠に thickness<384400000000 が TRUE なのでやはり無限ループします。処理が終わらない時は無限ループになっていないかチェックしましょう。

next / break

for, while ループでは、 if と併せて next , break というコマンドが使えます。
next が実行されると、その時点でそのループは終了し、次のループへと移ります。
break が実行されるとその時点で全てのループが終了し、for / while ループから抜けます。

例えば以下の2つのコードを見比べてみましょう。

for (i in 1:3){
  if (i == 2 ) next
  print(i)
}

for (i in 1:3){
  if (i == 2 ) break
  print(i)
}

上の方のコードでは、 i=2 の時、 print(i) を実行する前に next が機能するので、 print(2) は実行されず、1と3だけが画面に表示されます。

for (i in 1:3){
  if (i == 2 ) next
  print(i)
}
> [1] 1
> [1] 3

一方、下の方のコードでは、i=2 の時、 print(i) を実行する前に break が機能するので、 print(1) だけ実行して、ループは終わってしまいます。
この場合、実は終わった時の i の値も2になっていて、「 i に3を代入する」という for ループの処理自体が行われていないことがわかります。

for (i in 1:3){
  if (i == 2 ) break
  print(i)
}
> [1] 1

Plot

グラフは ggplot2 というパッケージを使って描くことが多いです。このパッケージは tidyverse パッケージに含まれているので、 library(tidyverse) とした時点で実は既に使えるようになっています。
書き方の基本は、

ggplot(データ名)+
  aes(x=X軸,y=Y軸)+
  geom_point()+ # 散布図ならこれ
  geom_bar()+ #棒グラフならこれ
  geom_line()+ #折れ線グラフならこれ
  theme() #ここでフォントなどを調整する

です。 geom~ は書きたいグラフに応じて使い分けてください。 theme はなくても動きます。
ここでは前節で計算した紙の厚さと折った回数の関係と、月までの距離をグラフで表現してみましょう。
最初に、紙を折った回数と紙の厚さを、データの形(dataframe)にまとめます。
データフレームの作り方も色々とありますが、ここでは一番シンプルな data.frame 関数を使います。
data.fram(列名 = 列の中身,・・・) という書き方をします。

tmp <- data.frame(ct=0:42,thick=0.09*2^(0:42))

この tmp を使ってグラフを書きましょう。
ここでは更に、 geom_hline() を使っています。 hlinehorizontal line の略です、多分。横線を引くことができます。
縦線はおそらく vertical line の略で geom_vline() です。
hline の場合は yintercept で、 vline の場合は xintercept で、どこに線を引くのか指定できます。
今回は月までの距離で yintercept を指定しましょう。
実線が2本だとややこしいかもしれないので、更に linetype= で、 geom_hline を破線にしています。
その他にも、 color=alpha= などで、色や透明度を変えたりもできます。

ggplot(tmp)+
  aes(x=ct,y=thick)+
  geom_line()+
  geom_point()+
  geom_hline(yintercept = 384400000000,linetype="dashed")

ちゃんと42回目で初めて月までの距離を超えていますね。

Data frame and Global Env.

ところで、今作った tmp というデータフレームには ctthick という列が含まれていましたが、これらの列をRで単純に ctthick と入力して呼び出すことはできません。列名は、先述のグローバル変数に含まれないからです。ややこしく感じるかもしれませんが、グローバル変数に含まれないおかげで、同じ列名を持つ異なる名前のデータフレームを作成でき、それらのデータフレーム同士で、共通の名前の列が干渉しあうことも起こりません。
(グローバル変数では、同じ名前のものを2つ作ろうとしても、先に作った方は後に作った方に上書きされてしまいます。)
データフレーム等の中にあるオブジェクト・列・ベクトルを呼び出す際には、 データフレーム名$列名 あるいは データフレーム名["列名"] と入力します。後者はダブルクォーテーションで囲まないと、 列名 というグローバル変数だと認識されてエラーが出たりします。
Rでも他の言語でも、最初のうちはこの、「グローバル変数」と「その他のオブジェクト」の区別が非常にややこしく、ストレスフルだと思います。
「オブジェクトが〜」というエラーメッセージが出た際には、自分の扱いたいオブジェクトがグローバルか否かを再考すると解決することが多いです。

Pipe Operator

tidyversedplyrrvest など特定のパッケージを library() で有効化している場合、パイプオペレーターと呼ばれる %>% を使うことができます。
Ctrl + Shift + MCommand + Shift + M で入力できます。
これは、 ‘%>%’ の左にあるオブジェクトを、右にある関数の引数として扱う、という意味になります。
例えば、最初の方に使った print() を使って画面に “Hello World!” と表示したい場合、
print("Hello World!")"Hello World!" %>% print() のどちらでも目的を果たすことができます。

print("Hello World!")
> [1] "Hello World!"
"Hello World!" %>% print()
> [1] "Hello World!"

これだけでは %>% を使うメリットは分かりませんが、実際の作業で多くの処理を一つのオブジェクトに対して行う場合、コードの煩雑化を避けるのに大いに役立ちます。
私が実際に研究で用いたコードについて、 %>% を使った場合と使わなかった場合の例を以下に書いてみます。
このコードでは、 abroad1 というファイルを読み込んで、形を扱いやすいものに変え、変な記法がされていた年データを直し(日本のデータは和暦の存在もあり、年を表す部分の修正が必要になる場合が非常に多いです)、年と産業の名前ごとに売上の合計を計算し、その合計の一覧に abs と名付ける、という作業を行なっています。

# %>% を使わない例 1
abs <- read.xlsx("abroad1.xlsx",sheet="sales")[,-1]
abs <- pivot_longer(data = abs,cols = -name,values_to = "sales",names_to = "year")
abs <- rowwise(abs)
abs <- mutate(abs,year = as.numeric(paste0(unlist(str_extract_all(year,pattern = "\\d")),collapse = ""))+2000)
abs <- group_by(abs,year,name)
abs <- mutate(abs,sales=sum(sales,na.rm = T))
abs <- slice_head(abs)
abs <- ungroup(abs)
# %>% を使わない例 2
abs <- ungroup(slice_head(mutate(group_by(mutate(rowwise(pivot_longer(data = read.xlsx("abroad1.xlsx",sheet="sales")[,-1],cols = -name,values_to = "sales",names_to = "year")),year = as.numeric(paste0(unlist(str_extract_all(year,pattern = "\\d")),collapse = ""))+2000),year,name),sales=sum(sales,na.rm = T))))
# %>% を使って書いたコード
abs <- read.xlsx("abroad1.xlsx",sheet="sales")[,-1] %>%
  pivot_longer(-name,values_to = "sales",names_to = "year") %>%
  rowwise() %>%
  mutate(year = str_extract_all(year,pattern = "\\d") %>% 
           unlist() %>%
           paste0(.,collapse = "") %>%
           as.numeric()+2000) %>% 
  group_by(year,name) %>%
  mutate(sales=sum(sales,na.rm = T)) %>% 
  slice_head() %>% ungroup()

好みは分かれると思います。特に1つ目は、1行につき1つの作業しかしていないので、見る分には分かりやすいです。 ただ、書くのはなかなか面倒で、 abs <- が連なっているのは代名詞のない作文みたいで冗長に思えます。
2つ目は作業を全てまとめて行っているので、括弧の数がとにかく多くて、書く分にも見る分にもややこしくなっています。括弧の数が合わずにエラーが出る可能性が高いし、どの関数が何をどうしているか見るのに手間がかかります。
3つ目の書き方では、作業を全てまとめて行いつつも、作業ごとに %>% で区切ってあるので、関数とその引数が分かりやすいかと思います。 abs も省略できるので、括弧の中に何も入力しなくても rowwise() などがちゃんと動作します。反面、 %>% を使ったことのない人から見ると最初は理解が難しいと思います。
Rを本格的に使っていくなら、3番目の書き方に慣れておくことをお勧めします。職場のRユーザーなら、 %>% にも慣れていると思うのでチェックしてもらう分にも安心でしょう。
余談ですが、 %>% を使う際には関数の括弧の中身を省略できますが、何も書かないという省略方法の他に、 . で代用するという方法もあります。こちらは、明確にどこに %>% の左側のオブジェクトが入って欲しいかを示すことができます。 print の例に戻るならば、

"Hello World!" %>% print(.)
> [1] "Hello World!"

でも良いということです。

function

Rでは自分で関数を作ることができます。作り方としては
関数の名前 <- function(関数の引数){関数の処理内容・return(返して欲しい値)} です。
ここでは、平均を求める関数 mymeanfunc を作りたいと思います。勿論、平均を求める関数はすでにRに存在しますが、ここではオプションで算術平均と幾何平均のどちらを求めるか選べるようにしてみましょう。
N個の数字の平均を求める時、 \[算術平均=\frac{\sum_{n=1}^N X_n}{N}\qquad ,\qquad 幾何平均 = \prod_{n=1}^N (X_n)^{\frac{1}{N}}\] です。

mymeanfunc <- function(X,option="Arithmetic"){
    if (option == "Arithmetic") {
    # length は ベクトルの長さ i.e. 要素の数を返す関数です
    return(sum(X)/length(X))
    } 
if (option == "Geometric") {
   # prod は ベクトルの product (積。全部かけ合わせた値) を返します。
   # 今回は X^(1/length(X)) で X の 1/N 乗 をかけ合わせています。
    return(prod(X^(1/length(X))))
    } 
}

これで mymeanfunc(X=平均を求めたいベクトル) とすれば、平均を求めることができます。
上のコードで function の中に option="Arithmetic" と書いてありますが、これは
「option という引数について何も指定がなかったら “Arithmetic” を使う」という意味になります。
言うならば、デフォルトの引数ですね。
動作を確認してみましょう。

mymeanfunc(1:10)
> [1] 5.5
mymeanfunc(1:10,option = "Arithmetic")
> [1] 5.5
mymeanfunc(1:10,option = "Geometric")
> [1] 4.528729

大丈夫そうです。