Python視点でR言語の文法を勉強する
🎯 目的
Pythonエンジニア視点で、R言語のコーディングで躓く点を明らかにする。
これまで1年ほどPythonで記述してきましたが、お仕事でRを使う機会が増えてきました。Python以外の言語もいくつか通ってきているので基本的なコーディングは問題なかったのですが、ところどころのポイントで躓いていました。
まだまだ深みには達していないものの、躓いたポイントを備忘録としてまとめます。
※ サンプルコードはClaude3.5に書いてもらっています。
👾 躓きポイント
1. 📦 パッケージの読み込み
Pythonではプロジェクト作成時にpipコマンドでパッケージをインストールすることが多いですが、Rではコードにinstall.packages()
関数によってパッケージをインストールします。
パッケージによってはCRANを指定しなければインストールできないものもあります。
✓ Python
# コンソールでインストール
# pip install pandas
# パッケージ読込
import pandas as pd
✓ R言語
# CRANミラーを設定
options(repos="https://ftp.yz.yamagata-u.ac.jp/pub/cran/")
# パッケージが存在しない場合のみインストール
if (!require(dplyr)) install.packages("dplyr")
# パッケージ読込
library(dplyr)
2. 🧮 ベクターとリスト
Pythonでは単に列挙する配列はリスト、キーと値をセットとする配列は辞書(dict)と呼ばれます。一方でRでは単に列挙する配列はベクター、キーと値をセットとする配列はリストと呼ばれます。
LLMに質問する際に「リスト」を要求すると、Pythonでいうdictが返ってくることになります。
✓ Python
# リスト(単純な配列)
python_list = [1, 2, 3, 4, 5]
# 辞書(キーと値のペア)
python_dict = {"fruit1": "apple", "fruit2": "banana", "fruit3": "cherry"}
✓ R言語
# ベクター(単純な配列)
r_vector <- c(1, 2, 3, 4, 5)
# リスト(キーと値のペア)
r_list <- list(fruit1 = "apple", fruit2 = "banana", fruit3 = "cherry")
3. 🔍 配列のindex
Pythonでは配列のindexは0から始まりますが、Rでは配列のindexは1から始まります。
また、indexとして負の値-n
を与えたとき、Pythonではで末尾からn番目の要素を参照しますが、Rではn番目の要素以外すべてを参照することになります。
✓ Python
# 配列とインデックスの使用
python_list = ["apple", "banana", "cherry", "date"]
print(python_list[0]) # 最初の要素: "apple"
print(python_list[2]) # 3番目の要素: "cherry"
print(python_list[-1]) # 最後の要素: "date"
# スライシングの例
print(python_list[1:3]) # ["banana", "cherry"]
✓ R言語
# 配列(ベクター)とインデックスの使用
r_vector <- c("apple", "banana", "cherry", "date")
print(r_vector[1]) # 最初の要素: "apple"
print(r_vector[3]) # 3番目の要素: "cherry"
print(r_vector[length(r_vector)]) # 最後の要素: "date"
# 負のインデックスの例(要素の除外)
print(r_vector[-1]) # c("banana", "cherry", "date")
# スライシングの例
print(r_vector[2:3]) # c("banana", "cherry")
4. 🔄 returnの挙動
Pythonではreturn文がなければNoneが返り、return x
と書けばxが返ります。Rではreturn文がなければ最後に処理された結果が返り、return(x)
と書けばxが返ります。
複数の値を返す場合、Pythonではタプルを、Rではリストとして返されます。
✓ Python
def python_function():
a = 1
b = 2
c = a + b
# return文なし
def python_function_with_return():
a = 1
b = 2
c = a + b
return c
def python_multiple_return():
return 1, 2, 3 # タプルとして複数の値を返す
print(python_function()) # 出力: None # Noneが返る
print(python_function_with_return()) # 出力: 3 # 指定されたc(3)を返す
print(python_multiple_return()) # 出力: (1, 2, 3) # 複数の値がタプルとして返される
✓ R言語
r_function <- function() {
a <- 1
b <- 2
c <- a + b
}
r_function_with_return <- function() {
a <- 1
b <- 2
c <- a + b
return(c)
}
r_multiple_return <- function() {
return(list(x = 1, y = 2, z = 3)) # リストとして複数の値を返す
}
print(r_function()) # 出力: 3 # 最後に処理されたc(3)が返る
print(r_function_with_return()) # 出力: 3 # 指定されたc(3)を返す
print(r_multiple_return()) # 出力: $x 1 $y 2 $z 3 # 複数の値がリストとして返される
5. 🛡️ tryCatchとグローバル変数
Pythonではエラー処理はtry-except
で行いますが、RではtryCatch-error
を使います。
このとき、Pythonのtry-except
内で定義した変数はスコープ外からアクセスできますが、RのtryCatch
内で定義した変数はスコープ外からアクセスできません。(※ Rのif文内で定義した変数はスコープ外からアクセスできます。)
RでtryCatch
内の変数を外から扱うには、 特別な演算子 <<-
を使ってグローバル変数とするか、tryCatch
を関数のように利用して1つの値を返す必要があります。
✓ Python
# Pythonの例
try:
x = 10
y = x / 0 # ゼロ除算エラーを発生させる
except ZeroDivisionError:
error_value = "ゼロ除算エラーが発生しました"
print(x) # 10が出力される
print(error_value) # "ゼロ除算エラーが発生しました" が出力される
✓ R言語
tryCatch({
x <- 10
y <- x / 0 # ゼロ除算エラーを発生させる
}, error = function(e) {
error_value <- "ゼロ除算エラーが発生しました"
})
print(x) # エラー: オブジェクト 'x' が見つかりません
print(error_value) # エラー: オブジェクト 'error_value' が見つかりません
✓ R言語 (グローバル変数を使用する例)
x <- NULL
error_value <- NULL
tryCatch({
x <<- 10 # グローバル代入演算子を使用
y <- x / 0
}, error = function(e) {
error_value <<- "ゼロ除算エラーが発生しました" # グローバル代入演算子を使用
})
print(x) # 10が出力される
print(error_value) # "ゼロ除算エラーが発生しました" が出力される
✓ R言語 (tryCatchを使用して1つの値を返す例)
result <- tryCatch({
10 / 0 # ゼロ除算を試みる
}, error = function(e) {
NA # エラーが発生した場合はNAを返す
})
print(result) # NAが出力される
6. 🖨️ 標準出力の書き方
Pythonではprint()
で標準出力に文字列を出力でき、Rではprint()
やcat()
などの関数で文字列を出力できます。
print()
は各引数を別々の行に出力し、デフォルトで引用符[1]
付きで表示します。一方、cat()
は引数を横並びに出力し、引用符なしで表示します。改行が行われないので、明示的に改行\n
を指定する必要があります。
個人的には引用符が邪魔すぎて、catを使うことが多いです。
✓ Python
name = "Alice"
age = 30
print("Hello, World!") # 出力: Hello, World!
print("My name is", name, ", and I am", age, "years old.") # 出力: My name is Alice, and I am 30 years old.
print(f"My name is {name}, and I am {age} years old.") # 出力: My name is Alice, and I am 30 years old.
✓ R言語
name <- "Bob"
age <- 25
print("Hello, World!") # 出力: [1] "Hello, World!"
print(name, age) # 出力: [1] "Bob" [2] 25
cat("Hello, World!\n") # 出力: Hello, World!
cat("My name is", name, "and I am", age, "years old.\n") # 出力: My name is Bob and I am 25 years old.
7. 🔗 paste()とpaste0()
Rには文字列結合のための関数としてpaste()
とpaste0()
が用意されています。
paste()
はデフォルトで要素間にスペースを挿入し、paste0()
はスペースを挿入しません。paste()
のsep引数で区切り文字を指定でき、両関数ともcollapse引数でベクター内の要素を1つの文字列に結合できます。
✓ R言語
# paste()の基本使用
name <- "Alice"
greeting <- paste("Hello", name)
print(greeting) # "Hello Alice"
# paste0()の使用
first_name <- "John"
last_name <- "Doe"
full_name <- paste0(first_name, last_name)
print(full_name) # "JohnDoe"
# sep引数の使用
words <- c("R", "is", "awesome")
sentence <- paste(words, sep = "-")
print(sentence) # "R-is-awesome"
# collapse引数の使用
fruits <- c("apple", "banana", "cherry")
fruit_list <- paste(fruits, collapse = ", ")
print(fruit_list) # "apple, banana, cherry"
8. 🏷️ データフレームのカラム指定
Pythonではpandasをインストールすることでpd.DataFrame()
を扱えるようになりますが、Rでは何もインストールせずとも標準でdata.frame()
がサポートされています。
当然データフレームの扱いにも違いがあり、カラムの指定方法や長さの確認方法が異なります。
特に特徴的なのはカラムの指定方法で、Rではカラム名がAの場合、df$A
のように$を使って指定します。そのAが変数に格納されている場合、df[[col_name]]
のように二重括弧を使って指定する必要があります。また、カラム名がアルファベットでない場合はdf$`名前
のようにバッククォートで囲む必要があります。
✓ Python pandas (カラムの指定)
import pandas as pd
# データフレームの作成
df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6], '名前': ['太郎', '花子', '次郎']})
# カラムの指定(文字列)
print(df['A']) # 出力: 0 1 1 2 2 3 Name: A, dtype: int64
# カラムの指定(インデックス)
print(df.iloc[:, 0]) # 出力: 0 1 1 2 2 3 Name: A, dtype: int64
# カラムの指定(変数内の文字列)
col_name = 'A'
print(df[col_name]) # 出力: 0 1 1 2 2 3 Name: A, dtype: int64
# 日本語カラム名の指定
print(df['名前']) # 出力: 0 太郎 1 花子 2 次郎 Name: 名前, dtype: object
# 複数カラムの指定(文字列リスト)
print(df[['A', 'B']]) # 出力: A B 0 1 4 1 2 5 2 3 6
✓ R言語 (カラムの指定)
# データフレームの作成
df <- data.frame(A = c(1, 2, 3), B = c(4, 5, 6), "名前" = c('太郎', '花子', '次郎'))
# カラムの指定(文字列)
print(df$A) # 出力: 1 2 3
print(df[["A"]]) # 出力: 1 2 3
# カラムの指定(インデックス)
print(df[, 1]) # 出力: 1 2 3
# カラムの指定(変数内の文字列)
col_name <- "A"
print(df[[col_name]]) # 出力: 1 2 3
# 日本語カラム名の指定(バッククォートを使用)
print(df$`名前`) # 出力: "太郎" "花子" "次郎"
# 複数カラムの指定(文字列ベクター)
print(df[, c("A", "B")]) # 出力: A B 1 1 4 2 2 5 3 3 6
9. 📏 データフレームの行列数の確認
行列数を確認する関数も異なります。
珍しくRの方が分かりやすい命名だと感じています。
✓ Python pandas (行列数の確認)
# 複数カラムの指定(インデックス)
print(df.iloc[:, [0, 1]]) # 出力: A B 0 1 4 1 2 5 2 3 6
# データフレームの長さ(行数)の確認
print(len(df)) # 出力: 3
# カラム数の確認
print(len(df.columns)) # 出力: 3
✓ R言語 (行列数の確認)
# 複数カラムの指定(インデックス)
print(df[, 1:2]) # 出力: A B 1 1 4 2 2 5 3 3 6
# データフレームの長さ(行数)の確認
print(nrow(df)) # 出力: 3
# カラム数の確認
print(ncol(df)) # 出力: 3
おわり 🏁
おわり
Discussion