はじめに
またまたRの勉強会に参加しました
今回はデータの前処理です
データ処理の8割は前処理といわれるくらい前処理は多岐にわたると思いますが
今回は、問題のあるcsvファイルとjsonを入力して、前処理を施す、でした
目的は、Rの講習会の内容をpythonではどうやって書くの?を復習かねて記録することです
環境
windows10 Pro 64bit
R :3.6.1
RStudio :1.2.1335
Google Colaboratoryを使用
Python :3.6.8
https://github.com/WillGardella/hotels/
内のjsonを利用
なにするの
①問題のあるcsvファイルの入力
②正規表現で文字処理を行い、データフォーマットを変更する
③jsonファイルの入力
④入力したデータの利用
Rのコード
①問題のあるcsvファイルの入力
ファイルの入力は、read.csv、read_csvなどを用いて読み込み
read_csvは、R標準のread.csvに比べ高速で便利な関数になります
↓参考にさせていただきました
https://heavywatal.github.io/rstats/readr.html
dirty.csv
col1, col2, col3
"1,233", "$12.79", "$1,333,233.17"
"470", "$1,113.22", "$0.12"
# 使用するpackage
library(readr)
library(dplyr)
library("jsonlite")
library("listviewer")
library("ndjson")
library("revgeo")
library("tidyverse")
# dirty.csvの読み込み
a2<-read_csv("dirty.csv")
> a2
# A tibble: 2 x 3
col1 col2 col3
<dbl> <chr> <chr>
1 1233 $12.79 $1,333,233.17
2 470 $1,113.22 $0.12
②正規表現で文字処理を行い、データフォーマットを変更する
データに$が付いているため、strで読み込まれている
$を削除して数値に置き換える関数を定義して、col2とcol3に適用
# "$"を削除して、数値に変換する関数を定義
clean <- function(ttt){
as.numeric( gsub('[^a-zA-Z0-9.]', '', ttt))
}
# a2に関数cleanを適用しdataとする
data <- a2 %>% mutate(col2 = clean(col2),col3 = clean(col3))
> data
# A tibble: 2 x 3
col1 col2 col3
<dbl> <dbl> <dbl>
1 1233 12.8 1333233.
2 470 1113. 0.12
③jsonファイルの入力
利用するデータは、hotels.json
コード内で調べますが、8076レコードのstreaming JSONをdataframeに読み込んでデータの概要をつかむ。
# streaming JSONをdataframeに入力
df <- "data/hotels.json" %>%
ndjson::stream_in()
# データの概要を確認
glimpse(df)
> glimpse(df)
Observations: 8,076
Variables: 25
$ activity <chr> "sleep", "sleep", "sleep", "sleep", "sleep", "slee...
$ address <chr> "Cwm Cadlan, Penderyn, CF44 0YJ", "Harbour Island,...
$ alt <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, "Grand Hotel a...
$ checkin <chr> NA, NA, NA, NA, NA, "14:00", NA, NA, NA, NA, NA, N...
$ checkout <chr> NA, NA, NA, NA, NA, "10:00", NA, "12:00", NA, NA, ...
$ content <chr> "Fantastic little B&B with 3 rooms, all en-suite. ...
$ directions <chr> "From Penderyn, follow Cwm Cadlan road from Lamb H...
$ email <chr> "willow.walks@hotmail.co.uk", NA, "info@porambahos...
$ fax <chr> NA, NA, NA, NA, NA, NA, "+33 4 90 60 40 76", NA, N...
$ geo.lat <dbl> 51.782300, 25.497250, -25.595870, 61.054100, 5.278...
$ geo.lon <dbl> -3.495900, -76.636740, -54.567661, 28.191100, 115....
$ hours <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ id <dbl> 4042, 8848, 23350, 15189, 14992, 15540, 40356, 375...
$ image <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, "https://en.wi...
$ name <chr> "Beili Helyg Guest House", "Valentines Resort & Ma...
$ phone <chr> "+44 0 1685 813609", "(866) 389-6864", "+54 3757 4...
$ price <chr> "ツ」80 per double room per night", NA, NA, "double ...
$ title <chr> "Brecon Beacons National Park", "Eleuthera", "Puer...
$ tollfree <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "+1-80...
$ type <chr> "landmark", "landmark", "landmark", "landmark", "l...
$ url <chr> "http://www.beilihelygguesthouse.co.uk", "http://w...
$ image_direct_url <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, "https://uploa...
$ city <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ country <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ state <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
④入力したデータの利用
例としてカラムの1つ、altの内容を確認。altは、6897/8076 欠損値であることが分かる。
文字化けを修正
GPSデータを抜き出してプロットしてみる。
世界中のhotelデータが登録されていることがわかる。
df %>% count(alt) %>% arrange(-n)
# A tibble: 1,161 x 2
alt n
<chr> <int>
1 NA 6897
2 Peak District Cottages 4
3 Best Western 3
4 Arresテク 2
5 Bed and Breakfast 2
6 Buda Panziテウ 2
7 formerly Etap 2
8 formerly Etap Hotel 2
9 formerly Four Points by Sheraton 2
10 Hostel 2
# ... with 1,151 more rows
# 文字化け修正
for(i in 1:25){
df[,i] <- df[,i] %>%
iconv(from="utf-8",to="cp932")
}
# GPSデータをプロット
plot(df$geo.lon, df$geo.lat)
Pythonのコード
①問題のあるcsvファイルの入力
pandasのread_csvでそのまま入力すると問題のあるcsvの意図通り?','を誤認識してしまいます
import pandas as pd
a1 = pd.read_csv('dirty.csv')
a1
col1 col2 col3
1,233 "$12.79" "$1 333 233.17"
470 "$1 113.22" "$0.12" NaN
read_csvのパラメータ skipinitialspace=True にすると今回はうまく読み込めます
a1 = pd.read_csv('dirty.csv', skipinitialspace=True)
a1
col1 col2 col3
0 1,233 $12.79 $1,333,233.17
1 470 $1,113.22 $0.12
②正規表現で文字処理を行い、データフォーマットを変更する
dataframeの各要素に対して処理を行う方法はいくつかあります
関数を適用する場合は、dataframe.applymap()などがありますが
今回は、正規表現を使うので、dataframe.replace()を使ってみます。regex=Trueで全要素に正規表現が適用されます。
このままでは要素はobjectのままなのでfloatに変換します
a1.replace('[^a-zA-Z0-9.]','',regex = True , inplace=True)
a1=a1.astype(float)
a1
col1 col2 col3
0 1233.0 12.79 1333233.17
1 470.0 1113.22 0.12
a1.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2 entries, 0 to 1
Data columns (total 3 columns):
col1 2 non-null float64
col2 2 non-null float64
col3 2 non-null float64
dtypes: float64(3)
memory usage: 128.0 bytes
③jsonファイルの入力
load 関数 :JSON ファイルをPythonの辞書型で保存する。
loads関数 :JSON 形式の文字列をpythonの辞書型で保存する。
hotels.jsonをopenすると、
<_io.TextIOWrapper name='hotels.json' mode='r' encoding='utf-8'>
で読み込まれます。strのイテレータなので(あってるのかな?)、1行づつloads関数で読み込んで
hotelsリストにappendしていきます。
load関数で読み込める場合は、1ラインずつ処理する必要ないのですが(おまけ参照)、、もっといい方法がありそう、、
loadとloadsでややこしい、、
import json
hotels = []
with open('hotels.json',encoding='utf-8') as f:
for i in f:
hotel = json.loads(i)
hotels.append(hotel)
hotelsリストは、そのままdataframeに変換できます。
しかし、このままではgeoデータがネストしてしまってます。
hotels_df = pd.DataFrame(hotels)
hotels_df.head()
activity address alt checkin checkout city content country directions email fax geo hours id image image_direct_url name phone price state title tollfree type url
0 sleep Cwm Cadlan, Penderyn, CF44 0YJ None None None NaN Fantastic little B&B with 3 rooms, all en-suit... NaN From Penderyn, follow Cwm Cadlan road from Lam... willow.walks@hotmail.co.uk None {'lat': 51.7823, 'lon': -3.4959} None 4042 None NaN Beili Helyg Guest House +44 0 1685 813609 £80 per double room per night NaN Brecon Beacons National Park None landmark http://www.beilihelygguesthouse.co.uk
1 sleep Harbour Island, North Eleuthera, Bahamas None None None NaN Valentines is the most vibrant and exciting lu... NaN None None None {'lat': 25.49725, 'lon': -76.63674} None 8848 None NaN Valentines Resort & Marina (866) 389-6864 None NaN Eleuthera None landmark http://www.valentinesresort.com/
2 sleep None None None None NaN Small, friendly and relaxed hostel, offering b... NaN El Urú 120, Puerto Iguazú, info@porambahostel.com None {'lat': -25.59587, 'lon': -54.567661} None 23350 None NaN Poramba Hostel +54 3757 423041 None NaN Puerto Iguazú None landmark http://porambahostel.com
3 sleep Kauppakatu 52 None None None NaN Centrally located. The shower facilities are s... NaN None None None {'lat': 61.0541, 'lon': 28.1911} None 15189 None NaN Matkustajakoti Turisti-Lappee +358 5 415 0800 double 51 €, single 31€ NaN Lappeenranta None landmark None
4 sleep Lot 27-28, Jalan Muhibbah None None None NaN a 2-star hotel. Rooms with A/C, attached toile... NaN None hpl1@hpl-group.com.my None {'lat': 5.278967, 'lon': 115.241568} None 14992 None NaN Pulau Labuan Hotel +60 87416288 RM128-158 NaN Labuan None landmark http://www.hpl-group.com.my/hpl.html
pd.io.json.json_normalize()
で読み込むと、ネストをフラットにしてdataframeへ変換できます。
geoは、 geo.lat geo.lon に分割されます。
hotels_df = pd.io.json.json_normalize(hotels)
hotels_df.head()
activity address alt checkin checkout city content country directions email fax geo.lat geo.lon hours id image image_direct_url name phone price state title tollfree type url
0 sleep Cwm Cadlan, Penderyn, CF44 0YJ None None None NaN Fantastic little B&B with 3 rooms, all en-suit... NaN From Penderyn, follow Cwm Cadlan road from Lam... willow.walks@hotmail.co.uk None 51.782300 -3.495900 None 4042 None NaN Beili Helyg Guest House +44 0 1685 813609 £80 per double room per night NaN Brecon Beacons National Park None landmark http://www.beilihelygguesthouse.co.uk
1 sleep Harbour Island, North Eleuthera, Bahamas None None None NaN Valentines is the most vibrant and exciting lu... NaN None None None 25.497250 -76.636740 None 8848 None NaN Valentines Resort & Marina (866) 389-6864 None NaN Eleuthera None landmark http://www.valentinesresort.com/
2 sleep None None None None NaN Small, friendly and relaxed hostel, offering b... NaN El Urú 120, Puerto Iguazú, info@porambahostel.com None -25.595870 -54.567661 None 23350 None NaN Poramba Hostel +54 3757 423041 None NaN Puerto Iguazú None landmark http://porambahostel.com
3 sleep Kauppakatu 52 None None None NaN Centrally located. The shower facilities are s... NaN None None None 61.054100 28.191100 None 15189 None NaN Matkustajakoti Turisti-Lappee +358 5 415 0800 double 51 €, single 31€ NaN Lappeenranta None landmark None
4 sleep Lot 27-28, Jalan Muhibbah None None None NaN a 2-star hotel. Rooms with A/C, attached toile... NaN None hpl1@hpl-group.com.my None 5.278967 115.241568 None 14992 None NaN Pulau Labuan Hotel +60 87416288 RM128-158 NaN Labuan None landmark http://www.hpl-group.com.my/hpl.html
変換したhotel_dfの概要
8076レコード数
25カラム
altのデータ数は、1179個(NaNが6897個)
でRの結果と同じですね
hotels_df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 8076 entries, 0 to 8075
Data columns (total 25 columns):
activity 8076 non-null object
address 7108 non-null object
alt 1179 non-null object
checkin 1405 non-null object
checkout 1479 non-null object
city 376 non-null object
content 8076 non-null object
country 443 non-null object
directions 3356 non-null object
email 3048 non-null object
fax 1638 non-null object
geo.lat 8076 non-null float64
geo.lon 8076 non-null float64
hours 37 non-null object
id 8076 non-null int64
image 120 non-null object
image_direct_url 93 non-null object
name 8076 non-null object
phone 6690 non-null object
price 5095 non-null object
state 344 non-null object
title 8076 non-null object
tollfree 598 non-null object
type 8076 non-null object
url 6945 non-null object
dtypes: float64(2), int64(1), object(22)
memory usage: 1.5+ MB
④入力したデータの利用
altの詳細とgeoデータのプロットをしてみます
hotels_df['alt'].value_counts(dropna=False)
NaN 6897
Peak District Cottages 4
Best Western 3
Bed and Breakfast 2
formerly Etap Hotel 2
Buda Panzió 2
formerly Etap 2
Готель Україна 2
Arresø 2
Napsugár Üdülő 2
Krogenberg Hegn 2
Peaceful stay in the sacred valley 2
Hostel 2
Гостиница «Интурист» 2
Near Castellana Grotte, Zoosafari and Alberobello 2
formerly Four Points by Sheraton 2
Гостиница Турист 2
野中温泉 1
Ukulhas Inn 1
info@dahliainn.com 1
名寄サンピラーユースホステル 1
Гостиница Stone 1
Hotel Los Cantaros 1
Felső-erdei Vendégház 1
沙流川温泉 ひだか高原荘 1
バックパッカーズ宮島 1
千姫物語 1
formerly Casa de las Chimeneas 1
Hotel Tókert Szálloda és Étterem 1
Отель "Miran International" 1
...
Alfréd Panzió 1
ริกก้า อินท์ 1
Готельний комплекс Viсtoria 1
鳥海大平キャンプ場 1
Кафе Польський Дім 1
Las Gaviotas Hotel & Apartments 1
Formerly Village Haven Motel 1
Belvárosi apartman 1
Napoleon Hotel Rome 1
Mátyás Hotel*** 1
Kristály Hotel*** 1
Ciklámen Faházak 1
ออรั่ม เดอะริเวอร์เพลส 1
Banyan Bed and Breakfast 1
にしめ湯っ娘ランド 1
Pirwa backpackers La Paz 1
Jagermeister Panzió 1
神戸ポートピアホテル 1
慢慢來民宿 1
Kirkenes Snøhotell 1
Nopola cottages 1
formerly "Green Court Hotel" 1
(forgot its name) 1
Árpád Panzió 1
Спутник 1
Relais Santa Chiara 1
''Khan HaShayarot'' 1
上士幌航空公園キャンプ場 1
宮沢海岸オートキャンプ場キャンパルわかみ 1
HI-Itasca State Park 1
Name: alt, Length: 1161, dtype: int64
import matplotlib.pyplot as plt
plt.scatter(hotels_df['geo.lon'],hotels_df['geo.lat'])
おまけ load関数での読み込み
github内のhotels.jsonは文字列でしたが、jsonフォルダ内のデータはjson形式でしたのでこちらも読み込んでみました。
'Review'と'HotelInfo'のkeyからなる辞書として読み込まれてます
with open('72572.json', encoding='utf-8') as f:
hotel = json.load(f)
hotel.keys()
dict_keys(['Reviews', 'HotelInfo'])
Reviewsは233レコードあるので、これをdataframeに変換
json形式の場合は、一括で読み込み可能なので楽です
元のデータに合わせて読み込みを変えていく必要があります
jsn_pd = pd.io.json.json_normalize(jsn['Reviews'])
jsn_pd.head()
Author AuthorLocation Content Date Ratings.Business service (e.g., internet access) Ratings.Check in / front desk Ratings.Cleanliness Ratings.Location Ratings.Overall Ratings.Rooms Ratings.Service Ratings.Sleep Quality Ratings.Value ReviewID Title
0 gowharr32 Boston We enjoyed the Best Western Pioneer Square. My... March 29, 2012 NaN NaN 5 5 5.0 5 4 4 4 UR126946257 “Excellent Hotel & Location”
1 Nancy W Madison, Wisconsin Great visit to Seattle thanks to our stay at t... March 27, 2012 NaN NaN NaN NaN 5.0 NaN NaN NaN NaN UR126795011 “Great Visit to Seattle!”
2 Janet H Ketchikan, Alaska Great Location,short walk from Amtrak station,... March 27, 2012 NaN NaN 5 5 5.0 5 5 5 5 UR126715331 “Excellent in Everyway”
3 TimothyFlorida Florida Accommodation in Seattle can be expensive. Thi... March 24, 2012 NaN NaN 5 5 5.0 4 5 4 5 UR126585393 “Great hotel, location & price.”
4 KarenArmstrong_BC Armstrong, BC Very cool old building in a great location. Ch... March 13, 2012 NaN NaN 4 5 4.0 3 3 3 3 UR126067021 “Cool place”