Rで値の文字と数字を分ける方法のメモ。方法はいろいろありそうだが、とりあえずシンプルに。
例えば、データに30cmや500mlなどの数値と文字列がくっついている場合がある。このとき、これらの値(30cmなど)は文字列として処理されるので処理しにくく、数値と文字列を切り分けたい場合がある。
まずは適当なサンプルデータを作る。特に意味はないけど、今回は{tibble}
を使ってデータフレームを作ってみるが普通のデータフレームでもいい。
library(tibble) d <- tibble(length = c("-20cm", "30cm", "40cm", "0.5m", "0.6m"))
このデータの長さはcmやmの単位がついており、数値を取り出すだけではなく、単位も取り出して、単位がcmのところは1/100して単位をmに統一という欲求も満たしたい。また数値は負の値にも対応したいと考える。
複雑なパターンを想定し始めると結構条件が多くなるので、今回のように数値1つに単位1つのパターンで考えてみる。
{stringr}
のstr_remove_all()
を使って任意の文字を条件を指定し数値と単位を切り出すことにする。
今回の場合は数値(小数点、マイナス記号を含む)を[[:digit:]-.]
で指定するといい([0-9-.]
でもいい)。数値を取り出すときは^
をつけてそれらを含まない文字を切り捨て、文字列のみを取り出すときには数値を切り捨てるようにするとうまく取り出せる。
また、数値は取り出したら数値型にするとあとで取り扱いやすい。
あとは、単位にcmを含むものを条件にif_else()
をつかって1/100するようにすると期待通りの結果が得られる。
library(dplyr)
##
## 次のパッケージを付け加えます: 'dplyr'
## 以下のオブジェクトは 'package:stats' からマスクされています:
##
## filter, lag
## 以下のオブジェクトは 'package:base' からマスクされています:
##
## intersect, setdiff, setequal, union
library(stringr) d <- d |> mutate(length_num = str_remove_all(length, "[^[:digit:]-.]") |> as.numeric(), length_str = str_remove_all(length, "[[:digit:]-.]"), length_m = if_else(length_str == "cm", length_num * 0.01, length_num)) d
## # A tibble: 5 × 4
## length length_num length_str length_m
## <chr> <dbl> <chr> <dbl>
## 1 -20cm -20 cm -0.2
## 2 30cm 30 cm 0.3
## 3 40cm 40 cm 0.4
## 4 0.5m 0.5 m 0.5
## 5 0.6m 0.6 m 0.6
{tidyverse}
ファミリーの{dplyr}
パッケージと{stringr}
パッケージをつかったが、組み込み関数({base}
)でも実現できる。
文字列の切り出しはgsub()
を使う。
d <- data.frame(length = c("-20cm", "30cm", "40cm", "0.5m", "0.6m")) d <- d |> transform(length_num = gsub(pattern = "[^[:digit:]\\.-]", replacement = "", x = length) |> as.numeric(), length_str = gsub(pattern = "[[:digit:]\\.-]", replacement = "", x = length)) |> transform(length_m = ifelse(length_str == "cm", length_num * 0.01, length_num)) d
## length length_num length_str length_m
## 1 -20cm -20.0 cm -0.2
## 2 30cm 30.0 cm 0.3
## 3 40cm 40.0 cm 0.4
## 4 0.5m 0.5 m 0.5
## 5 0.6m 0.6 m 0.6