2017/1/3 追記: DataFrames.jl はAPIの互換性も一部失われる大規模な改修を行った v.0.9 のリリースを2017年の2月に予定しているそうです。この記事は v.0.6.10に基づいて書かれているので注意してください。時間が出来てなおかつ気が向いたら(おい)それに合わせて書き直すかもしれません。
ただ、ここのところあまり Julia を触る時間もなくて……。
前回の記事の続きです。前回はほとんどデータの中身も見ないまま終わってしまいましたが、気を取り直して今日は簡単な内容確認とか列の取り出し方とかについて書いていきます。
以下のコードの実行例では REPL には前回の内容で読み込んだデータが乗っているという前提です。
テーブルのサマリ
今回紹介しているどのライブラリ・言語にも「簡単なデータ構造の要約を返す」という関数が用意されているので、使ってみましょう。
Pandas:
>>> unique_artists.describe()
artist_id artist_mbid \
count 3888 3489
unique 3888 3488
top AROBQ0B1187FB404F6 2c0be2ba-fa63-430f-afca-7499852158f6
freq 1 2
track_id artist_name
count 3888 3888
unique 3888 3875
top TRAPGXH128F426D205 Bill & Gloria Gaither
freq 1 3
>>> artist_term.describe()
artist_id term
count 97493 97493
unique 3885 3502
top ARLYKKT11F4C83B350 rock
freq 91 2346
DataFrames.jl:
julia> DataFrames.describe(unique_artists)
artist_id
Length 3888
Type UTF8String
NAs 0
NA% 0.0%
Unique 3888
artist_mbid
Length 3888
Type UTF8String
NAs 399
NA% 10.26%
Unique 3489
track_id
Length 3888
Type UTF8String
NAs 0
NA% 0.0%
Unique 3888
artist_name
Length 3888
Type UTF8String
NAs 0
NA% 0.0%
Unique 3875
Julia> DataFrames.describe(artist_term)
artist_id
Length 97493
Type Nullable{UTF8String}
NAs 0
NA% 0.0%
Unique 3885
term
Length 97493
Type Nullable{UTF8String}
NAs 0
NA% 0.0%
Unique 3502
R:
> summary(unique_artists)
artist_id artist_mbid
AR009211187B989185: 1 : 399
AR00A6H1187FB5402A: 1 2c0be2ba-fa63-430f-afca-7499852158f6: 2
AR00LNI1187FB444A5: 1 001a1d90-56dc-4992-bd7d-970ecd7105d0: 1
AR00MBZ1187B9B5DB1: 1 001e4a87-fc46-4d66-ba37-e9714e0fe58a: 1
AR01IP11187B9AF5D2: 1 0039c7ae-e1a7-4a7d-9b49-0cbc716821a6: 1
AR01VU31187B997DA0: 1 0039cd9c-ea95-4553-86c4-4f729984cc2f: 1
(Other) :3882 (Other) :3483
track_id artist_name
TRAAAFD128F92F423A: 1 Bill & Gloria Gaither : 3
TRAAARJ128F9320760: 1 2-Gether feat. Sarinah : 2
TRAABCL128F4286650: 1 Abbott & Chambers : 2
TRAABJL12903CDCF1A: 1 Art Ensemble Of Chicago : 2
TRAABRB128F9306DD5: 1 Billy Price_ Fred Chapellier: 2
TRAABVM128F92CA9DC: 1 Eddie Palmieri : 2
(Other) :3882 (Other) :3875
> summary(artist_term)
artist_id term
Length:97493 Length:97493
Class :character Class :character
Mode :character Mode :character
Pandas も DataFrames.jl もユニークな要素や最頻値を出してくれたりするのは良いですね。R の方は上位何件かを見れるのですが、データの性質によっては意味が薄い感もあり。 DataFrames.jl は NA の比率を出してくれるのも良いです。
数値データのほうが表示結果が面白いというか有り難みが感じられるので、ちょっと例を出してみます。
>>> pandas.DataFrame({"a":range(1,11)}).describe()
a
count 10.00000
mean 5.50000
std 3.02765
min 1.00000
25% 3.25000
50% 5.50000
75% 7.75000
max 10.00000
julia> DataFrames.describe(DataFrames.DataFrame(a=1:10))
a
Min 1.0
1st Qu. 3.25
Median 5.5
Mean 5.5
3rd Qu. 7.75
Max 10.0
NAs 0
NA% 0.0%
> summary(seq(10))
Min. 1st Qu. Median Mean 3rd Qu. Max.
1.00 3.25 5.50 5.50 7.75 10.00
列単位のアクセス
ではとりあえず列の取り出し方を。unique_artists の 1 始まりで数えて 4 列目 "artist_name" の列を取り出すということをします。
Pandas は次の2つが同じ結果を返します。
>>> unique_artists.artist_name
0 Carroll Thompson
1 The Meatmen
2 Bruce BecVar
3 Memphis Minnie
4 Call To Preserve
5 Grand Funk
6 3OH!3
7 Ross
8 Annie Philippe
9 Tito Puente
10 Hi-Fi Companions
11 Delta 9
12 Bersuit Vergarabat
13 BT
14 John Williams
15 Britney Spears
16 Sylver
17 The Bug Featuring Ricky Ranking
18 Alexisonfire
19 Yellowcard
20 The Disposable Heroes Of Hiphoprisy
21 Dead Kennedys
22 Wilks featuring pee wee ellis
23 Mike Bloomfield
24 Roy Drusky
25 Alex Ubago
26 D'Molls
27 Kassav'
28 Ol' Dirty Bastard
29 Fudge Tunnel
...
3858 Smokin' Joe Kubek & Bnois King
3859 William Orbit
3860 Warner mack
3861 Biddu
3862 Ideal
3863 Reginaldo Bessa
3864 Rainbow
3865 Babylon Disco
3866 Mawatari Matsuko
3867 Widespread Bloodshed
3868 Top Of The Poppers
3869 Elliot Goldenthal
3870 Alexander Zonjic
3871 Jim Reeves
3872 Mister Ries
3873 Martriden
3874 Günter Noris
3875 Rise Against
3876 Henry Mancini
3877 Jason Michael Carroll
3878 Los Ninos De Sara
3879 Juelz Santana / Bezel
3880 Vaggelis Perpiniadis
3881 Davol
3882 John Stevens
3883 Taboo
3884 Mt. Wilson Repeater
3885 Chapta_ Stage McCloud_ SupaStarr & Tony Manshino
3886 Rooney
3887 Delroy Wilson
Name: artist_name, dtype: object
>>> unique_artists["artist_name"]
(略)
DataFrames.jl はこう書くようです。
unique_artists[:artist_name]
R だと次のようになります。(※ デフォルト状態の R の REPL で安易にこれを叩くと列の全部のデータを表示しにかかるので注意してください。)
unique_artists$artist_name
unique_artists[, "artist_name"]
えーと、R だけ[]の中に","が入ってるのが気になった方はいますか。いませんか。いるということにします。
「列を取り出す」と安易に書きましたが、上記は全て「データフレームの列を構成するデータ構造を取り出す」際の書き方です。「データフレームの列を構成するデータ構造」というのは Pandas なら Series、R なら vector、DataFrames.jl なら DataArray です。
これらは一列のデータフレームとは異なるので注意が要ります。適当にしていると、関数の返り値が data.frame だと思っていたら vector になっててあばばばーってなったりするので注意しましょう。
「一列のデータフレームを取り出す」場合はそれぞれ以下です。
Pandas:
unique_artists[["artist_name"]]
DataFrames.jl:
unique_artists[[:artist_name]]
R:
unique_artists["artist_name"]
unique_artists[, "artist_name", drop=F]
というか基本的には複数列を取り出す操作と一緒なのですが、R の場合は drop がデフォルトで TRUE になっているのがトラップだったりします。
複数列取り出す場合はそのまま取得する列名として渡している配列やらリストの要素を複数にすれば良くて、以下のようになります。
Pandas:
unique_artists[["artist_id", "artist_name"]]
DataFrames.jl:
unique_artists[[:artist_id, :artist_name]]
R:
unique_artists[c("artist_id", "artist_name")]
unique_artists[, c("artist_id", "artist_name"), drop=F]
特定の列を除く場合は以下です。
Pandas:
>>> unique_artists.drop(["track_id", "artist_mbid"], axis=1)
artist_id artist_name
0 AR009211187B989185 Carroll Thompson
1 AR00A6H1187FB5402A The Meatmen
2 AR00LNI1187FB444A5 Bruce BecVar
3 AR00MBZ1187B9B5DB1 Memphis Minnie
4 AR01IP11187B9AF5D2 Call To Preserve
5 AR01VU31187B997DA0 Grand Funk
6 AR01W2D1187FB5912F 3OH!3
7 AR022JO1187B99587B Ross
8 AR02DB61187B9A0B5E Annie Philippe
9 AR02IU11187FB513F2 Tito Puente
10 AR02KZG1187FB3B3B4 Hi-Fi Companions
11 AR02PUA1187FB52574 Delta 9
12 AR02YGA1187B9B8AC4 Bersuit Vergarabat
13 AR035N21187FB3938E BT
14 AR039B11187B9B30D0 John Williams
15 AR03BDP1187FB5B324 Britney Spears
16 AR03GWG1187B9B6C85 Sylver
17 AR040M31187B98CA41 The Bug Featuring Ricky Ranking
18 AR040QX1187FB4CFE1 Alexisonfire
19 AR048JZ1187B9AEB85 Yellowcard
20 AR04KTB1187B99B6B7 The Disposable Heroes Of Hiphoprisy
21 AR050VJ1187B9B13A7 Dead Kennedys
22 AR051KA1187B98B2FF Wilks featuring pee wee ellis
23 AR0569B1187B9A4036 Mike Bloomfield
24 AR059HI1187B9A14D7 Roy Drusky
25 AR05IU31187B9B9A1A Alex Ubago
26 AR05KQA1187B9963B3 D'Molls
27 AR05NQH1187B98E875 Kassav'
28 AR05OJD1187B9B99A6 Ol' Dirty Bastard
29 AR05VW21187FB407B4 Fudge Tunnel
... ... ...
3858 ARZRVFK11F4C83DF46 Smokin' Joe Kubek & Bnois King
3859 ARZS5VW1187FB567E8 William Orbit
3860 ARZSFIJ1187B98B8BC Warner mack
3861 ARZSTXE1187B99DD77 Biddu
3862 ARZTGQE1187FB461D9 Ideal
3863 ARZTSMH122988F522A Reginaldo Bessa
3864 ARZTSYB1187FB54987 Rainbow
3865 ARZU9NI1187B9AEE08 Babylon Disco
3866 ARZUVRN1269FB3759D Mawatari Matsuko
3867 ARZUZYU12086C17110 Widespread Bloodshed
3868 ARZVBBM1241B9CB622 Top Of The Poppers
3869 ARZVEF91187B9AC770 Elliot Goldenthal
3870 ARZVJ641187FB36FA4 Alexander Zonjic
3871 ARZVTZN1187FB579D4 Jim Reeves
3872 ARZVZRN1241B9C4B14 Mister Ries
3873 ARZWAHK119B8668273 Martriden
3874 ARZWBH21187B99ACE1 Günter Noris
3875 ARZWK2R1187B98F09F Rise Against
3876 ARZWPWP1241B9CA793 Henry Mancini
3877 ARZXLZD11E2835CEA7 Jason Michael Carroll
3878 ARZXMYV1187FB5B99B Los Ninos De Sara
3879 ARZXTEY1187B9997A7 Juelz Santana / Bezel
3880 ARZXTUO12509411DAE Vaggelis Perpiniadis
3881 ARZXVY01187B9972EC Davol
3882 ARZXYRK1187B99E432 John Stevens
3883 ARZY28S1187FB40BAB Taboo
3884 ARZYFWI11F4C84225B Mt. Wilson Repeater
3885 ARZYP6O1187B9892E7 Chapta_ Stage McCloud_ SupaStarr & Tony Manshino
3886 ARZYPLF1187FB45B9B Rooney
3887 ARZZRK91187B9A5CA5 Delroy Wilson
[3888 rows x 2 columns]
Pandas の drop は inplace=True を指定しなかった場合には非破壊的で、drop メソッドを呼び出したあとも DataFrame から列が削除されるということはありません。
このように非破壊的に特定の列を除くという操作を行う関数がどうも DataFrames.jl や R には無いようです。(下記のような関数を自分で定義すればいいといえばそうですが)
DataFrames.jl では内包表記なりなんなりで残したい列だけ true になる bool 配列を作ってしまうのが良いようです。
cf: http://stackoverflow.com/questions/24665439/julia-dataframe-remove-column-by-name
julia> unique_artists[~[(x in [:artist_mbid, :track_id]) for x in names(unique_artists)]]
3888x2 DataFrames.DataFrame
| Row | artist_id |
|------|----------------------|
| 1 | "AR009211187B989185" |
| 2 | "AR00A6H1187FB5402A" |
| 3 | "AR00LNI1187FB444A5" |
| 4 | "AR00MBZ1187B9B5DB1" |
| 5 | "AR01IP11187B9AF5D2" |
| 6 | "AR01VU31187B997DA0" |
| 7 | "AR01W2D1187FB5912F" |
| 8 | "AR022JO1187B99587B" |
⋮
| 3880 | "ARZXTEY1187B9997A7" |
| 3881 | "ARZXTUO12509411DAE" |
| 3882 | "ARZXVY01187B9972EC" |
| 3883 | "ARZXYRK1187B99E432" |
| 3884 | "ARZY28S1187FB40BAB" |
| 3885 | "ARZYFWI11F4C84225B" |
| 3886 | "ARZYP6O1187B9892E7" |
| 3887 | "ARZYPLF1187FB45B9B" |
| 3888 | "ARZZRK91187B9A5CA5" |
| Row | artist_name |
|------|----------------------------------------------------|
| 1 | "Carroll Thompson" |
| 2 | "The Meatmen" |
| 3 | "Bruce BecVar" |
| 4 | "Memphis Minnie" |
| 5 | "Call To Preserve" |
| 6 | "Grand Funk" |
| 7 | "3OH!3" |
| 8 | "Ross" |
⋮
| 3880 | "Juelz Santana / Bezel" |
| 3881 | "Vaggelis Perpiniadis" |
| 3882 | "Davol" |
| 3883 | "John Stevens" |
| 3884 | "Taboo" |
| 3885 | "Mt. Wilson Repeater" |
| 3886 | "Chapta_ Stage McCloud_ SupaStarr & Tony Manshino" |
| 3887 | "Rooney" |
| 3888 | "Delroy Wilson" |
julia> # destructive
julia> # DataFrames.delete!(unique_artists, [:artist_mbid, :track_id])
R の場合も発想は一緒です。
> unique_artists[!names(unique_artists) %in% c("artist_mbid", "track_id")]
(略)
> # destructive
> # unique_artists$artist_mbid <- NULL
> # unique_artists$track_id <- NULL
スライスとか言って列のアクセス方法までしか書いてませんが、今回はこの辺りで。
環境:
- OS: Manjaro Linux
- Python: 3.5.0
- pandas: 0.17.1
- R: 3.2.2
- RSQLite 1.0.0
- Julia: 0.4.0
- DataFrames: 0.6.10
- DataStreams: 0.0.3
- SQLite: 0.3.0