!date
!python --version
Fri Apr 11 03:29:22 AM UTC 2025
Python 3.11.12
14. 数値データに対する前処理コード例#
変更履歴
2024年5月: quilt 周りで不具合あり。そこでquiltは使用せず、別途データセットをファイルとして用意して利用するように修正。本コードを実行する際には、別に用意している
youtuber.xlsx
をダウンロードしてから実行してください。2025年4月11日: matplotlib => plotlyに変更。
ref.
preprocess methods
data: YouTuberデータセット公開してみた
全体の流れ
データセットの準備。
数値データに対する前処理の例
手法1:バイナリ化
手法2:アドホックな離散化
手法3:統計的な離散化
手法4:ログスケール化
デフォルトとログスケールとの比較
手法5:標準化
手法6:min-maxスケーリング
特徴ベクトルに対する前処理の例
手法7:正規化
手法8:正規分布への写像
デフォルトとbox-cox写像との比較
14.1. 環境構築#
#!pip install quilt
#!quilt install haradai1262/YouTuber
14.2. データセットの準備#
#from quilt.data.haradai1262 import YouTuber
import numpy as np
import pandas as pd
#import matplotlib.pyplot as plt
import plotly.express as px
import plotly.graph_objects as go
#df = YouTuber.channels.UUUM()
#df = YouTuber.channel_videos.UUUM_videos()
df = pd.read_excel("youtuber.xlsx")
# check the descriptive statistics of numerical data
df.describe()
viewCount | likeCount | favoriteCount | dislikeCount | commentCount | TopicIds | idx | |
---|---|---|---|---|---|---|---|
count | 6.627900e+04 | 64256.000000 | 66289.0 | 64256.000000 | 65997.000000 | 0.0 | 66289.000000 |
mean | 4.545539e+05 | 3233.703390 | 0.0 | 296.430014 | 533.418807 | NaN | 235.730136 |
std | 1.328105e+06 | 9768.090605 | 0.0 | 1633.734833 | 2253.437482 | NaN | 142.868881 |
min | 0.000000e+00 | 0.000000 | 0.0 | 0.000000 | 0.000000 | NaN | 1.000000 |
25% | 3.907100e+04 | 266.000000 | 0.0 | 23.000000 | 55.000000 | NaN | 111.000000 |
50% | 1.214190e+05 | 776.000000 | 0.0 | 67.000000 | 150.000000 | NaN | 229.000000 |
75% | 3.512260e+05 | 2260.000000 | 0.0 | 201.000000 | 394.000000 | NaN | 357.000000 |
max | 8.664236e+07 | 630051.000000 | 0.0 | 213677.000000 | 227598.000000 | NaN | 501.000000 |
# the description of data frame
df.head()
id | title | description | liveBroadcastContent | tags | publishedAt | thumbnails | viewCount | likeCount | favoriteCount | ... | commentCount | caption | definition | dimension | duration | projection | TopicIds | relevantTopicIds | idx | cid | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | R7V5d94XkGQ | 【大食い】超高級寿司店で3人で食べ放題したらいくらかかるの!?【大トロ1カン2,000円】 | 提供:ポコロンダンジョンズ\n\n\n\niOS:https://bit.ly/2sGgOR... | none | ['ヒカキン', 'ヒカキンtv', 'hikakintv', 'hikakin', 'ひか... | 2018-06-30T04:00:01.000Z | https://i.ytimg.com/vi/R7V5d94XkGQ/default.jpg | 2244205.0 | 27703.0 | 0 | ... | 8647.0 | False | hd | 2d | PT21M16S | rectangular | NaN | ['/m/02wbm', '/m/019_rr', '/m/019_rr', '/m/02w... | 1 | UCZf__ehlCEBPop___sldpBUQ |
1 | 2R9_bkcWNd4 | 【女王集結】女性YouTuberたちと飲みながら本音トークしてみたら爆笑www | しばなんチャンネルの動画\n\n\n\nhttps://www.youtube.com/wa... | none | ['ヒカキン', 'ヒカキンtv', 'hikakintv', 'hikakin', 'ひか... | 2018-06-29T08:00:01.000Z | https://i.ytimg.com/vi/2R9_bkcWNd4/default.jpg | 1869268.0 | 30889.0 | 0 | ... | 8859.0 | False | hd | 2d | PT18M38S | rectangular | NaN | ['/m/04rlf', '/m/02jjt', '/m/02jjt'] | 2 | UCZf__ehlCEBPop___sldpBUQ |
2 | EU8S-zxS9PI | 【悪質】偽物ヒカキン許さねぇ…注意してください!【なりすまし】 | ◆チャンネル登録はこちら↓\n\n\n\nhttp://www.youtube.com/us... | none | ['ヒカキン', 'ヒカキンtv', 'hikakintv', 'hikakin', 'ひか... | 2018-06-27T08:38:55.000Z | https://i.ytimg.com/vi/EU8S-zxS9PI/default.jpg | 1724625.0 | 33038.0 | 0 | ... | 11504.0 | False | hd | 2d | PT6M12S | rectangular | NaN | ['/m/04rlf', '/m/02jjt', '/m/02jjt'] | 3 | UCZf__ehlCEBPop___sldpBUQ |
3 | 5wnfkIfw0jE | ツイッターのヒカキンシンメトリーBotが面白すぎて爆笑www | ◆チャンネル登録はこちら↓\n\n\n\nhttp://www.youtube.com/us... | none | ['ヒカキン', 'ヒカキンtv', 'hikakintv', 'hikakin', 'ひか... | 2018-06-25T07:46:07.000Z | https://i.ytimg.com/vi/5wnfkIfw0jE/default.jpg | 1109029.0 | 25986.0 | 0 | ... | 6852.0 | False | hd | 2d | PT6M31S | rectangular | NaN | ['/m/04rlf', '/m/02jjt', '/m/02jjt'] | 4 | UCZf__ehlCEBPop___sldpBUQ |
4 | -6duBsde_XM | 【放送事故】酒飲みながら東海オンエア×ヒカキンで質問コーナーやったらヤバかったwww | 提供:モンスターストライク\n\n\n\n▼キャンペーンサイトはこちら\n\n\n\nhtt... | none | ['ヒカキン', 'ヒカキンtv', 'hikakintv', 'hikakin', 'ひか... | 2018-06-21T08:00:00.000Z | https://i.ytimg.com/vi/-6duBsde_XM/default.jpg | 1759797.0 | 33923.0 | 0 | ... | 4517.0 | False | hd | 2d | PT27M7S | rectangular | NaN | ['/m/098wr', '/m/019_rr', '/m/02wbm', '/m/019_... | 5 | UCZf__ehlCEBPop___sldpBUQ |
5 rows × 21 columns
# column 'viewCount''
df['viewCount'].sort_values()
viewCount | |
---|---|
24426 | 0.0 |
14789 | 0.0 |
16400 | 0.0 |
12752 | 0.0 |
47228 | 0.0 |
... | ... |
45854 | NaN |
45856 | NaN |
45860 | NaN |
45864 | NaN |
45865 | NaN |
66289 rows × 1 columns
“NaN” = Not a Numberの略で直訳すると「数字ではない」。データセットでは欠落しており、データフレームとして読み込むと NaN として保存されることが多い。必要に応じて別途対応が必要。例えばこれらを説明変数として扱うと想定外の動作となることがある。
# drop samples including NaN & 0 on 'viewCount'
print('orig_num = ', len(df))
print('num of NaN = ', df['viewCount'].isna().sum())
df = df[df['viewCount'].notnull()]
print('after_num = ', len(df))
df = df[df['viewCount'] != 0]
print('after_num2 = ', len(df))
orig_num = 66289
num of NaN = 10
after_num = 66279
after_num2 = 66231
df['viewCount'].describe()
viewCount | |
---|---|
count | 6.623100e+04 |
mean | 4.548834e+05 |
std | 1.328530e+06 |
min | 2.000000e+00 |
25% | 3.919150e+04 |
50% | 1.215850e+05 |
75% | 3.515195e+05 |
max | 8.664236e+07 |
# 1枚目: リニアスケール
fig1 = go.Figure()
fig1.add_trace(go.Histogram(x=df['viewCount'], nbinsx=100))
fig1.update_xaxes(title_text='ViewCount')
fig1.update_yaxes(title_text='Frequency')
fig1.update_layout(
title='histgram of viewCount (linear)',
height=500, width=700
)
fig1.show()
# 2枚目: ログスケール
fig2 = go.Figure()
fig2.add_trace(go.Histogram(x=df['viewCount'], nbinsx=100))
fig2.update_xaxes(title_text='ViewCount')
fig2.update_yaxes(title_text='Frequency (log)', type='log')
fig2.update_layout(
title='histgram of viewCount (log)',
height=500, width=700
)
fig2.show()
14.3. 数値データに対する前処理の例#
14.3.1. 手法1:バイナリ化(binarization)#
# preprocess method 1: binarization by mean value
THRESHOLD = df['viewCount'].mean()
new_column = df['viewCount'] > THRESHOLD
new_column = np.where(new_column == True, 1, 0)
temp = pd.DataFrame(df['viewCount'])
temp['binary'] = new_column
temp.head()
viewCount | binary | |
---|---|---|
0 | 2244205.0 | 1 |
1 | 1869268.0 | 1 |
2 | 1724625.0 | 1 |
3 | 1109029.0 | 1 |
4 | 1759797.0 | 1 |
14.3.2. 手法2:アドホックな離散化(ad-hoc discretization)#
# preprocess method 2: discretization 1, ad-hoc division
floor = 10000
new_column = np.floor_divide(df['viewCount'], floor)
temp['discret_floor'] = new_column
temp.head()
viewCount | binary | discret_floor | |
---|---|---|---|
0 | 2244205.0 | 1 | 224.0 |
1 | 1869268.0 | 1 | 186.0 |
2 | 1724625.0 | 1 | 172.0 |
3 | 1109029.0 | 1 | 110.0 |
4 | 1759797.0 | 1 | 175.0 |
# default (logスケール)
fig3 = go.Figure()
fig3.add_trace(go.Histogram(x=temp['viewCount'], nbinsx=100))
fig3.update_xaxes(title_text='viewCounts')
fig3.update_yaxes(title_text='Freqency (log)', type='log')
fig3.update_layout(
title='default',
height=500, width=700
)
fig3.show()
# discret_floor (logスケール)
fig4 = go.Figure()
fig4.add_trace(go.Histogram(x=temp['discret_floor'], nbinsx=100))
fig4.update_xaxes(title_text='discret_floor')
fig4.update_yaxes(title_text='Freqency (log)', type='log')
fig4.update_layout(
title='discret_floor',
height=500, width=700
)
fig4.show()
14.3.3. 手法3:統計的な離散化#
# preprocess method 3: discretization 2, quantilzation
discret_num = 4
ranges = np.linspace(0, 1, discret_num)
data = df['viewCount'].quantile(ranges)
data
viewCount | |
---|---|
0.000000 | 2.000000e+00 |
0.333333 | 5.913133e+04 |
0.666667 | 2.408843e+05 |
1.000000 | 8.664236e+07 |
new_column = pd.qcut(df['viewCount'], discret_num, labels=False)
temp['discret_quantile'] = new_column
temp
viewCount | binary | discret_floor | discret_quantile | |
---|---|---|---|---|
0 | 2244205.0 | 1 | 224.0 | 3 |
1 | 1869268.0 | 1 | 186.0 | 3 |
2 | 1724625.0 | 1 | 172.0 | 3 |
3 | 1109029.0 | 1 | 110.0 | 3 |
4 | 1759797.0 | 1 | 175.0 | 3 |
... | ... | ... | ... | ... |
66284 | 131489.0 | 0 | 13.0 | 2 |
66285 | 13271.0 | 0 | 1.0 | 0 |
66286 | 76266.0 | 0 | 7.0 | 1 |
66287 | 282447.0 | 0 | 28.0 | 2 |
66288 | 6900.0 | 0 | 0.0 | 0 |
66231 rows × 4 columns
# default (logスケール)
fig5 = go.Figure()
fig5.add_trace(go.Histogram(x=temp['viewCount'], nbinsx=100))
fig5.update_xaxes(title_text='viewCounts')
fig5.update_yaxes(title_text='Freqency (log)', type='log')
fig5.update_layout(
title='default',
height=500, width=700
)
fig5.show()
# discret_quantile (logスケール)
fig6 = go.Figure()
fig6.add_trace(go.Histogram(x=temp['discret_quantile'], nbinsx=discret_num*2))
fig6.update_xaxes(title_text='viewCounts (discret_quantile={})'.format(discret_num))
fig6.update_yaxes(title_text='Freqency (log)', type='log')
fig6.update_layout(
title='discret_quantile',
height=500, width=700
)
fig6.show()
14.3.4. 手法4:ログスケール化(log-scaling)#
# preprocess method 4: log-scaling
new_column = np.log10(df['viewCount'] + 1)
temp['log10'] = new_column
temp.head()
viewCount | binary | discret_floor | discret_quantile | log10 | |
---|---|---|---|---|---|
0 | 2244205.0 | 1 | 224.0 | 3 | 6.351063 |
1 | 1869268.0 | 1 | 186.0 | 3 | 6.271672 |
2 | 1724625.0 | 1 | 172.0 | 3 | 6.236695 |
3 | 1109029.0 | 1 | 110.0 | 3 | 6.044943 |
4 | 1759797.0 | 1 | 175.0 | 3 | 6.245463 |
14.3.5. デフォルトとログスケールとの比較#
# default
fig7 = go.Figure()
fig7.add_trace(go.Histogram(x=temp['viewCount'], nbinsx=100))
fig7.update_xaxes(title_text='viewCounts')
fig7.update_yaxes(title_text='Freqency')
fig7.update_layout(
title='default',
height=500, width=700
)
fig7.show()
# log10
fig8 = go.Figure()
fig8.add_trace(go.Histogram(x=temp['log10'], nbinsx=100))
fig8.update_xaxes(title_text='viewCounts')
fig8.update_yaxes(title_text='Freqency')
fig8.update_layout(
title='log10',
height=500, width=700
)
fig8.show()
14.3.6. 手法5:標準化(standardization)#
from sklearn import preprocessing
data = np.array(df['viewCount'].values, dtype='float64')
data = data.reshape(len(data), 1)
new_column = preprocessing.scale(data)
temp['standardization'] = new_column
temp.head()
viewCount | binary | discret_floor | discret_quantile | log10 | standardization | |
---|---|---|---|---|---|---|
0 | 2244205.0 | 1 | 224.0 | 3 | 6.351063 | 1.346854 |
1 | 1869268.0 | 1 | 186.0 | 3 | 6.271672 | 1.064632 |
2 | 1724625.0 | 1 | 172.0 | 3 | 6.236695 | 0.955757 |
3 | 1109029.0 | 1 | 110.0 | 3 | 6.044943 | 0.492387 |
4 | 1759797.0 | 1 | 175.0 | 3 | 6.245463 | 0.982231 |
mean = np.mean(new_column)
var = np.var(new_column)
print('mean = ', mean, ', var = ', var)
temp['standardization'].describe()
mean = 1.2873900181367037e-17 , var = 1.0
standardization | |
---|---|
count | 6.623100e+04 |
mean | 1.287390e-17 |
std | 1.000008e+00 |
min | -3.423971e-01 |
25% | -3.128985e-01 |
50% | -2.508795e-01 |
75% | -7.780379e-02 |
max | 6.487481e+01 |
# default (logスケール)
fig9 = go.Figure()
fig9.add_trace(go.Histogram(x=temp['viewCount'], nbinsx=100))
fig9.update_yaxes(type='log')
fig9.update_xaxes(title_text='viewCounts')
fig9.update_yaxes(title_text='Freqency')
fig9.update_layout(
title='default',
height=500, width=700
)
fig9.show()
# standardization (logスケール)
fig10 = go.Figure()
fig10.add_trace(go.Histogram(x=temp['standardization'], nbinsx=100))
fig10.update_yaxes(type='log')
fig10.update_xaxes(title_text='viewCounts')
fig10.update_yaxes(title_text='Freqency (log)')
fig10.update_layout(
title='standaridization',
height=500, width=700
)
fig10.show()
14.3.7. 手法6:min-maxスケーリング(Min-Max scalering)#
"""
min = data.min(axis=0)
max = data.max(axis=0)
new_column = (data - min) / (max - min)
temp['min-max'] = new_column
temp.head()
"""
new_column = preprocessing.minmax_scale(df['viewCount'])
temp['min-max'] = new_column
temp.head()
viewCount | binary | discret_floor | discret_quantile | log10 | standardization | min-max | |
---|---|---|---|---|---|---|---|
0 | 2244205.0 | 1 | 224.0 | 3 | 6.351063 | 1.346854 | 0.025902 |
1 | 1869268.0 | 1 | 186.0 | 3 | 6.271672 | 1.064632 | 0.021575 |
2 | 1724625.0 | 1 | 172.0 | 3 | 6.236695 | 0.955757 | 0.019905 |
3 | 1109029.0 | 1 | 110.0 | 3 | 6.044943 | 0.492387 | 0.012800 |
4 | 1759797.0 | 1 | 175.0 | 3 | 6.245463 | 0.982231 | 0.020311 |
# default
fig11 = go.Figure()
fig11.add_trace(go.Histogram(x=temp['viewCount'], nbinsx=100))
fig11.update_yaxes(type='log')
fig11.update_xaxes(title_text='viewCounts')
fig11.update_yaxes(title_text='Freqency (log)')
fig11.update_layout(
title='default',
height=500, width=700
)
fig11.show()
# min-max
fig12 = go.Figure()
fig12.add_trace(go.Histogram(x=temp['min-max'], nbinsx=100))
fig12.update_yaxes(type='log')
fig12.update_xaxes(title_text='viewCounts (min-max)')
fig12.update_yaxes(title_text='Freqency (log)')
fig12.update_layout(
title='min-max',
height=500, width=700
)
fig12.show()
14.3.8. 手法7:正規分布への写像(Mapping to a Gaussian distribution)#
pt = preprocessing.PowerTransformer(method='box-cox', standardize=False)
orig = df['viewCount'].values.reshape(-1,1)
new_column = pt.fit_transform(orig)
temp['box-cox'] = new_column
temp.head()
viewCount | binary | discret_floor | discret_quantile | log10 | standardization | min-max | box-cox | |
---|---|---|---|---|---|---|---|---|
0 | 2244205.0 | 1 | 224.0 | 3 | 6.351063 | 1.346854 | 0.025902 | 15.286493 |
1 | 1869268.0 | 1 | 186.0 | 3 | 6.271672 | 1.064632 | 0.021575 | 15.086986 |
2 | 1724625.0 | 1 | 172.0 | 3 | 6.236695 | 0.955757 | 0.019905 | 14.999159 |
3 | 1109029.0 | 1 | 110.0 | 3 | 6.044943 | 0.492387 | 0.012800 | 14.518429 |
4 | 1759797.0 | 1 | 175.0 | 3 | 6.245463 | 0.982231 | 0.020311 | 15.021171 |
14.3.9. デフォルトとBox-Cox写像との比較#
# default
fig13 = go.Figure()
fig13.add_trace(go.Histogram(x=temp['viewCount'], nbinsx=100))
fig13.update_yaxes(type='log')
fig13.update_xaxes(title_text='viewCounts')
fig13.update_yaxes(title_text='Freqency (log)')
fig13.update_layout(
title='default',
height=500, width=700
)
fig13.show()
# box-cox
fig14 = go.Figure()
fig14.add_trace(go.Histogram(x=temp['box-cox'], nbinsx=100))
fig14.update_xaxes(title_text='viewCounts')
fig14.update_yaxes(title_text='Freqency')
fig14.update_layout(
title='box-cox',
height=500, width=700
)
fig14.show()
# 似ている分布、log-scaledとの比較
# log10
fig15 = go.Figure()
fig15.add_trace(go.Histogram(x=temp['log10'], nbinsx=100))
fig15.update_xaxes(title_text='viewCounts (log-scaled)')
fig15.update_yaxes(title_text='Freqency')
fig15.update_layout(
title='log10',
height=500, width=700
)
fig15.show()
14.4. 特徴ベクトルに対する前処理の例#
14.4.1. 手法8:正規化(normalization)#
正規化という考え方自体は特徴量(データセットを表と見た時の列)に対しても適用できる。ここでは特徴ベクトル(行)に対して適用した際の値を観察する。
NOTE: the process target is NOT one feature value (one column). The target of normalization is “feature vector (one row)”.
temp.head()
viewCount | binary | discret_floor | discret_quantile | log10 | standardization | min-max | box-cox | |
---|---|---|---|---|---|---|---|---|
0 | 2244205.0 | 1 | 224.0 | 3 | 6.351063 | 1.346854 | 0.025902 | 15.286493 |
1 | 1869268.0 | 1 | 186.0 | 3 | 6.271672 | 1.064632 | 0.021575 | 15.086986 |
2 | 1724625.0 | 1 | 172.0 | 3 | 6.236695 | 0.955757 | 0.019905 | 14.999159 |
3 | 1109029.0 | 1 | 110.0 | 3 | 6.044943 | 0.492387 | 0.012800 | 14.518429 |
4 | 1759797.0 | 1 | 175.0 | 3 | 6.245463 | 0.982231 | 0.020311 | 15.021171 |
normalized_l2 = preprocessing.normalize(temp, norm='l2')
normalized_l2 = pd.DataFrame(normalized_l2, columns=temp.columns)
normalized_l2.head()
viewCount | binary | discret_floor | discret_quantile | log10 | standardization | min-max | box-cox | |
---|---|---|---|---|---|---|---|---|
0 | 1.0 | 4.455921e-07 | 0.000100 | 0.000001 | 0.000003 | 6.001473e-07 | 1.154169e-08 | 0.000007 |
1 | 1.0 | 5.349688e-07 | 0.000100 | 0.000002 | 0.000003 | 5.695449e-07 | 1.154169e-08 | 0.000008 |
2 | 1.0 | 5.798362e-07 | 0.000100 | 0.000002 | 0.000004 | 5.541823e-07 | 1.154169e-08 | 0.000009 |
3 | 1.0 | 9.016897e-07 | 0.000099 | 0.000003 | 0.000005 | 4.439801e-07 | 1.154168e-08 | 0.000013 |
4 | 1.0 | 5.682474e-07 | 0.000099 | 0.000002 | 0.000004 | 5.581503e-07 | 1.154169e-08 | 0.000009 |
sum = 0
for item in normalized_l2.values[0]:
sum += item ** 2
print('L2 norm = ', sum)
L2 norm = 0.9999999999999999
14.5. 演習#
dislikeCountの出現頻度をヒストグラムとして描画してみよう。数値はそのまま用いるものとする。ビン数は50とすること。
1のヒストグラムにおいて、ビン数を10〜100の間で変更し、描画されるグラフへの影響を確認してみよう。
1のヒストグラムにおいて、カウント数をlogスケールで描画してみよう。
1のヒストグラムにおいて、カウント数を標準化して描画してみよう。
1のヒストグラムにおいて、カウント数をBox-Cox写像して描画してみよう。
前処理なし、logスケール、標準化、Box-Cox写像、各々によるヒストグラム上の違いを確認してみよう。