In [ ]:
import io
import numpy as np
import pandas as pd
import plotly_express as px
In [ ]:
# MASTER ONLY
import ast
# imports %%solution, %%submission, %%template etc.
%load_ext prog_edu_assistant_tools.magics
from prog_edu_assistant_tools.magics import report, autotest
lang:en In this unit, we will get acquainted with a couple of simple techniques to change the data:
Let's start with reading the data.
lang:ja この講義では、簡単なデータの変換を紹介します。
まずはデータを読み込みましょう。
In [ ]:
# データをCVSファイルから読み込みます。 Read the data from CSV file.
df = pd.read_csv('data/15-July-2019-Tokyo-hourly.csv')
In [ ]:
print("データフレームの行数は %d" % len(df))
print(df.dtypes)
df.head()
lang:en Let's consider the question of how one should hold an umbrella when it rains. Depending on the wind direction, it's better to slant the umbrella towards the direction the rain is coming from. Therefore, one needs to know the wind direction when it rains. First step is to limit the data to the hours when there was rain. To accomplish that, we filter the data set by using a condition. The condition is placed in square brackets after the dataframe.
Technical details:
df['Precipitation_mm']
extracts a single column as a pandas Series
object.df['Precipitation_mm'] > 0'
is evaluated as a vector expression, that computes
the condition element-wise, resulting in a Series
object of the same length with boolean elements
(true or false).True
. Note that the original
data frame is left unmodified. Instead, a new copy of a data lang:ja雨の中の傘の持ち方について考えましょう。風の向きによって、適切な持ち方が変わります。風が来ている方向に傾けると傘の効率がよくなります。 したがって、雨のときの風の向きを調べなければいけません。 まずは雨のなかったデータを除きましょう。そのために条件をつけてデータをフィルターします。 条件はデータフレームの参照の後に角括弧に入ります。
詳しく述べると:
df['Precipitation_mm']
は一つの列を抽出します。それはpandasのSeries
オブジェクトになります。df['Precipitation_mm'] > 0'
は各行ごとに評価されます、真理値のベクターになります。それもSeries
です。長さはデータフレームの行数です。結果のデータフレームは新しいデータフレームです。既存のデータフレームは変わらないままで、フィルターされたデータフレームを新しい変数に保存します。
In [ ]:
# This is an example of filtering rows by a condition
# that is computed over variables in the dataframe.
# 条件によってデータフレームをフィルターします。
df2 = df[df['Precipitation_mm'] > 0]
len(df2)
lang:en So it was 11 hours out of 24 in a day that the rain was falling. Let's see what the distribution of wind directions was.
lang:ja 一日の24時間の中に雨が降っていたは11時間がありました。 風の向きを可視化しましょう。 px.histogram
はx
の値を数えて、個数を棒グラフとして可視化します。
In [ ]:
px.histogram(df2, x='WindDirection_16compasspoints')
lang:en Now we can clearly see that NE was the prevailing wind direction while it rained.
Note that the result may have been different if we did not filter for the hours with rain:
lang:ja雨が降ったときに風はNEの方向に吹いたことがわかります。雨だけのデータにフィルターしなければ、グラフは異なる結果がえられます。
以下はdf
は元のデータフレームで、フィルターされたデータフレームはdf2
です。
In [ ]:
px.histogram(df, x='WindDirection_16compasspoints')
lang:en We can plot the whole data and use the color dimension to distinguish between hours when it rained or not by using a different technique: instead of filtering rows by some condition, we can introduce the condition as a new boolean variable. This is done by assigning to a new column in the data frame:
lang:jaフィルターに変わりに、可視化によって同じデータを確認ができます。たとえば、雨が降ったかどうかを色で表現します。
そのために新しい真理値の列を作らなければなりません。以下の例はdf
のデータフレームに新しい列を追加します。
In [ ]:
# This creates a new column named "rained" that is a boolean variable
# indicating whether it was raining in that hour.
# 新しい真理値の列'rained'を追加します。
df['rained'] = df['Precipitation_mm'] > 0
px.histogram(df, x='WindDirection_16compasspoints', color='rained')
lang:en Now let's consider how could we present the same data in a tabular form. If we do not do anything, all existing columns in the data frame would be shown, which may make it hard for the reader to see the point of the author. To make reading the data easier, we can limit the data output just to columns we are interested in.
lang:ja 今まで解析してきたデータを表の形に表示について考えましょう。 df
のデータフレームをそのまま表示するとたくさんの列が出て、
どのデータを見せたかったのはとてもわかりにくくなります。 それを解決するために、見せたい列だけを抽出しましょう。
In [ ]:
# そのままだとデータが多すぎて混乱しやすい。
# その表を見せてなにがいいたいのか分かりづらい。
df
In [ ]:
# 列の名前の一覧を見ましょう。
df.dtypes
In [ ]:
# Indexing by list of column names returns a copy of the data frame just with the named
# columns.
# 列の名前を二重角括弧に入れると、列の抽出ができます。 列の名前は以上の`dtypes`の一覧によって確認できます。
df[['Time_Hour', 'WindDirection_16compasspoints', 'rained']]
lang:en
Starting with the weather data frame df
defined above, filter out the data set consisting only of the day hours when sun was shining (i.e. variable SunshineDuration_h
> 0), and containing only the following columns:
Time_Hour
-- extracted from the original data frame.WindDirection_16compasspoints
-- extracted from the original data frame.rained
-- the boolean indicator of whether it was raining or not (Precipitation_mm > 0
). This is a new column that is not present in the original data, so it should be added.lang:ja
以上に定義したdf
のデータフレームを使って、以下のデータの表を抽出しましょう。
SunshineDuration_h
> 0)以下の列だけを抽出しましょう。
Time_Hour
-- 元のデータフレームから抽出しましょう。WindDirection_16compasspoints
-- 元のデータフレームから抽出しましょう。rained
-- 雨があったかどうかの真理値列 (すなわち、Precipitation_mm > 0
)。こちらの列は元のデータに入ってないため、追加しなければなりません。
In [ ]:
%%solution
""" # BEGIN PROMPT
# Note: you can do multiple steps to get the data frame you need.
# 複数の段階に分けてデータ処理してもよい。
df['rained'] = df[...]
sunny_df = df[...]
sunny_df = sunny_df[...]
""" # END PROMPT
# BEGIN SOLUTION
df['rained'] = df['Precipitation_mm'] > 0
sunny_df = df[df['SunshineDuration_h'] > 0]
sunny_df = sunny_df[['Time_Hour', 'WindDirection_16compasspoints', 'rained']]
# END SOLUTION
lang:enNote: if you see a warning SettingWithCopyWarning
, it means that you are trying to apply transformation
to a data frame that is a copy or a slice of a different data frame. This is an optimization that Pandas
library may do on filtering steps to reduce memory use. To avoid this warning, you can either move the new column computation before the filtering step, or add a .copy()
call to the filtered data frame to force
creating of a full data frame object.
lang:jaもしSettingWithCopyWarning
のエラーが出たら、データフレームのコピーに変更を行うという意味なのです。pandas
は、データ抽出のときに
自動的にコピーしないような最適化の副作用です。解決のために、データ変更は先にするか、抽出の後に.copy()
を呼び出すことができます。
In [ ]:
# Inspect the data frame
sunny_df
In [ ]:
%%studenttest StudentTest
# Test your solution
assert len(sunny_df) == 2, "The result data frame should only have 2 rows, yours has %d" % len(sunny_df)
assert np.sort(np.unique(sunny_df['Time_Hour'])).tolist() == [13, 14], "Sunshine was during 13h,14h, but you got %s" % sunny_df['Time_Hour']
assert np.all(sunny_df['rained'] == False), "It was not raining during sunshine hours!"
In [ ]:
%%inlinetest AutograderTest
# This cell will not be present in the students notebook.
assert 'sunny_df' in globals(), "Did you define the data frame named 'sunny_df' in the solution cell?"
assert sunny_df.__class__ == pd.core.frame.DataFrame, "Did you define a data frame named 'sunny_df'? 'sunny_df' was a %s instead" % sunny_df.__class__
assert len(sunny_df) == 2, "The data frame should have 2 rows, but you have %d" % len(sunny_df)
assert np.sort(np.unique(sunny_df['Time_Hour'])).tolist() == [13, 14], "Sunshine was during 13h,14h, but you got %s" % sunny_df['Time_Hour']
assert np.all(sunny_df['rained'] == False), "It was not raining during sunshine hours!"
assert np.all(np.sort(np.unique(sunny_df.columns)) == ['Time_Hour', 'WindDirection_16compasspoints', 'rained']), ("Expected to see 3 columns: rained, Time_Hour, WindDirection_16compasspoints, but got %d: %s" % (len(np.unique(sunny_df.columns)), np.sort(np.unique(sunny_df.columns))) )
In [ ]:
%%submission
df['rained'] = df['Precipitation_mm'] > 0
sunny_df = df[df['SunshineDuration_h'] > 0]
#sunny_df = sunny_df[['Time_Hour', 'WindDirection_16compasspoints', 'rained']]
In [ ]:
import re
result, logs = %autotest AutograderTest
assert re.match(r'Expected to see 3 columns.*', str(result.results['error']))
report(AutograderTest, results=result.results, source=submission_source.source)