はじめに
deepblueインターン生の中山です。
【読み込み、要約統計量、行・列選択、代入】PythonとRのデータフレーム操作比較 vol.1の続きです。
列追加、重複削除、列名変更、結合、集約について、tidyverse
を用いたRとPythonの比較をしたいと思います。
連載
- 下記5記事のまとめ:PythonのpandasとRのdplyrを用いたデータフレーム操作比較
- 【読み込み、要約統計量、行・列選択、代入】PythonとRのデータフレーム操作比較 vol.1
- 【列追加、重複削除、列名変更、結合、マージ、集約】PythonとRのデータフレーム操作比較 vol.2
- 【集計、ソート、縦持ち・横持ち変換】PythonとRのデータフレーム操作比較 vol.3
- 【列分割・NA操作・サンプリング】PythonとRのデータフレーム操作比較 vol.4
- 【train/test分割】PythonとRのデータフレーム操作比較 vol.5
利用したデータ
使ったデータは、MineThatData E-Mail Analytics And Data Mining Challenge datasetです。
前回のblogとデータは同じです。本記事では、history
を3000
以上に条件付けている事が多いですが、データ数を減らして確認しやすくしているだけで、深い意味はないです。
データ読み込み
csvデータを読み込むコード。
head
で10
個確認しています。
Python
import pandas as pd
PATH = "http://www.minethatdata.com/Kevin_Hillstrom_MineThatData_E-MailAnalytics_DataMiningChallenge_2008.03.20.csv"
df = pd.read_csv(PATH)
df.head(10)
# recency history_segment history mens womens zip_code newbie channel segment visit conversion spend
# 0 10 2) $100 - $200 142.44 1 0 Surburban 0 Phone Womens E-Mail 0 0 0.0
# 1 6 3) $200 - $350 329.08 1 1 Rural 1 Web No E-Mail 0 0 0.0
# 2 7 2) $100 - $200 180.65 0 1 Surburban 1 Web Womens E-Mail 0 0 0.0
# 3 9 5) $500 - $750 675.83 1 0 Rural 1 Web Mens E-Mail 0 0 0.0
# 4 2 1) $0 - $100 45.34 1 0 Urban 0 Web Womens E-Mail 0 0 0.0
# 5 6 2) $100 - $200 134.83 0 1 Surburban 0 Phone Womens E-Mail 1 0 0.0
# 6 9 3) $200 - $350 280.20 1 0 Surburban 1 Phone Womens E-Mail 0 0 0.0
# 7 9 1) $0 - $100 46.42 0 1 Urban 0 Phone Womens E-Mail 0 0 0.0
# 8 9 5) $500 - $750 675.07 1 1 Rural 1 Phone Mens E-Mail 0 0 0.0
# 9 10 1) $0 - $100 32.84 0 1 Urban 1 Web Womens E-Mail 0 0 0.0
R
library(tidyverse)
PATH <- "http://www.minethatdata.com/Kevin_Hillstrom_MineThatData_E-MailAnalytics_DataMiningChallenge_2008.03.20.csv"
df <- read.csv(PATH)
head(df, 10)
# df %>% head(10) # こちらでも可
# recency history_segment history mens womens zip_code newbie channel segment visit conversion spend
# 1 10 2) $100 - $200 142.44 1 0 Surburban 0 Phone Womens E-Mail 0 0 0
# 2 6 3) $200 - $350 329.08 1 1 Rural 1 Web No E-Mail 0 0 0
# 3 7 2) $100 - $200 180.65 0 1 Surburban 1 Web Womens E-Mail 0 0 0
# 4 9 5) $500 - $750 675.83 1 0 Rural 1 Web Mens E-Mail 0 0 0
# 5 2 1) $0 - $100 45.34 1 0 Urban 0 Web Womens E-Mail 0 0 0
# 6 6 2) $100 - $200 134.83 0 1 Surburban 0 Phone Womens E-Mail 1 0 0
# 7 9 3) $200 - $350 280.20 1 0 Surburban 1 Phone Womens E-Mail 0 0 0
# 8 9 1) $0 - $100 46.42 0 1 Urban 0 Phone Womens E-Mail 0 0 0
# 9 9 5) $500 - $750 675.07 1 1 Rural 1 Phone Mens E-Mail 0 0 0
# 10 10 1) $0 - $100 32.84 0 1 Urban 1 Web Womens E-Mail 0 0 0
vol.1でやった事
前回のblogの後半部分で扱った内容を1つにまとめます。
列の選択、行の抽出、値の置換の3つです。
Python
df_new = df[["recency", "history", "zip_code", "channel", "spend"]]
df_new = df_new[df_new.history > 3000].assign(spend = 1000)
# df_new
# recency history zip_code channel spend
# 4579 2 3345.93 Surburban Phone 1000
# 38680 1 3215.97 Urban Multichannel 1000
# 43060 1 3003.48 Urban Phone 1000
# 52860 1 3040.20 Urban Web 1000
R
df_new <- df %>%
select(recency, history, zip_code, channel, spend) %>%
filter(history > 3000) %>%
mutate(spend = 1000)
# df_new
# recency history zip_code channel spend
# 1 2 3345.93 Surburban Phone 1000
# 2 1 3215.97 Urban Multichannel 1000
# 3 1 3003.48 Urban Phone 1000
# 4 1 3040.20 Urban Web 1000
列追加
新たな列を追加するコード。
上記では、データの置換を実行しましたが、ここでは新たな列を追加します。
下記コードでは、df_selected
に抽出結果を格納し、df_selected
に列を追加したものがdf_new
となっています。
Python
df["col"] = df.mutate.apply(lambda x: x.hoge * x.fuga, axis=1)
df_selected = df[["recency", "history", "zip_code", "channel", "spend"]]
df_selected = df_selected[df_selected.history > 3000]
df_new = df_selected.copy()
df_new["col"] = df_new.apply(lambda x: x.recency * x.history, axis=1)
# df_new["col"] = df_new.recency * df_new.history # こちらでも可
# df_new
# recency history zip_code channel spend col
# 4579 2 3345.93 Surburban Phone 0.0 6691.86
# 38680 1 3215.97 Urban Multichannel 0.0 3215.97
# 43060 1 3003.48 Urban Phone 0.0 3003.48
# 52860 1 3040.20 Urban Web 0.0 3040.20
R
df %>% mutate(col = hoge * fuga)
df_selected <- df %>%
select(recency, history, zip_code, channel, spend) %>%
filter(history > 3000)
df_new <- df_selected %>%
mutate(col = recency * history)
# df_new
# recency history zip_code channel spend col
# 1 2 3345.93 Surburban Phone 0 6691.86
# 2 1 3215.97 Urban Multichannel 0 3215.97
# 3 1 3003.48 Urban Phone 0 3003.48
# 4 1 3040.20 Urban Web 0 3040.20
重複削除
データフレームの重複を削除するコード。
ここでは、channel
列の重複を削除しています。
Python
drop_duplicates()
df_new = df.channel.drop_duplicates()
# df_new
# 0 Phone
# 1 Web
# 12 Multichannel
# Name: channel, dtype: object
R
distinct()
df_new <- df %>%
distinct(channel)
# df_new
# channel
# 1 Phone
# 2 Web
# 3 Multichannel
列名変更
列名を変更するコード。
PythonとRでは、hoge
とfuga
の書く順番が違うため注意が必要です。
Python
rename(columns={"hoge" : "fuga"})
df_new = df.rename(columns={"recency":"RECENCY"})
# df_new.head()
# RECENCY history_segment history mens womens zip_code newbie channel segment visit conversion spend
# 0 10 2) $100 - $200 142.44 1 0 Surburban 0 Phone Womens E-Mail 0 0 0.0
# 1 6 3) $200 - $350 329.08 1 1 Rural 1 Web No E-Mail 0 0 0.0
# 2 7 2) $100 - $200 180.65 0 1 Surburban 1 Web Womens E-Mail 0 0 0.0
# 3 9 5) $500 - $750 675.83 1 0 Rural 1 Web Mens E-Mail 0 0 0.0
# 4 2 1) $0 - $100 45.34 1 0 Urban 0 Web Womens E-Mail 0 0 0.0
R
rename(fuga = hoge)
df_new <- df %>%
rename(RECENCY = recency)
# df_new %>% head()
# RECENCY history_segment history mens womens zip_code newbie channel segment visit conversion spend
# 1 10 2) $100 - $200 142.44 1 0 Surburban 0 Phone Womens E-Mail 0 0 0
# 2 6 3) $200 - $350 329.08 1 1 Rural 1 Web No E-Mail 0 0 0
# 3 7 2) $100 - $200 180.65 0 1 Surburban 1 Web Womens E-Mail 0 0 0
# 4 9 5) $500 - $750 675.83 1 0 Rural 1 Web Mens E-Mail 0 0 0
# 5 2 1) $0 - $100 45.34 1 0 Urban 0 Web Womens E-Mail 0 0 0
# 6 6 2) $100 - $200 134.83 0 1 Surburban 0 Phone Womens E-Mail 1 0 0
データの列結合
データフレームを列どうしで結合するコード。
df
をdf1
とdf2
に分割し、列結合をしています。
Python
concat([df1, df2], axis=1)
df1 = df[["recency", "history", "zip_code"]]
df2 = df[["channel", "spend"]]
df_new = pd.concat([df1, df2], axis=1)
# df_new.head()
# recency history zip_code channel spend
# 0 10 142.44 Surburban Phone 0.0
# 1 6 329.08 Rural Web 0.0
# 2 7 180.65 Surburban Web 0.0
# 3 9 675.83 Rural Web 0.0
# 4 2 45.34 Urban Web 0.0
R
bind_cols(df1, df2)
df1 <- df %>%
select(recency, history, zip_code)
df2 <- df %>%
select(channel, spend)
df_new <- df1 %>%
bind_cols(df2)
# tidyverseを利用しない場合
df_new <- cbind(df1, df2)
# df_new %>% head()
# recency history zip_code channel spend
# 1 10 142.44 Surburban Phone 0
# 2 6 329.08 Rural Web 0
# 3 7 180.65 Surburban Web 0
# 4 9 675.83 Rural Web 0
# 5 2 45.34 Urban Web 0
# 6 6 134.83 Surburban Phone 0
データの行結合
データフレームを行どうしで結合するコード。
df
をdf1
とdf2
に分割し、行結合をしています。
Python
concat([df1, df2], axis=0)
df1 = df[df.history > 3000]
df2 = df[df.history == 30]
df_new = pd.concat([df1, df2], axis=0)
# df_new
# recency history_segment history mens womens zip_code newbie channel segment visit conversion spend
# 4579 2 7) $1,000 + 3345.93 1 1 Surburban 1 Phone No E-Mail 0 0 0.0
# 38680 1 7) $1,000 + 3215.97 1 1 Urban 1 Multichannel Mens E-Mail 1 0 0.0
# 43060 1 7) $1,000 + 3003.48 1 1 Urban 1 Phone No E-Mail 0 0 0.0
# 52860 1 7) $1,000 + 3040.20 0 1 Urban 1 Web Womens E-Mail 0 0 0.0
# 8645 9 1) $0 - $100 30.00 1 0 Rural 0 Phone No E-Mail 0 0 0.0
# 56175 10 1) $0 - $100 30.00 1 0 Surburban 0 Phone Mens E-Mail 0 0 0.0
R
bind_rows(df1, df2)
df1 <- df %>%
filter(history > 3000)
df2 <- df %>%
filter(history == 30)
df_new <- df1 %>%
bind_rows(df2)
# tidyverseを利用しない場合
df_new <- rbind(df1, df2)
# df_new
# recency history_segment history mens womens zip_code newbie channel segment visit conversion spend
# 1 2 7) $1,000 + 3345.93 1 1 Surburban 1 Phone No E-Mail 0 0 0
# 2 1 7) $1,000 + 3215.97 1 1 Urban 1 Multichannel Mens E-Mail 1 0 0
# 3 1 7) $1,000 + 3003.48 1 1 Urban 1 Phone No E-Mail 0 0 0
# 4 1 7) $1,000 + 3040.20 0 1 Urban 1 Web Womens E-Mail 0 0 0
# 5 9 1) $0 - $100 30.00 1 0 Rural 0 Phone No E-Mail 0 0 0
# 6 10 1) $0 - $100 30.00 1 0 Surburban 0 Phone Mens E-Mail 0 0 0
列のマージ
データフレームを列でマージするコード。
df
をdf1
とdf2
に分割し、index
をキーとして内部結合しています。
Python
pd.merge(df1, df2, on = "hoge", how = "inner")
how = "inner"
の他にもleft
, right
, outer
などがあります。
df1 = df.reset_index().loc[df.history > 3000,
["index", "recency", "history", "zip_code"]]
df2 = df.reset_index().loc[:, ["index", "channel", "spend"]]
df_new = pd.merge(df1, df2, on = "index", how = "inner")
# df_new
# index recency history zip_code channel spend
# 0 4579 2 3345.93 Surburban Phone 0.0
# 1 38680 1 3215.97 Urban Multichannel 0.0
# 2 43060 1 3003.48 Urban Phone 0.0
# 3 52860 1 3040.20 Urban Web 0.0
R
inner_join(df1, df2, by = "hoge")
inner_join
の他にもleft_join
, right_join
, full_join
などがあります。
df1 <- df %>%
rowid_to_column("index") %>%
filter(history > 3000) %>%
select(index, recency, history, zip_code)
df2 <- df %>%
rowid_to_column("index") %>%
select(index, channel, spend)
df_new <- df1 %>%
inner_join(df2, by = "index")
# df_new
# index recency history zip_code channel spend
# 1 4580 2 3345.93 Surburban Phone 0
# 2 38681 1 3215.97 Urban Multichannel 0
# 3 43061 1 3003.48 Urban Phone 0
# 4 52861 1 3040.20 Urban Web 0
データの集約
groupby
でデータを分けて全列の統計量を算出するコード。
ここでは、df
のchannel
でグルーピングして、各列の平均値を算出しています。
Python
groupby("hoge")
df_new = df.groupby("channel").mean()
# df_new
# recency history mens womens newbie visit conversion spend
# channel
# Multichannel 4.768488 520.970370 0.632698 0.624195 0.595723 0.171734 0.012626 1.401777
# Phone 5.897541 202.807184 0.539203 0.538953 0.493309 0.127155 0.007744 0.908892
# Web 5.904632 204.375017 0.540313 0.539923 0.485417 0.159407 0.009321 1.095420
R
group_by(hoge)
df_new <- df %>%
group_by(channel) %>%
summarise_all(funs(mean))
# df_new
# channel recency history_segment history mens womens zip_code newbie segment visit conversion spend
# <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1 Multichannel 4.77 NA 521. 0.633 0.624 NA 0.596 NA 0.172 0.0126 1.40
# 2 Phone 5.90 NA 203. 0.539 0.539 NA 0.493 NA 0.127 0.00774 0.909
# 3 Web 5.90 NA 204. 0.540 0.540 NA 0.485 NA 0.159 0.00932 1.10