Julia の Dataframes の列名で、正規表現が使えるRの "grep" をする方法

julia には、R の grep と同じ働きをするコマンドはありません。

結論の定義を書きます。ブロードキャスト "." というのを使って、contains.(), または、ismatch.() して、true を、find() で探せば良いです。"set" を、iris という Dataframe の :Species という列 (column) から探します。

find(contains.(iris[:Species] , "set"))
または、
find(ismatch.(r"set" , iris[:Species]))

恐らく、これが関数を使った記載で、回帰的に書かない、シンプルな記載ではないかと考えます。r" " というのは、正規表現のマクロだそうです。contain() か、ismatch() の使い方と、find() の組合せなので、下記より覚えやすいと思います。

以下は、昔、がんばって書いた分です。参考になる人がいたら幸いです。Dataframes の列名で、grep する関数を定義しました。

function grep(word, array)
  foo = find(ismatch(Regex(word), x) for x in array)
  return foo
end

  • word には、"" で、単語の一部などを入れて下さい。array は、下記の iris の例なら iris[:Species] を入れます。順番は、R の grep の順にしました。
  • 正規表現で探したい場合は、word の部分を r"" で入力して下さい。例えば、Regex(r"hoge$") は、r"hoge$" を返しので動くはずです。
  • [ismatch(Regex(word), x) for x in array] だけなら、true or false の Bool で返ります。これを find() の中に入れると、true のある番号を返してくれます。Bool の方が良ければ、foo = [ismatch(Regex(word), x) for x in array] と書けば良いでしょう。
  • Regex(word) で、word に代入した文字列が正規表現化されます。
  • 正規表現が必要なければ、foo = find(contains(x, word) for x in array) でも同じ結果になります。

上記で定義した grep 関数の実例は最後に書いてあります。毎度、おなじみの R のデータセット iris を例に、順をおって勉強してみましょう。

using RDatasets
iris = dataset("datasets", "iris")

これで、iris に格納されるはずです。

julia> by(iris, :Species, nrow)
3×2 DataFrames.DataFrame
│ Row │ Species      │ x1 │
├─────┼──────────────┼────┤
│ 1   │ "setosa"     │ 50 │
│ 2   │ "versicolor" │ 50 │
│ 3   │ "virginica"  │ 50 │
という、3つの種のデータが50個ずつですね。

このうち、"set" で含むものを採ってきましょう。まずは、正規表現の関係がない contains() を使ってみます。

[contains(x,"set") for x in iris[:Species]]

と書けば Bool で返ります。 "setosa" のところが、true になっているはずです。

次に、R の grep() は、行番号を返すので、true のところの番号を返す find() を使います。

iris[ find( contains(x,"set") for x in iris[:Species] ) , :]
または、
iris[find( x->contains(x,"set"),iris[:Species] ), :]
とします。

含まないものは、"!" を "contains" の前に付けて、

find( !contains(x,"set") for x in iris[:Species] )
または、
find( x->!contains(x,"set"),iris[:Species] )

と書けば良いです。

しかし、find( x->!contains(x,"set"),iris[:Species] ) は、正規表現がたぶん使えません。

正規表現を使いたい派のあなたと、ブリーアン型のベクトルを作って複数の条件を組み合わせたいあなたは、ismatch を使いましょう。

[ismatch(r"set", x ) for x in iris[:Species] ]
これで true or false で返してくれます。r""というのは、マクロらしいです。Regex() の中に入れても同じ動きをします。残念ながら、ismatch() は、正規表現に変換しないと動かないようです。再帰的な記載をしましたが、for ループで積み上げる記載だと下記のようになります。
foo=[]
foo=ismatch(r"set",iris[1,:Species] )
for i in 2:size(iris)[1]
foo=[foo; ismatch(r"set",iris[i,:Species] ) ]
end

参考までに正規表現では、始まりの検索は、r("^set") 、終りの検索は、r("set$") と書けば良いのです。(今回の例では、r("set$") は、全部 false になります。)

この Bool に対して、find() で、true の番号を返せば、R の grep() に相当する機能になるわけです。

では、はじめに定義した grep() の用法例です。


julia> iris[grep("set", iris[:Species]),:]
50×5 DataFrames.DataFrame
│ Row │ SepalLength │ SepalWidth │ PetalLength │ PetalWidth │ Species  │
├─────┼─────────────┼────────────┼─────────────┼────────────┼──────────┤
│ 1   │ 5.1         │ 3.5        │ 1.4         │ 0.2        │ "setosa" │
│ 2   │ 4.9         │ 3.0        │ 1.4         │ 0.2        │ "setosa" │
│ 3   │ 4.7         │ 3.2        │ 1.3         │ 0.2        │ "setosa" │
│ 4   │ 4.6         │ 3.1        │ 1.5         │ 0.2        │ "setosa" │
│ 5   │ 5.0         │ 3.6        │ 1.4         │ 0.2        │ "setosa" │
│ 6   │ 5.4         │ 3.9        │ 1.7         │ 0.4        │ "setosa" │
│ 7   │ 4.6         │ 3.4        │ 1.4         │ 0.3        │ "setosa" │
│ 8   │ 5.0         │ 3.4        │ 1.5         │ 0.2        │ "setosa" │
│ 9   │ 4.4         │ 2.9        │ 1.4         │ 0.2        │ "setosa" │
⋮
│ 41  │ 5.0         │ 3.5        │ 1.3         │ 0.3        │ "setosa" │
│ 42  │ 4.5         │ 2.3        │ 1.3         │ 0.3        │ "setosa" │
│ 43  │ 4.4         │ 3.2        │ 1.3         │ 0.2        │ "setosa" │
│ 44  │ 5.0         │ 3.5        │ 1.6         │ 0.6        │ "setosa" │
│ 45  │ 5.1         │ 3.8        │ 1.9         │ 0.4        │ "setosa" │
│ 46  │ 4.8         │ 3.0        │ 1.4         │ 0.3        │ "setosa" │
│ 47  │ 5.1         │ 3.8        │ 1.6         │ 0.2        │ "setosa" │
│ 48  │ 4.6         │ 3.2        │ 1.4         │ 0.2        │ "setosa" │
│ 49  │ 5.3         │ 3.7        │ 1.5         │ 0.2        │ "setosa" │
│ 50  │ 5.0         │ 3.3        │ 1.4         │ 0.2        │ "setosa" │

以上、R の grep 相当の動きをするはずです。

B! LINE