データサイエンス100本ノック(構造化データ加工編)- R Part 5 (Q81 to Q100)の解説です。
参照(Reference) : 「データサイエンティスト協会スキル定義委員」の「データサイエンス100本ノック(構造化データ加工編)」
The Data Scientist Society Github :
Data Science 100 Knocks (Structured Data Processing) URL :
はじめに
- 初めに以下のセルを実行してください
- 必要なライブラリのインポートとデータベース(PostgreSQL)からのデータ読み込みを行います
- 利用が想定されるライブラリは以下セルでインポートしています
- その他利用したいライブラリがあればinstall.packages()で適宜インストールしてください
- 名前、住所等はダミーデータであり、実在するものではありません
require("RPostgreSQL")
require("tidyr")
require("dplyr")
require("stringr")
require("caret")
require("lubridate")
require("rsample")
require("recipes")
require("themis")
host <- "db"
port <- Sys.getenv()["PG_PORT"]
dbname <- Sys.getenv()["PG_DATABASE"]
user <- Sys.getenv()["PG_USER"]
password <- Sys.getenv()["PG_PASSWORD"]
con <- dbConnect(PostgreSQL(), host=host, port=port, dbname=dbname, user=user, password=password)
df_customer <- dbGetQuery(con,"SELECT * FROM customer")
df_category <- dbGetQuery(con,"SELECT * FROM category")
df_product <- dbGetQuery(con,"SELECT * FROM product")
df_receipt <- dbGetQuery(con,"SELECT * FROM receipt")
df_store <- dbGetQuery(con,"SELECT * FROM store")
df_geocode <- dbGetQuery(con,"SELECT * FROM geocode")
Loading required package: RPostgreSQL Loading required package: DBI Loading required package: tidyr Loading required package: dplyr Attaching package: ‘dplyr’ The following objects are masked from ‘package:stats’: filter, lag The following objects are masked from ‘package:base’: intersect, setdiff, setequal, union Loading required package: stringr Loading required package: caret Loading required package: ggplot2 Loading required package: lattice Loading required package: lubridate Attaching package: ‘lubridate’ The following objects are masked from ‘package:base’: date, intersect, setdiff, union Loading required package: rsample Loading required package: recipes Attaching package: ‘recipes’ The following object is masked from ‘package:stringr’: fixed The following object is masked from ‘package:stats’: step Loading required package: themis Registered S3 methods overwritten by 'themis': method from bake.step_downsample recipes bake.step_upsample recipes prep.step_downsample recipes prep.step_upsample recipes tidy.step_downsample recipes tidy.step_upsample recipes tunable.step_downsample recipes tunable.step_upsample recipes Attaching package: ‘themis’ The following objects are masked from ‘package:recipes’: step_downsample, step_upsample
演習問題
R-081: 単価(unit_price)と原価(unit_cost)の欠損値について、それぞれの平均値で補完した新たな商品データを作成せよ。なお、平均値については1円未満を丸めること(四捨五入または偶数への丸めで良い)。補完実施後、各項目について欠損が生じていないことも確認すること。
price_mean <- round(mean(df_product$unit_price, na.rm = TRUE))
cost_mean <- round(mean(df_product$unit_cost, na.rm = TRUE))
df_product_2 <- df_product %>%
replace_na(list(unit_price = price_mean, unit_cost = cost_mean))
sapply(df_product_2, function(x) sum(is.na(x)))
- product_cd
- 0
- category_major_cd
- 0
- category_medium_cd
- 0
- category_small_cd
- 0
- unit_price
- 0
- unit_cost
- 0
解説:
このコードは以下の動作を行う。
データフレーム 'df_product' の 'unit_price' と 'unit_cost' 列の平均を計算し、結果を最も近い整数に丸める。
price_mean <- round(mean(df_product$unit_price, na.rm = TRUE)) cost_mean <- round(mean(df_product$unit_cost, na.rm = TRUE))
round() 関数は、平均値を最も近い整数に丸めるために使用される。
na.rm=TRUE は、計算から欠損値を取り除くために使用される。
df_product' の 'unit_price' と 'unit_cost' 列の欠損値をそれぞれの平均値で置き換えます。
df_product_2 <- df_product %>% replace_na(list(unit_price = price_mean, unit_cost = cost_mean))
replace_na() は 'tidyr' パッケージから、欠損値を先に計算した平均値に置き換えるために使用されます。
演算子 %>% (パイプ演算子としても知られている) は、2つのアクションを一緒に連鎖させるために使用され、最初のアクションの出力は、2番目のアクションの入力として使用されます。
sapply()関数を使用して、修正した「df_product_2」データフレームの各列における欠損値の数を計算します。
sapply(df_product_2, function(x) sum(is.na(x)))
sapply()関数は、'df_product_2'データフレームの各列に関数(function(x) sum(is.na(x)) )を適用するために使用されます。
関数のsum(is.na(x))の部分は、'df_product_2'データフレームの各列(x)において、欠損値(NA)の数をカウントする。
R-082: 単価(unit_price)と原価(unit_cost)の欠損値について、それぞれの中央値で補完した新たな商品データを作成せよ。なお、中央値については1円未満を丸めること(四捨五入または偶数への丸めで良い)。補完実施後、各項目について欠損が生じていないことも確認すること。
price_median <- round(median(df_product$unit_price, na.rm = TRUE))
cost_median <- round(median(df_product$unit_cost, na.rm = TRUE))
df_product_3 <- df_product %>%
replace_na(list(unit_price = price_median, unit_cost = cost_median))
sapply(df_product_3, function(x) sum(is.na(x)))
- product_cd
- 0
- category_major_cd
- 0
- category_medium_cd
- 0
- category_small_cd
- 0
- unit_price
- 0
- unit_cost
- 0
解説:
このコードは以下の動作を行います。
データフレーム 'df_product' の 'unit_price' と 'unit_cost' 列の中央値を計算し、結果を最も近い整数に丸める。
price_median <- round(median(df_product$unit_price, na.rm = TRUE)) cost_median <- round(median(df_product$unit_cost, na.rm = TRUE))
median()関数は、'unit_price' および 'unit_cost' 列の中央値を計算するために使用される。
round() 関数は、中央値を最も近い整数に丸めるために使用されます。
na.rm=TRUE は、計算から欠損値を取り除くために使用されます。
df_product' の 'unit_price' と 'unit_cost' カラムの欠損値をそれぞれの中央値で置き換えます。
df_product_3 <- df_product %>% replace_na(list(unit_price = price_median, unit_cost = cost_median))
replace_na() は 'tidyr' パッケージのもので、欠損値を先に計算した中央値で置き換えるために使用される
演算子%>%(パイプ演算子としても知られている)を使用して、2つのアクションを連鎖させ、最初のアクションの出力を2番目のアクションの入力として使用します。
sapply()関数を使用して、修正した「df_product_3」データフレームの各列における欠損値の数を計算します。
sapply(df_product_3, function(x) sum(is.na(x)))
sapply()関数は、'df_product_3'データフレームの各列に関数(function(x) sum(is.na(x)) )を適用するために使用されます。
関数のsum(is.na(x))の部分は、'df_product_3'データフレームの各列(x)において、欠損値(NA)の数をカウントする。
R-083: 単価(unit_price)と原価(unit_cost)の欠損値について、各商品のカテゴリ小区分コード(category_small_cd)ごとに算出した中央値で補完した新たな商品データを作成せよ。なお、中央値については1円未満を丸めること(四捨五入または偶数への丸めで良い)。補完実施後、各項目について欠損が生じていないことも確認すること。
df_product_4 <- df_product %>%
group_by(category_small_cd) %>%
summarise(price_median = round(median(unit_price, na.rm = TRUE)), cost_median = round(median(unit_cost, na.rm = TRUE)), .groups = "drop") %>%
inner_join(df_product, by = "category_small_cd") %>%
mutate(unit_price = ifelse(is.na(unit_price), price_median, unit_price), unit_cost = ifelse(is.na(unit_cost), cost_median, unit_cost)) sapply(df_product_4, function(x) sum(is.na(x)))
- category_small_cd
- 0
- price_median
- 0
- cost_median
- 0
- product_cd
- 0
- category_major_cd
- 0
- category_medium_cd
- 0
- unit_price
- 0
- unit_cost
- 0
解説:
このコードは、以下の動作を行います。
df_product'データフレームを'category_small_cd'カラムでグループ化する。
df_product_4 <- df_product %>% group_by(category_small_cd)
演算子%>%は、2つのアクションを連鎖させるために使用され、最初のアクションの出力は、2番目のアクションの入力として使用されます。
dplyr' パッケージの 'group_by()' 関数を使用して、'df_product' データフレームを 'category_small_cd' 列でグループ化する。
グループ化されたデータフレームの各グループの 'unit_price' と 'unit_cost' 列の中央値を計算し、結果を最も近い整数に丸め、結果を新しいデータフレームに要約します。
summarise(price_median = round(median(unit_price, na.rm = TRUE)), cost_median = round(median(unit_cost, na.rm = TRUE)), .groups = "drop")
'summarise()'関数は'dplyr'パッケージから使用し、グループ化したデータフレームの各グループの'unit_price'と'unit_cost'の列の中央値を算出する。
'round()'関数は、中央値を最も近い整数に丸めるために使用される。
na.rm=TRUEは、計算から欠損値を取り除くために使用されます。
.groups="drop" 引数は、出力からグループ化情報を削除するために使用されます。
要約されたデータフレームと元の 'df_product' データフレームを 'category_small_cd' カラムで結合する。
inner_join(df_product, by = "category_small_cd")
inner_join()」関数は、「dplyr」パッケージから使用され、「category_small_cd」列によって、要約データフレームと元の「df_product」データフレームを結合します。
結果として得られるデータフレームは、両方のデータフレームからすべての列を持つことになります。
結合したデータフレームの 'unit_price' と 'unit_cost' 列の欠損値を、対応する 'category_small_cd' グループのそれぞれの中央値で置き換えます。
mutate(unit_price = ifelse(is.na(unit_price), price_median, unit_price), unit_cost = ifelse(is.na(unit_cost), cost_median, unit_cost))
mutate()' 関数は、'dplyr' パッケージから、結合したデータフレームに値を変更した新しい列を作成するために使用されます。
ifelse() 関数は、'unit_price' と 'unit_cost' 列で値が欠損(NA)しているかどうかをチェックし、その値が属する 'category_small_cd' グループの対応する中央値で置き換えるために使用される。
sapply()関数を使用して、変更後の'df_product_4'データフレームの各列における欠損値の数を計算する。
sapply(df_product_4, function(x) sum(is.na(x)))
sapply()関数は、'df_product_4'データフレームの各列に関数(function(x) sum(is.na(x)) )を適用するために使用されます。
関数のsum(is.na(x))の部分は、'df_product_4'データフレームの各列(x)において、欠損値(NA)の数をカウントする。
R-084: 顧客データ(df_customer)の全顧客に対して全期間の売上金額に占める2019年売上金額の割合を計算し、新たなデータを作成せよ。ただし、売上実績がない場合は0として扱うこと。そして計算した割合が0超のものを抽出し、結果を10件表示せよ。また、作成したデータに欠損が存在しないことを確認せよ。
df_receipt_2019 <- df_receipt %>%
filter(20190101 <= sales_ymd & sales_ymd <= 20191231) %>%
group_by(customer_id) %>% summarise(amount_2019 = sum(amount), .groups = "drop")
df_receipt_all <- df_receipt %>%
group_by(customer_id) %>%
summarise(amount_all = sum(amount), .groups = "drop")
df_sales_rate <- left_join(df_customer["customer_id"], df_receipt_2019, by = "customer_id") %>%
left_join(df_receipt_all, by = "customer_id") %>%
replace_na(list(amount_2019 = 0, amount_all = 0)) %>%
mutate(amount_rate = ifelse(amount_all == 0, 0, amount_2019 / amount_all)) df_sales_rate %>% filter(amount_rate > 0) %>%
slice(1:10)
customer_id | amount_2019 | amount_all | amount_rate |
---|---|---|---|
<chr> | <dbl> | <dbl> | <dbl> |
CS031415000172 | 2971 | 5088 | 0.58392296 |
CS015414000103 | 874 | 3122 | 0.27994875 |
CS011215000048 | 248 | 3444 | 0.07200929 |
CS029415000023 | 3767 | 5167 | 0.72904974 |
CS035415000029 | 5823 | 7504 | 0.77598614 |
CS023513000066 | 208 | 771 | 0.26977951 |
CS035513000134 | 463 | 1565 | 0.29584665 |
CS001515000263 | 216 | 216 | 1.00000000 |
CS006415000279 | 229 | 229 | 1.00000000 |
CS031415000106 | 215 | 7741 | 0.02777419 |
sapply(df_receipt_2019, function(x) sum(is.na(x)))
- customer_id
- 0
- amount_2019
- 0
解説:
このコードでは、df_receiptというデータ・フレームに対していくつかのデータ操作を行なっていますが、このデータ・フレームには売上取引に関する情報が含まれていると思われます。以下は、各コードの行が何を行っているのかの内訳です。
df_receipt_2019 <- df_receipt %>% filter(20190101 <= sales_ymd & sales_ymd <= 20191231) %>% group_by(customer_id) %>% summise(amount_2019 = sum(amount), .groups = "drop")
このコード行は、df_receipt_2019という新しいデータフレームを作成し、元のdf_receiptデータフレームをフィルタリングして2019年1月1日から2019年12月31日の間に発生した販売取引のみを含むようにします。そして、customer_idでデータをグループ化し、その期間に各顧客が使った金額の合計を計算し、結果をamount_2019という新しい列に格納します。
df_receipt_all <- df_receipt %>% group_by(customer_id) %>% summise(amount_all = sum(amount), .groups = "drop")
このコードでは、df_receipt_allという新しいデータフレームを作成し、df_receiptデータフレームをcustomer_idでグループ化して、各顧客がすべての取引で使った合計金額を計算し、結果をamount_allという新しい列に保存しています。
df_sales_rate <- left_join(df_customer["customer_id"], df_receipt_2019, by = "customer_id") %>% left_join(df_receipt_all, by = "customer_id") %>% replace_na(list(quantity_2019 = 0, amount_all = 0)) %>% mutate(amount_rate = ifelse(amount_all == 0, 0, amount_2019 / amount_all)) %>% filter(amount_rate > 0) %>% slice(1: 10)
このコードでは、df_customer データフレーム(顧客の属性に関する情報が含まれている可能性が高い)と df_receipt_2019 および df_receipt_all データフレームを customer_id 列で結合して df_sales_rate という新しいデータフレームを作成しています。次に、amount_2019とamount_all列の欠損値を0に置き換え、2019年に発生した顧客の総支出の割合を表すamount_rateという新しい列を計算し(すなわちamount_2019 / amount_all)、2019年にお金を使った顧客のみを含むようにデータをフィルタリングし(すなわちamount_rate > 0)、最後にamount_rate値によって上位10名の顧客を選択する(すなわちslice(1:10) )。
全体として、このコードは、2019年に総支出の割合が最も高い上位10名の顧客を特定しており、ターゲットマーケティングや顧客維持の取り組みに役立つと考えられます。
R-085: 顧客データ(df_customer)の全顧客に対し、郵便番号(postal_cd)を用いてジオコードデータ(df_geocode)を紐付け、新たな顧客データを作成せよ。ただし、1つの郵便番号(postal_cd)に複数の経度(longitude)、緯度(latitude)情報が紐づく場合は、経度(longitude)、緯度(latitude)の平均値を算出して使用すること。また、作成結果を確認するために結果を10件表示せよ。
df_geocode_1 <- df_geocode[c("postal_cd", "longitude" ,"latitude")] %>% group_by(postal_cd) %>%
summarise(m_longiture = mean(longitude), m_latitude = mean(latitude), .groups = "drop")
df_customer_1 <- inner_join(df_customer, df_geocode_1, by = "postal_cd") head(df_customer_1, 10)
customer_id | customer_name | gender_cd | gender | birth_day | age | postal_cd | address | application_store_cd | application_date | status_cd | m_longiture | m_latitude | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
<chr> | <chr> | <chr> | <chr> | <date> | <int> | <chr> | <chr> | <chr> | <chr> | <chr> | <dbl> | <dbl> | |
1 | CS021313000114 | 大野 あや子 | 1 | 女性 | 1981-04-29 | 37 | 259-1113 | 神奈川県伊勢原市粟窪********** | S14021 | 20150905 | 0-00000000-0 | 139.3178 | 35.41358 |
2 | CS037613000071 | 六角 雅彦 | 9 | 不明 | 1952-04-01 | 66 | 136-0076 | 東京都江東区南砂********** | S13037 | 20150414 | 0-00000000-0 | 139.8350 | 35.67193 |
3 | CS031415000172 | 宇多田 貴美子 | 1 | 女性 | 1976-10-04 | 42 | 151-0053 | 東京都渋谷区代々木********** | S13031 | 20150529 | D-20100325-C | 139.6897 | 35.67374 |
4 | CS028811000001 | 堀井 かおり | 1 | 女性 | 1933-03-27 | 86 | 245-0016 | 神奈川県横浜市泉区和泉町********** | S14028 | 20160115 | 0-00000000-0 | 139.4836 | 35.39125 |
5 | CS001215000145 | 田崎 美紀 | 1 | 女性 | 1995-03-29 | 24 | 144-0055 | 東京都大田区仲六郷********** | S13001 | 20170605 | 6-20090929-2 | 139.7078 | 35.54084 |
6 | CS020401000016 | 宮下 達士 | 0 | 男性 | 1974-09-15 | 44 | 174-0065 | 東京都板橋区若木********** | S13020 | 20150225 | 0-00000000-0 | 139.6724 | 35.77073 |
7 | CS015414000103 | 奥野 陽子 | 1 | 女性 | 1977-08-09 | 41 | 136-0073 | 東京都江東区北砂********** | S13015 | 20150722 | B-20100609-B | 139.8360 | 35.67818 |
8 | CS029403000008 | 釈 人志 | 0 | 男性 | 1973-08-17 | 45 | 279-0003 | 千葉県浦安市海楽********** | S12029 | 20150515 | 0-00000000-0 | 139.9047 | 35.65422 |
9 | CS015804000004 | 松谷 米蔵 | 0 | 男性 | 1931-05-02 | 87 | 136-0073 | 東京都江東区北砂********** | S13015 | 20150607 | 0-00000000-0 | 139.8360 | 35.67818 |
10 | CS033513000180 | 安斎 遥 | 1 | 女性 | 1962-07-11 | 56 | 241-0823 | 神奈川県横浜市旭区善部町********** | S14033 | 20150728 | 6-20080506-5 | 139.5146 | 35.45013 |
解説:
このコードは以下のタスクを実行します。
df_geocodeデータフレームから3つの列(postal_cd, longitude, latitude)を選択し、df_geocode_1という新しいデータフレームを作成する。
df_geocode_1データフレームはpostal_cdでグループ化され、各グループの経度と緯度の平均値がsummarise()関数で計算される。結果として得られるデータフレームは、postal_cdのユニークな値ごとに1行、postal_cd、m_longitude、m_latitudeのカラムを含みます。
df_customer データフレームは、共通の postal_cd 列に基づいて行をマッチングする inner_join() 関数を使用して df_geocode_1 データフレームと結合されます。結果として得られるデータフレームは、両方のデータフレームからのすべての列を含んでいます。
head()関数を使用して、結果のデータフレーム(df_customer_1)の最初の10行を表示します。これらの行には、顧客に関する情報と地理的な位置(緯度と経度)が含まれています。
R-086: 085で作成した緯度経度つき顧客データに対し、会員申込店舗コード(application_store_cd)をキーに店舗データ(df_store)と結合せよ。そして申込み店舗の緯度(latitude)・経度情報(longitude)と顧客住所(address)の緯度・経度を用いて申込み店舗と顧客住所の距離(単位:km)を求め、顧客ID(customer_id)、顧客住所(address)、店舗住所(address)とともに表示せよ。計算式は以下の簡易式で良いものとするが、その他精度の高い方式を利用したライブラリを利用してもかまわない。結果は10件表示せよ。
緯度(ラジアン):φ緯度(ラジアン):λ:距離L=6371∗arccos(sinφ1∗sinφ2+cosφ1∗cosφ2∗cos(λ1−λ2))
calc_distance <- function(x1, y1, x2, y2) { distance <- 6371 * acos( sin(x1 * pi / 180) * sin(x2 * pi / 180) + cos(x1 * pi / 180) * cos(x2 * pi / 180) * cos((y1 * pi / 180) - (y2 * pi / 180 ))) print(class(distance)) # Check the CLASS of the calculation results just to be sure. return(distance) }
inner_join(df_customer_1, df_store, by = c("application_store_cd" = "store_cd")) %>%
rename(customer_address = address.x, store_address = address.y) %>%
mutate(distance = calc_distance(m_latitude, m_longiture, latitude, longitude)) %>% select(customer_id, customer_address, store_address, distance) %>%
slice(1:10)
[1] "numeric"
customer_id | customer_address | store_address | distance |
---|---|---|---|
<chr> | <chr> | <chr> | <dbl> |
CS021313000114 | 神奈川県伊勢原市粟窪********** | 神奈川県伊勢原市伊勢原四丁目 | 1.3944087 |
CS037613000071 | 東京都江東区南砂********** | 東京都江東区南砂一丁目 | 1.4511822 |
CS031415000172 | 東京都渋谷区代々木********** | 東京都渋谷区初台二丁目 | 0.4117335 |
CS028811000001 | 神奈川県横浜市泉区和泉町********** | 神奈川県横浜市瀬谷区二ツ橋町 | 8.0651960 |
CS001215000145 | 東京都大田区仲六郷********** | 東京都大田区仲六郷二丁目 | 1.2684210 |
CS020401000016 | 東京都板橋区若木********** | 東京都北区十条仲原三丁目 | 4.1859046 |
CS015414000103 | 東京都江東区北砂********** | 東京都江東区南砂二丁目 | 1.4496734 |
CS029403000008 | 千葉県浦安市海楽********** | 千葉県浦安市東野一丁目 | 0.8048581 |
CS015804000004 | 東京都江東区北砂********** | 東京都江東区南砂二丁目 | 1.4496734 |
CS033513000180 | 神奈川県横浜市旭区善部町********** | 神奈川県横浜市瀬谷区阿久和西一丁目 | 1.9569470 |
解説:
このコードは、以下のタスクを実行します。
calc_distance()というカスタム関数を定義し、4つのパラメータx1、y1、x2、およびy2を受け取ります。この関数は、2つの地理的な場所(緯度と経度で指定)間の距離を、ハバーシンの公式を使用して計算する。計算された距離はキロメートル単位で返される。
df_customer_1 データフレームは、inner_join()関数を使用して df_store データフレームと結合します。結合は、df_customer_1 の application_store_cd 列と df_store の store_cd 列に対して実行されます。
結果として得られるデータフレームは、rename()関数を使用して、2つの異なるアドレスカラムを反映するように名前が変更されます。
mutate() 関数を使用して、distance という新しい列が結果のデータフレームに追加されます。calc_distance()関数は、顧客と店舗との間の距離を計算するために使用されます。この関数は、df_customer_1 の緯度と経度の平均値(m_latitude と m_longitude)と df_store の緯度と経度の値という 4 つの引数で呼ばれる。得られた距離値は、distance 列に格納される。
次に、select()関数を用いて、customer_id、customer_address、store_address、およびdistance列のみを含むように、結果のデータフレームをサブセットする。
最後に、slice()関数を使用して、結果のデータフレームの最初の10行を表示します。これらの行には、顧客に関する情報、顧客の住所、店舗の住所、顧客と店舗間の距離が含まれています。
R-087: 顧客データ(df_customer)では、異なる店舗での申込みなどにより同一顧客が複数登録されている。名前(customer_name)と郵便番号(postal_cd)が同じ顧客は同一顧客とみなして1顧客1レコードとなるように名寄せした名寄顧客データを作成し、顧客データの件数、名寄顧客データの件数、重複数を算出せよ。ただし、同一顧客に対しては売上金額合計が最も高いものを残し、売上金額合計が同一もしくは売上実績がない顧客については顧客ID(customer_id)の番号が小さいものを残すこととする。
df_sales_amount <- df_receipt %>%
group_by(customer_id) %>% summarise(sum_amount = sum(amount), .groups = "drop")
df_customer_u <- left_join(df_customer, df_sales_amount, by = "customer_id") %>% mutate(sum_amount = ifelse(is.na(sum_amount), 0, sum_amount)) %>% arrange(desc(sum_amount), customer_id) %>%
distinct(customer_name, postal_cd, .keep_all = TRUE)
print(paste( "df_customer_cnt:", nrow(df_customer), "df_customer_u_cnt:", nrow(df_customer_u), "diff:", nrow(df_customer) - nrow(df_customer_u)))
[1] "df_customer_cnt: 21971 df_customer_u_cnt: 21941 diff: 30"
解説:
このコードは、以下のステップを実行します。
df_receiptデータフレーム内の各顧客の売上金額の合計を計算し、group_by()とsummarise()関数を使用して新しいデータフレームdf_sales_amountに結果を保存します。
df_sales_amount <- df_receipt %>% group_by(customer_id) %>% summise(sum_amount = sum(amount), .groups = "drop")
customer_idカラムに基づいてdf_customerとdf_sales_amountデータフレーム間で左結合を行い、mutate()関数を使用してsum_amountカラムのNA値を0に置き換え、結果のデータフレームをsum_amountとcustomer_idの降順で並び替え、customer_nameとportal_cdカラムに基づいてユニーク行のみを保持します。
df_customer_u <- left_join(df_customer, df_sales_amount, by = "customer_id") %>% mutate(sum_amount = ifelse(is.na(sum_amount), 0, sum_amount) %>% arrange(desc(sum_amount), customer_id) %>% distinct(customer_name, postal_cd, .keep_all = TRUE)
元のdf_customerデータフレーム、結果のdf_customer_uデータフレームの行数とその差を出力し、重複した行がどれだけ削除されたかを確認する。
print(paste( "df_customer_cnt:", nrow(df_customer), "df_customer_u_cnt:", nrow(df_customer_u), "diff:", nrow(df_customer) - nrow(df_customer_u)))
R-088: 087で作成したデータを元に、顧客データに統合名寄IDを付与したデータを作成せよ。ただし、統合名寄IDは以下の仕様で付与するものとする。
- 重複していない顧客:顧客ID(customer_id)を設定
- 重複している顧客:前設問で抽出したレコードの顧客IDを設定
顧客IDのユニーク件数と、統合名寄IDのユニーク件数の差も確認すること。
df_customer_n = inner_join(df_customer,
df_customer_u[c("customer_id","customer_name","postal_cd")],
by = c("customer_name", "postal_cd")) %>%
rename(customer_id = customer_id.x,
integration_id = customer_id.y)
customer_id_cnt <- length(unique(df_customer_n$customer_id))
integration_id_cnt <- length(unique(df_customer_n$integration_id))
print(paste("Difference in number of IDs", customer_id_cnt - integration_id_cnt))
[1] "ID数の差 30"
解説:
このコードは以下の処理を実行します。
df_customerとdf_customer_uの間で、"customer_name "と "postal_cd "というカラムを結合キーとして使用した内部結合を実行します。
結果のデータフレームはdf_customer_nに割り当てられます。
df_customer_nの列 "customer_id.x "は "customer_id "にリネームされます。
df_customer_uのカラム "customer_id.y "は、"integration_id "にリネームされる。
df_customer_nの "customer_id "と "integration_id "カラムのユニークな値の数が計算され、これらの数の差が出力される。
このコードの目的は、元のdf_customerデータフレーム内のユニークな顧客IDの数と、df_customerと顧客ごとの総売上金額(df_sales_amount)を結合して作成したdf_customer_uデータフレーム内のユニークな顧客IDの数とを比較することです。前提として、df_customerには顧客名と郵便番号が重複している可能性があり、その結果、df_customerのユニークな顧客IDの数はdf_customer_uと比較して多くなります。コードの最後に表示される2つのカウントの差は、結合操作によって削除された重複する顧客IDの数を表します。
R-089: 売上実績がある顧客を、予測モデル構築のため学習用データとテスト用データに分割したい。それぞれ8:2の割合でランダムにデータを分割せよ。
set.seed(71)
#Example using rsample initial_split
df_sales_customer <- df_receipt %>%
group_by(customer_id) %>%
summarise(sum_amount = sum(amount), .groups = "drop") %>%
filter(sum_amount > 0)
df_tmp <- inner_join(df_customer, df_sales_customer, by = "customer_id")
split <- initial_split(df_tmp, prop = 0.8) df_customer_train <- training(split) df_customer_test <- testing(split)
# 確認
print(paste("Percentage of training data:", nrow(df_customer_train) / nrow(df_tmp))) print(paste("Test Data Percentage:", nrow(df_customer_test) / nrow(df_tmp)))
[1] "学習データ割合: 0.799903684083795" [1] "テストデータ割合: 0.200096315916205"
解説:
このコードは、Rのrsampleパッケージを使用して、データセットをトレーニングセットとテストセットに分割しています。
set.seed(71)は、結果の再現性を確保するためのランダムシードを設定しています。
df_sales_customerは、df_receiptをcustomer_idでグループ化し、各顧客の金額の合計を計算することで作成されています。そして、合計がプラスになる顧客だけを残す。
df_tmpはdf_customerとdf_sales_customerをcustomer_idで結合することで作成されます。
splitはrsampleパッケージのinitial_split()関数を用いて作成する。propパラメータは0.8に設定されており、データセットが80%のトレーニングデータと20%のテストデータに分割されることを意味します。
df_customer_trainとdf_customer_testはそれぞれ、分割によって得られたトレーニングセットとテストセットである。
最後に、print()文を使って、トレーニングデータとテストデータの割合を確認する。
R-090: レシート明細データ(df_receipt)は2017年1月1日〜2019年10月31日までのデータを有している。売上金額(amount)を月次で集計し、学習用に12ヶ月、テスト用に6ヶ月の時系列モデル構築用データを3セット作成せよ。
# caretのcreateTimeSlicesを使った例
df_ts_amount <- df_receipt %>% group_by(substr(as.character(sales_ymd), 1, 6)) %>% summarise(sum_amount = sum(amount), .groups = "drop")
colnames(df_ts_amount) <- c("sales_ym", "sales_amount")
timeSlice <- createTimeSlices(df_ts_amount$sales_ym, initialWindow = 12, horizon = 6, skip = 5, fixedWindow = TRUE)
df_train_1 <- df_ts_amount[timeSlice$train[[1]],]
df_train_2 <- df_ts_amount[timeSlice$train[[2]],]
df_train_3 <- df_ts_amount[timeSlice$train[[3]],]
df_test_1 <- df_ts_amount[timeSlice$test[[1]],]
df_test_2 <- df_ts_amount[timeSlice$test[[2]],]
df_test_3 <- df_ts_amount[timeSlice$test[[3]],]
# df_train_2とdf_train_3の表示は割愛 df_train_1
sales_ym | sales_amount |
---|---|
<chr> | <int> |
201701 | 902056 |
201702 | 764413 |
201703 | 962945 |
201704 | 847566 |
201705 | 884010 |
201706 | 894242 |
201707 | 959205 |
201708 | 954836 |
201709 | 902037 |
201710 | 905739 |
201711 | 932157 |
201712 | 939654 |
# df_test_2とdf_test_3の表示は割愛 df_test_1
sales_ym | sales_amount |
---|---|
<chr> | <int> |
201801 | 944509 |
201802 | 864128 |
201803 | 946588 |
201804 | 937099 |
201805 | 1004438 |
201806 | 1012329 |
解説:
このコードは、caretパッケージのcreateTimeSlices関数を使って、時間ベースのクロスバリデーションフォールドを作成する方法の例である。
このコードの最初のステップは、group_by関数とsummarise関数を使って、データセット全体の月別の売上金額を要約することです。そして、出来上がったデータフレームは、より意味のあるカラム名にリネームされます。
次に、createTimeSlices関数を使用して、データに対して3つの時間ベースの折りたたみを作成します。この関数は、時点のベクトル(この場合は販売月)を受け取り、各フォールドのトレーニングインデックスとテストインデックスのセットに分割する。initialWindowパラメータは最初のトレーニングウィンドウのサイズを、horizonパラメータはテストウィンドウのサイズを、skipパラメータは各折り返し間のスキップ時間量を、fixedWindowパラメータはテストウィンドウのサイズを固定するかどうかを指定するものである。
最後に、createTimeSlicesで生成されたインデックスを使用して、df_trainとdf_testのデータフレームが各折り返しで作成されます。これらのデータフレームは、モデルの時間ベースのクロスバリデーションに使用することができます。
R-091: 顧客データ(df_customer)の各顧客に対し、売上実績がある顧客数と売上実績がない顧客数が1:1となるようにアンダーサンプリングで抽出せよ。
# receiptsパッケージを使った例
df_sales_amount <- df_receipt %>%
group_by(customer_id) %>%
summarise(sum_amount = sum(amount), .groups = "drop") %>%
right_join(df_customer, by = "customer_id") %>%
mutate(is_buy_flag = factor(ifelse(is.na(sum_amount), 0, 1)))
df_down_sampling <- df_sales_amount %>%
recipe() %>%
step_downsample(is_buy_flag, seed = 71) %>%
prep() %>% juice()
df_down_sampling %>%
group_by(is_buy_flag) %>%
summarise(cnt = n(), .groups = "drop")
is_buy_flag | cnt |
---|---|
<fct> | <int> |
0 | 8306 |
1 | 8306 |
解説:
Rのrecipesパッケージを使ってダウンサンプリングを実行しているコードです。
まず、各顧客の売上金額の合計を計算し、顧客情報と結合します。そして、is_buy_flagというバイナリ変数を作成し、売上金額の有無から顧客が購入したか否かを示しています。
次に、recipe()関数を用いてレシピオブジェクトを作成する。次に、step_downsample()関数を使用して、71のランダムシードを使用して、多数派クラス(購入をしなかった顧客)を少数派クラス(購入をした顧客)の観測数に合わせてダウンサンプリングします。
prep()関数はレシピの準備に、juice()関数は処理されたデータセットの抽出に使用される。最後に、is_buy_flagでデータをグループ化し、各グループのオブザベーション数をカウントすることで、結果のダウンサンプリングを検証する。
R-092: 顧客データ(df_customer)の性別について、第三正規形へと正規化せよ。
df_gender_std = unique(df_customer[c("gender_cd", "gender")]) df_customer_std = df_customer[, colnames(df_customer) != "gender"]
# データの内容確認 head(df_customer_std, n = 3)
customer_id | customer_name | gender_cd | birth_day | age | postal_cd | address | application_store_cd | application_date | status_cd | |
---|---|---|---|---|---|---|---|---|---|---|
<chr> | <chr> | <chr> | <date> | <int> | <chr> | <chr> | <chr> | <chr> | <chr> | |
1 | CS021313000114 | 大野 あや子 | 1 | 1981-04-29 | 37 | 259-1113 | 神奈川県伊勢原市粟窪********** | S14021 | 20150905 | 0-00000000-0 |
2 | CS037613000071 | 六角 雅彦 | 9 | 1952-04-01 | 66 | 136-0076 | 東京都江東区南砂********** | S13037 | 20150414 | 0-00000000-0 |
3 | CS031415000172 | 宇多田 貴美子 | 1 | 1976-10-04 | 42 | 151-0053 | 東京都渋谷区代々木********** | S13031 | 20150529 | D-20100325-C |
# データの内容確認 head(df_gender_std, n = 3)
gender_cd | gender | |
---|---|---|
<chr> | <chr> | |
1 | 1 | 女性 |
2 | 9 | 不明 |
6 | 0 | 男性 |
解説:
上のコードは、顧客情報を格納した「df_customer」というデータフレームを操作しています。以下、各コード行の処理内容を紹介します。
df_gender_std = unique(df_customer[c("gender_cd", "gender")]) - このコードでは、df_gender_std という新しいデータフレームを作成します。これは、df_customer データフレームから 2 つの列、特に "gender_cd" と "gender" という名前の列を選択します。そして、unique()関数を使って重複する行を削除し、元のデータフレームに含まれる性別コードと性別値のユニークな組み合わせをすべて含むデータフレームを作成します。
df_customer_std = df_customer[, colnames(df_customer) != "gender"] - このコードの行はdf_customer_stdという別の新しいデータフレームを作成します。 これはdf_customerデータフレームから「性別」列を除くすべての列をコピーします。これは、colnames()関数と論理演算子!=を使って、名前が "gender "と等しくない全ての列を選択することで行われます。 結果のデータフレームは、元のdf_customerデータフレームと同じ行を持ちますが、"gender "列はありません。
この2行のコードにより、元のdf_customerデータフレームは、ユニークな性別コードと値のみを含む部分と、性別列を除く他のすべての顧客情報を含む部分に分割されました。
R-093: 商品データ(df_product)では各カテゴリのコード値だけを保有し、カテゴリ名は保有していない。カテゴリデータ(df_category)と組み合わせて非正規化し、カテゴリ名を保有した新たな商品データを作成せよ。
df_product_full <- inner_join(df_product, df_category[c("category_small_cd", "category_major_name", "category_medium_name", "category_small_name")], by = "category_small_cd")
# Check data content
head(df_product_full, n = 3)
product_cd | category_major_cd | category_medium_cd | category_small_cd | unit_price | unit_cost | category_major_name | category_medium_name | category_small_name | |
---|---|---|---|---|---|---|---|---|---|
<chr> | <chr> | <chr> | <chr> | <int> | <int> | <chr> | <chr> | <chr> | |
1 | P040101001 | 04 | 0401 | 040101 | 198 | 149 | 惣菜 | 御飯類 | 弁当類 |
2 | P040101002 | 04 | 0401 | 040101 | 218 | 164 | 惣菜 | 御飯類 | 弁当類 |
3 | P040101003 | 04 | 0401 | 040101 | 230 | 173 | 惣菜 | 御飯類 | 弁当類 |
解説:
上のコードは、「df_product」と「df_category」という2つのデータフレームを操作しています。以下、各コード行の処理内容を紹介します。
df_product_full <- inner_join(df_product, df_category[c("category_small_cd", "category_major_name", "category_medium_name", "category_small_name")], by = "category_small_cd") - このコードでは df_product_full という新しいデータフレームを作っています。これは、inner_join()関数を使用して、"category_small_cd "という共通の列に基づいてdf_productとdf_categoryデータフレームを結合しています。その結果、"category_small_cd "の値が一致する両方のデータフレームからすべてのカラムを含むデータフレームが生成されます。df_categoryデータフレームは、"category_small_cd", "category_major_name", "category_medium_name", "category_small_name" 列のみを含むようにサブセットされています。
head(df_product_full, n = 3) - このコードの行は、df_product_fullデータフレームの内容をチェックするために使用されます。head()関数を使用して、データ・フレームの最初の3行を表示します。これは、結合操作が成功したことを確認し、出力の形式をチェックするために、結果のデータ・フレームを素早く検査するのに便利な方法です。
R-094: 093で作成したカテゴリ名付き商品データを以下の仕様でファイル出力せよ。
|ファイル形式|ヘッダ有無|文字エンコーディング| |:–:|:–:|:–:| |CSV(カンマ区切り)|有り|UTF-8|
ファイル出力先のパスは以下のようにすること
|出力先| |:–:| |./data|
# 解答ファイルの置き場所が設問ファイルと異なるため、パスが'../data'となっている点に注意 write.csv(df_product_full, "../data/R_df_product_full_UTF-8_header.csv", row.names=FALSE, fileEncoding = "UTF-8")
解説:
上のコードは、df_product_fullというデータフレームをUTF-8エンコーディングでCSVファイルに書き込んでいます。write.csv()関数の各引数の役割は以下の通りです。
df_product_full - CSVファイルに書き出したいデータフレームです。
"../data/R_df_product_full_UTF-8_header.csv" - 出力CSVファイルのファイルパスとファイル名です。パスの先頭にある.は、ファイルが現在の作業ディレクトリの親ディレクトリに保存されることを意味します。R_df_product_full_UTF-8_header.csv は、出力ファイルの名前です。
row.names=FALSE - この引数は、出力CSVファイルに行名を含めないことを指定します。
fileEncoding = "UTF-8" - この引数は、出力CSVファイルのエンコーディングを指定します。UTF-8は、さまざまな言語の文字を幅広くサポートする文字エンコーディングであるため、英語以外の文字を扱うのに適しています。
まとめると、write.csv()関数はdf_product_fullデータフレームをUTF-8エンコーディングでCSVファイルに書き込み、指定したファイルパスとファイル名に保存します。出来上がったCSVファイルには、行名は含まれません。
R-095: 093で作成したカテゴリ名付き商品データを以下の仕様でファイル出力せよ。
|ファイル形式|ヘッダ有無|文字エンコーディング| |:–:|:–:|:–:| |CSV(カンマ区切り)|有り|CP932|
ファイル出力先のパスは以下のようにすること。
|出力先| |:–:| |./data|
# 解答ファイルの置き場所が設問ファイルと異なるため、パスが'../data'となっている点に注意 write.csv(df_product_full, "../data/R_df_product_full_CP932_header.csv", row.names = FALSE, fileEncoding = "CP932")
解説:
上記のコードは、df_product_fullというデータフレームをCP932エンコーディングでCSVファイルに書き込んでいます。write.csv()関数の各引数が何をするのか、以下に示します。
df_product_full - CSVファイルに書き出したいデータフレームです。
"../data/R_df_product_full_CP932_header.csv" - 出力CSVファイルのファイルパスとファイル名です。パスの先頭にある.は、ファイルが現在の作業ディレクトリの親ディレクトリに保存されることを意味します。R_df_product_full_CP932_header.csv は、出力ファイルの名前です。
row.names=FALSE - この引数は、出力CSVファイルに行名を含めないことを指定します。
fileEncoding = "CP932" - この引数は、出力CSVファイルのエンコーディングを指定します。CP932は、日本語テキストに使用される文字エンコーディングで、日本語で使用される様々な文字に対応しています。
要約すると、write.csv()関数は、df_product_fullデータフレームをCP932エンコーディングでCSVファイルに書き込み、指定されたファイルパスとファイル名に保存する。出来上がったCSVファイルには、行名は含まれません。このエンコーディングは、日本語のテキストデータを扱う際に便利です。
R-096: 093で作成したカテゴリ名付き商品データを以下の仕様でファイル出力せよ。
|ファイル形式|ヘッダ有無|文字エンコーディング| |:–:|:–:|:–:| |CSV(カンマ区切り)|無し|UTF-8|
ファイル出力先のパスは以下のようにすること
|出力先| |:–:| |./data|
# 解答ファイルの置き場所が設問ファイルと異なるため、パスが'../data'となっている点に注意 write.table(df_product_full, "../data/R_df_product_full_UTF-8_noh.csv", row.names = FALSE, col.names = FALSE, sep = ",", fileEncoding = "UTF-8")
解説:
上のコードは、df_product_fullというデータフレームをUTF-8エンコーディングでテキストファイルに書き込んでいます。write.table()関数の各引数が何をするのか、以下に示します。
df_product_full - テキスト・ファイルに書き込むデータ・フレームです。
"../data/R_df_product_full_UTF-8_noh.csv" - 出力テキストファイルのファイルパスとファイル名です。パスの先頭にある.は、ファイルが現在の作業ディレクトリの親ディレクトリに保存されることを意味します。R_df_product_full_UTF-8_noh.csvは、出力ファイルの名前です。
row.names = FALSE - この引数は、出力テキスト・ファイルに行名を含めないことを指定します。
col.names = FALSE - この引数は、出力テキスト・ファイルに列名を含めないことを指定します。
sep = "," - この引数は、出力テキストファイルの列の間に使用するデリミターを指定します。この場合、デリミターとしてカンマが使用されます。
fileEncoding = "UTF-8" - この引数は、出力テキストファイルのエンコーディングを指定する。UTF-8は、さまざまな言語の文字を幅広くサポートする文字エンコーディングであるため、英語以外の文字を扱うのに適しています。
要約すると、write.table()関数は、df_product_fullデータフレームをUTF-8エンコーディングでテキストファイルに書き込み、指定したファイルパスとファイル名に保存します。出来上がったテキストファイルは、行名や列名を含まず、区切り文字としてカンマを使用します。
R-097: 094で作成した以下形式のファイルを読み込み、データを3件を表示させて正しく取り込まれていることを確認せよ。
|ファイル形式|ヘッダ有無|文字エンコーディング| |:–:|:–:|:–:| |CSV(カンマ区切り)|有り|UTF-8|
# 解答ファイルの置き場所が設問ファイルと異なるため、パスが'../data'となっている点に注意 c_class <- c(NA, "character", "character", "character", NA, NA, NA, NA, NA) df_product_full <- read.csv("../data/R_df_product_full_UTF-8_header.csv", colClasses = c_class, fileEncoding = "UTF-8") head(df_product_full, 3)
product_cd | category_major_cd | category_medium_cd | category_small_cd | unit_price | unit_cost | category_major_name | category_medium_name | category_small_name | |
---|---|---|---|---|---|---|---|---|---|
<chr> | <chr> | <chr> | <chr> | <int> | <int> | <chr> | <chr> | <chr> | |
1 | P040101001 | 04 | 0401 | 040101 | 198 | 149 | 惣菜 | 御飯類 | 弁当類 |
2 | P040101002 | 04 | 0401 | 040101 | 218 | 164 | 惣菜 | 御飯類 | 弁当類 |
3 | P040101003 | 04 | 0401 | 040101 | 230 | 173 | 惣菜 | 御飯類 | 弁当類 |
解説:
上記のコードは、R_df_product_full_UTF-8_header.csvというCSVファイルをdf_product_fullというデータフレームに読み込んでいます。read.csv()関数の各引数が何をするかは以下の通りです。
"../data/R_df_product_full_UTF-8_header.csv" - これは入力CSVファイルのファイルパスとファイル名である。パスの先頭の.は、ファイルが現在の作業ディレクトリの親ディレクトリにあることを意味します。
colClasses = c_class - この引数は、データフレーム内の各列のクラスを指定するベクトルである。この場合、1列目と5〜9列目はNAに設定され、クラスが自動的に決定されることが示されている。2列目から4列目まではcharacterに設定され、文字列として扱われることが示される。
fileEncoding = "UTF-8" - この引数は、入力CSVファイルのエンコーディングを指定する。UTF-8は、さまざまな言語の文字を幅広くサポートする文字エンコーディングである。
head(df_product_full, 3) - このコマンドは、df_product_fullデータフレームの最初の3行をコンソールに表示します。
要約すると、read.csv() 関数は R_df_product_full_UTF-8_header.csv ファイルを、指定した列クラスとファイルエンコーディングを使って df_product_full というデータフレームに読み込む。そして、出来上がったデータフレームは、head()関数を用いてコンソールに出力されます。
R-098: 096で作成した以下形式のファイルを読み込み、データを3件を表示させて正しく取り込まれていることを確認せよ。
|ファイル形式|ヘッダ有無|文字エンコーディング| |:–:|:–:|:–:| |CSV(カンマ区切り)|ヘッダ無し|UTF-8|
# コード例1(後から項目名をつける) # 解答ファイルの置き場所が設問ファイルと異なるため、パスが'../data'となっている点に注意
c_class <- c(NA, "character", "character", "character", NA, NA, NA, NA, NA)
df_product_full <- read.csv("../data/R_df_product_full_UTF-8_noh.csv", colClasses = c_class, header = FALSE, fileEncoding = "UTF-8")
colnames(df_product_full) <- c("product_cd", "category_major_cd", "category_medium_cd", "category_small_cd", "unit_price", "unit_cost", "category_major_name", "category_medium_name", "category_small_name")
head(df_product_full, 3)
product_cd | category_major_cd | category_medium_cd | category_small_cd | unit_price | unit_cost | category_major_name | category_medium_name | category_small_name | |
---|---|---|---|---|---|---|---|---|---|
<chr> | <chr> | <chr> | <chr> | <int> | <int> | <chr> | <chr> | <chr> | |
1 | P040101001 | 04 | 0401 | 040101 | 198 | 149 | 惣菜 | 御飯類 | 弁当類 |
2 | P040101002 | 04 | 0401 | 040101 | 218 | 164 | 惣菜 | 御飯類 | 弁当類 |
3 | P040101003 | 04 | 0401 | 040101 | 230 | 173 | 惣菜 | 御飯類 | 弁当類 |
解説:
上記のコードは、R_df_product_full_UTF-8_noh.csvというCSVファイルをdf_product_fullというデータフレームに読み込み、新しい列名をデータフレームに割り当てています。read.csv()関数の各引数が何をするかは以下の通りです。
"../data/R_df_product_full_UTF-8_noh.csv" - これは入力CSVファイルのファイルパスとファイル名である。パスの先頭の.は、ファイルが現在の作業ディレクトリの親ディレクトリにあることを意味します。
colClasses = c_class - この引数は、データフレーム内の各列のクラスを指定するベクトルである。この場合、1列目と5~9列目はNAに設定され、クラスが自動的に決定されることが示されている。2列目から4列目はcharacterに設定され、文字列として扱われるべきことを示す。
header = FALSE - この引数は、入力CSVファイルにヘッダー行がないことを指定する。
fileEncoding = "UTF-8" - この引数は、入力CSVファイルのエンコーディングを指定する。UTF-8は、さまざまな言語の文字を幅広くサポートする文字エンコーディングである。
colnames(df_product_full) <- c("product_cd", "category_major_cd", "category_medium_cd", "category_small_cd", "unit_price", "unit_cost", "category_major_name", "category_medium_name", "category_small_name") - データフレームに新しいコラム名を付与するコマンドです.新しい列名は "product_cd", "category_major_cd", "category_medium_cd", "category_small_cd", "unit_price", "unit_cost", "category_major_name", "category_medium_name", and "category_small_name", the order of the same column name is.
head(df_product_full, 3) - このコマンドは、df_product_fullデータフレームの最初の3行をコンソールに表示します。
要約すると、read.csv() 関数は R_df_product_full_UTF-8_noh.csv ファイルを、指定された列クラス、ヘッダー設定、ファイルエンコーディングを用いて df_product_full というデータフレームに読み込む。そして、出来上がったデータフレームに新しいカラム名を付け、head()関数を用いてコンソールに出力する。
# コード例2(先に項目名を定義する) # 解答ファイルの置き場所が設問ファイルと異なるため、パスが'../data'となっている点に注意
c_names <- c("product_cd", "category_major_cd", "category_medium_cd", "category_small_cd", "unit_price","unit_cost", "category_major_name", "category_medium_name", "category_small_name") c_class <- c(NA, "character", "character", "character", NA, NA, NA, NA, NA)
df_product_full <- read.csv("../data/R_df_product_full_UTF-8_noh.csv", col.names = c_names, colClasses = c_class, header = FALSE, fileEncoding = "UTF-8")
head(df_product_full, 3)
product_cd | category_major_cd | category_medium_cd | category_small_cd | unit_price | unit_cost | category_major_name | category_medium_name | category_small_name | |
---|---|---|---|---|---|---|---|---|---|
<chr> | <chr> | <chr> | <chr> | <int> | <int> | <chr> | <chr> | <chr> | |
1 | P040101001 | 04 | 0401 | 040101 | 198 | 149 | 惣菜 | 御飯類 | 弁当類 |
2 | P040101002 | 04 | 0401 | 040101 | 218 | 164 | 惣菜 | 御飯類 | 弁当類 |
3 | P040101003 | 04 | 0401 | 040101 | 230 | 173 | 惣菜 | 御飯類 | 弁当類 |
解説:
上記のコードは、R_df_product_full_UTF-8_noh.csvというCSVファイルをdf_product_fullというデータフレームに読み込み、新しい列名をデータフレームに割り当てています。read.csv()関数の各引数が何をするかは以下の通りです。
"../data/R_df_product_full_UTF-8_noh.csv" - これは入力CSVファイルのファイルパスとファイル名である。パスの先頭の.は、ファイルが現在の作業ディレクトリの親ディレクトリにあることを意味します。
col.names = c_names - この引数は、データフレームで使用する列名を指定します。c_namesは、新しい列名を入力ファイルに現れるのと同じ順序で列挙する文字ベクトルです。
colClasses = c_class - この引数は、データフレーム内の各列のクラスを指定します。c_classは、データフレーム内の各列のクラスを指定するベクトルです。この場合、最初の列はNAに設定され、そのクラスが自動的に決定されることを示す。2列目から4列目まではcharacterに設定され、文字列として扱われることが示される。5番目と6番目の列はNAに設定され、そのクラスが自動的に決定されるべきことを示す。最後の3つの列はNAに設定され、欠損値として扱われるべきことを示す。
header = FALSE - この引数は、入力CSVファイルにヘッダー行がないことを指定する。
fileEncoding = "UTF-8" - この引数は、入力CSVファイルのエンコーディングを指定する。UTF-8は、さまざまな言語の文字を幅広くサポートする文字エンコーディングである。
head(df_product_full, 3) - このコマンドは、df_product_fullデータフレームの最初の3行をコンソールに表示します。
要約すると、read.csv()関数は、R_df_product_full_UTF-8_noh.csv ファイルを、指定した列名、列クラス、ヘッダー設定、ファイルエンコーディングを用いて df_product_full というデータフレームに読み込む。そして、出来上がったデータフレームは、head()関数を用いてコンソールに出力されます。
R-099: 093で作成したカテゴリ名付き商品データを以下の仕様でファイル出力せよ。
|ファイル形式|ヘッダ有無|文字エンコーディング| |:–:|:–:|:–:| |TSV(タブ区切り)|有り|UTF-8|
ファイル出力先のパスは以下のようにすること
|出力先| |:–:| |./data|
# 解答ファイルの置き場所が設問ファイルと異なるため、パスが'../data'となっている点に注意 write.table(df_product_full, "../data/R_df_product_full_UTF-8_header.tsv", row.names = FALSE, sep = "\t", fileEncoding = "UTF-8")
解説:
上記のコードは、データフレームdf_product_fullの内容を、R_df_product_full_UTF-8_header.tsvというタブ区切り値(TSV)ファイルに書き込んでいます。以下、write.table()関数の各引数が何をするのかを説明します。
df_product_full - TSVファイルに書き込まれるデータフレームです。
"../data/R_df_product_full_UTF-8_header.tsv" - 出力TSVファイルのファイルパスとファイル名です。パスの先頭にある...は、ファイルが現在の作業ディレクトリの親ディレクトリに配置されることを意味します。
row.names = FALSE - この引数は、出力ファイルに行名を含めないことを指定します。
sep = "\t" - この引数は、列の間に使用される区切り文字を指定します。この場合、区切り記号はタブ文字です。
fileEncoding = "UTF-8" - この引数は、出力TSVファイルのエンコーディングを指定します。UTF-8は、さまざまな言語のさまざまな文字をサポートする文字エンコーディングです。
まとめると、write.table()関数は、df_product_fullデータフレームの内容を、区切り文字にタブ、ファイルエンコードにUTF-8を使って、R_df_product_full_UTF-8_header.tsvというTSVファイルに書き込んでいます。
R-100: 099で作成した以下形式のファイルを読み込み、データを3件を表示させて正しく取り込まれていることを確認せよ。
|ファイル形式|ヘッダ有無|文字エンコーディング| |:–:|:–:|:–:| |TSV(タブ区切り)|有り|UTF-8|
# Note that the location of the answer file is different from the question file, so the path is '. /data' because the location of the answer file is different from the question file.
c_class <- c(NA, "character", "character", "character", NA, NA, NA, NA, NA)
df_product_tmp <- read.table("../data/R_df_product_full_UTF-8_header.tsv", colClasses = c_class, header = TRUE, fileEncoding = "UTF-8")
head(df_product_tmp,3)
product_cd | category_major_cd | category_medium_cd | category_small_cd | unit_price | unit_cost | category_major_name | category_medium_name | category_small_name | |
---|---|---|---|---|---|---|---|---|---|
<chr> | <chr> | <chr> | <chr> | <int> | <int> | <chr> | <chr> | <chr> | |
1 | P040101001 | 04 | 0401 | 040101 | 198 | 149 | 惣菜 | 御飯類 | 弁当類 |
2 | P040101002 | 04 | 0401 | 040101 | 218 | 164 | 惣菜 | 御飯類 | 弁当類 |
3 | P040101003 | 04 | 0401 | 040101 | 230 | 173 | 惣菜 | 御飯類 | 弁当類 |
解説:
上記のコードは、R_df_product_full_UTF-8_header.tsvというタブ区切り値(TSV)ファイルを読み込み、その内容をdf_product_tmpというデータフレームに格納しています。read.table()関数の各引数の役割は以下の通りです。
c_class - TSVファイル内の各列のクラスを指定するベクトルです。この場合、最初の列はNAのままで、他の列は "character "というクラスで指定されています。
"../data/R_df_product_full_UTF-8_header.tsv" - 入力TSVファイルのファイルパスとファイル名です。
colClasses = c_class - この引数は、入力TSVファイルの列クラスを指定します。
header = TRUE - この引数は、入力ファイルの最初の行が列名を含むことを指定します。
fileEncoding = "UTF-8" - この引数は、入力TSVファイルの文字エンコーディングを指定する。
TSV ファイルを読み込んだ後、head() 関数を使用して、結果の df_product_tmp データフレームの最初の 3 行を表示します。
全体として、このコードは、CSVファイルを読み込んでその内容をdf_product_fullデータフレームに格納する前のコードと似ています。しかし、このコードではTSVファイルを読み込み、その内容をdf_product_tmpという一時的なデータ・フレームに格納します。一時的なデータ・フレームを使用する目的は、最終結果を別の名前のデータ・フレームに格納する前に、データのクリーニングや操作を行うためかもしれません。
Comment