Python {Article023}

ようこそ「Python」へ...

PandasのDataFrameにデータをロードするには

ここではPythonのライブラリの中でもっとも頻繁に利用されるPandasを徹底的に使いこなすために「Python+Pandasシリーズ」として、 PandasのDataFrameにデータをロード(作成)する方法を解説します。 PandasにはExcelファイル、CSVファイル、タブ区切りのテキストファイル、データベースなどからデータを取り込む機能があります。 外部ファイルからデータを取り込む方法については別記事にて解説します。 ここではテスト的に使用する数件のデータを作成する方法を中心に説明します。

余談ですが、Pandasを学ぶには、ここで解説しているように10件くらいのテストデータを作成して学ぶことをお勧めします。 たとえば、Pandasのgroupby(), concat(), merge()メソッドを学ぶときは10件程度の少量のテストデータを作成して検証します。

ここではVisula Studio Code(VSC)の「Python Interactive window」 を使用してJupter(IPython Notebook)のような環境で説明します。 VSCを通常の環境からインタラクティブな環境に切り換えるにはコードを記述するときコメント「# %%」を入力します。 詳しい、操作手順については「ここ」 を参照してください。 インタラクティブな環境では、Pythonの「print(), plt.show()」などを使う必要がないので掲載しているコードでは省略しています。 VSCで通常の環境で使用するときは、必要に応じて「print(), plt.show()」等を追加してください。

この記事では、Pandas、Matplotlibのライブラリを使用しますので 「記事(Article001) | 記事(Article002) | 記事(Article003) | 記事(Article004)」 を参照して事前にインストールしておいてください。 Pythonのコードを入力するときにMicrosoftのVisula Studio Codeを使用します。 まだ、インストールしていないときは「記事(Article001)」を参照してインストールしておいてください。

説明文の左側に図の画像が表示されていますが縮小されています。 画像を拡大するにはマウスを画像上に移動してクリックします。 画像が拡大表示されます。拡大された画像を閉じるには右上の[X]をクリックします。 画像の任意の場所をクリックして閉じることもできます。


プログラム内で定義したデータをPandasのDataFrameにロードする

  1. Pythonのdict型で定義したデータをPandasのDataFrameにロードする

    行2-5ではPythonのライブラリを取り込んでいます。 行6ではPythonの警告メッセージをを抑止しています。 行10-15ではPhtyonに取り込むデータを「dict」型で定義しています。 行16ではPandasのDataFrame()メソッドでDataFrameにデータを取り込んでいます。 行17ではPandasのto_datetime()メソッドでstr型の日付をdatetime型に変換しています。 日付が「yyyy/mm/dd」の形式になっているときに「format='%Y/%m/%d'」のように指定します。 また、日付に時刻「hh:mm:ss」も含まれるときは「format='%Y/%m/%d %H:%M:%S'」のように指定します。
    # Import the necessary libraries
    import pandas as pd
    import datetime as dt
    import numpy as np
    import warnings
    warnings.simplefilter('ignore')
    # %%
    
    # Create DataFrame from dict 
    data = {
        'category_name': ['JavaScript','jQuery','Python','C++','C#'],
        'page_view': [100,150,900,600,700],
        'exclude_me': [False, True, False, False, False],
        'date_added': ['2021-10-01','2021-10-02','2021-10-25','2021-10-30','2021-10-31']
    }
    df = pd.DataFrame(data)
    df['date_added'] = pd.to_datetime(df['date_added'], format='%Y-%m-%d') # Convert string to datetime format
    #df['date_added'] = pd.to_datetime(df['date_added'], format='%Y/%m/%d') # Convert string to datetime format
    #df['date_added'] = pd.to_datetime(df['date_added'], format='%Y/%m/%d %H:%M:%S') # Convert string to datetime format
    #print(df.info())
    click image to zoom!
    図1
    図1はVisual Studio Code(VSC)の画面です。 VSCのインタラクティブ・ウィンドウから「df.info()」、「df.head()」を入力してPandasのDataFrameの構造とデータの中身を表示しています。
  2. Pythonのlist型で定義したデータをPandasのDataFrameにロードする

    行2ではDataFrameのindexのデータをlist型で定義しています。 行3ではDataFrameの列名をlist型で定義しています。 行4ではDataFrameに取り込む空のデータをlist型で定義しています。 行6-9ではlist型の変数「data」にDataFrameのレコード(行)をappend()メソッドで追加しています。 行11ではPandasのDataFrame()メソッドでデータを取り込んでいます。 DataFrameにindexも取り込むときは行12のようにDataFrame()の引数に「index=indices」を追加します。 行13のように特定の列「date_added」を除外することもできます。 行14ではPandasのto_datetime()メソッドでstr型の日付をdatetime型に変換しています。 str型の日付が「yyyy/mm/dd HH:MM:SS」の形式になっているので引数に「format='%Y/%m/%d %H:%M:%S'」を指定しています。
    # Add Rows One By One To Data
    indices = ['a','b','c','d','e']
    columns = ['category_name', 'page_view', 'exclude_me', 'date_added']
    data = []
    data.append(['JavaScript', 100, False, '2021/10/01 11:29:59'])
    data.append(['jQuery', 150, True, '2021/10/02 12:13:15'])
    data.append(['Python', 900, False, '2021/10/25 05:06:59'])
    data.append(['C++', 600, False, '2021/10/30 03:05:02'])
    data.append(['C#', 700, False, '2021/10/31 01:02:03'])
    
    df = pd.DataFrame(data, columns=columns)  
    #df =pd.DataFrame(data, columns=columns, index=indices)  
    #df = pd.DataFrame.from_records(data, exclude=['date_added'], columns=columns, index=indices) 
    df['date_added'] = pd.to_datetime(df['date_added'], format='%Y/%m/%d %H:%M:%S') # Convert string to datetime format
    #print(df)
    click image to zoom!
    図2
    図2はVisual Studio Code(VSC)の画面です。 VSCのインタラクティブ・ウィンドウから「df.info()」、「df.head()」を入力してPandasのDataFrameの構造とデータの中身を表示しています。
  3. PandasのDataFrameにロードされた不正なデータを修正する

    行2-8ではPandasのDataFrameに取り込む列名とデータを定義しています。 ここでは、意図的に不正なデータを定義しています。 ハイライトされている箇所が不正なデータです。 行10ではPandasのDataFrameにデータを取り込んでいます。

    行11ではstr型の日付をdatetime型に変換しています。 ここではPandasのto_datetime()メソッドの引数に「errors='coerce'」を指定しています。 「errors='coerce'」を追加すると不正なデータを検出してもエラーを無視して処理を続行します。 この指定がないと不正なデータを検出すると異常終了します。 日付が不正なときはPandasは「NaT(Not a Time)」を格納します。 行13-14ではPandasのisnull()メソッドで不正なデータ件数を表示しています。

    行17-18では列「page_view」の不正なデータ「NaN(Not a Number)」を「0」で置換しています。 さらに列のデータ型を「int」型に変換しています。 参考までにDataFrameの列に「NaN」が値が含まれているときは、その列のデータ型は「float」型になります。

    行21-22ではDataFrameから「datettime」型の列(Series)を抽出して不正なデータ「NaT(Not a Time)」を今日の日付で置換しています。 行21のselect_dtypes()メソッドでは列「date_added」が抽出されます。 したがって、行22では列「date_added」の不正な日付が置換されます。

    行25-26では列「exclude_me」の不正なデータ「None」を「False」で置換しています。 さらに列「exclude_me」のデータ型を「bool」型に変換しています。 参考までに列に「None」が含まれるときはその列のデータ型は「object(str)」型になります。

    行29では列「category_name」の不正なデータ「None」を「Null Data」に置換しています。
    # Ignore invalid data and fixed it
    columns = ['category_name', 'page_view', 'exclude_me', 'date_added']
    data = []
    data.append(['JavaScript', np.nan, False, '2021/10/01 11:29:59'])   # invalid page_view
    data.append(['jQuery', 200, None, '2021/10/02 12:13:15'])           # a null value exclude_me
    data.append(['Python', 900, False, '9999/99/99 05:06:59'])          # invalid date_added(date)
    data.append(['C++', 600, False, '2021/10/30 99:99:99'])             # invalid date_added(time)
    data.append([None, 700, True, '2021/10/31 01:02:03'])               # a null value category_name
    
    df = pd.DataFrame(data, columns=columns) 
    df['date_added'] = pd.to_datetime(df['date_added'], format='%Y-%m-%d %H:%M:%S', errors='coerce') # Convert string to datetime format => NaT
    
    #print(f'df.isnull().sum():{df.isnull().sum()}')
    #print(f'df.isnull().sum().sum() = {df.isnull().sum().sum()}')
    
    # Fix page_view: NaN => 0, float => int
    df['page_view'] = df['page_view'].fillna(0)
    df['page_view'] = df['page_view'].astype('int')   # int8, int16, int32, int64
    
    # Fix add_added: NaT => today
    dt_cols = df.select_dtypes(include=['datetime'])
    df[dt_cols.columns] = dt_cols.fillna(pd.to_datetime('today'))
    
    # Fix exclude_me: None => False
    df['exclude_me'] = df['exclude_me'].fillna(False)
    df['exclude_me'] = df['exclude_me'].astype('bool')  # boolean
    
    # Fix category_name: None => 'Null Data'
    df['category_name'] = df['category_name'].fillna('Null Data')
    
    #print(f'df.isnull().sum():\n{df.isnull().sum()}')
    #df.info()
    click image to zoom!
    図3-1
    図3-1はソードコードの行11まで実行したときのVSCの画面です。 行11以降はコメントにしています。 まずは、「df.head()」で表示したDataFrameの中身を見てください。 ハイライトしているのが不正な値が格納されている箇所です。 列が「object」型のときは「Null Data」は「None」として表示されます。 列が「int」型のときは不正な値は「NaN(Not a Number)」として表示されます。 列が「bool」型のときは不正な値は「None」として表示されます。 列が「datetime」型のときは不正な値は「NaT(Not a Time)」として表示されます。

    次に「df.info()」で表示したDataFrameの「Dtype」を見てください。 列「page_view」は本来「int」型のはずですが不正なデータ「NaN」があるので「float」型になっています。 なぜかと言えば、「NaN」は「float」型として変換されるからです。 列「exclude_me」は本来「bool」型のはずですが不正なデータ「None」があるので「object(str)」型になっています。 「None」は「object」型として変換されます。 列「date_added」は不正なデータ「NaT」があるのに「datetime」型になっています。 これは、Pandasのto_datetime()メソッドでstr型からdatetime型に変換するとき引数に「errors='coerce'」を指定しているからです。 「errors='coerce'」の指定があると、不正な日付があるときエラーを無視して「NaT」値を格納します。 「NaT」は「datetime」型として変換されます。 ちなみに、「errors='ignore'」を指定したときはエラーを無視して不正な日付をそのまま「object」型として格納します。 したがって列は「object」型になります。 「errors=''」の指定がないときはエラーとなって処理が中断されます。

    click image to zoom!
    図3-2
    図3-2はVSCのインタラクティブ・ウィンドウから「df.isnull().sum()」と「df」を入力して実行した画面です。 通常、PandasのDataFrame()メソッドで取り込んだデータに不正があるかどうかはDataFrameのisnull()メソッドを使用します。 画面に表示されているようにDataFrameには合計5個の不正なデータがあることは分かります。

    click image to zoom!
    図3-3
    図3-3はソードコードの行17-18のコメントを外して実行した後の画面です。 ここではVSCのインタラクティブ・ウィンドウから「df.info()」と「df」を入力して実行しています。 列「page_view」の不正なデータ「NaN」が「0」に置換されています。 そして列のデータ型が「float」型から「int」型に変わっています。

    click image to zoom!
    図3-4
    図3-4はソードコードの行21-22のコメントを外して実行した後の画面です。 ここではVSCのインタラクティブ・ウィンドウから「df.info()」と「df」を入力して実行しています。 列「date_added」の不正なデータ「NaT」が「today」の日付に置換されています。

    click image to zoom!
    図3-5
    図3-5はソードコードの行25-26のコメントを外して実行した後の画面です。 ここではVSCのインタラクティブ・ウィンドウから「df.info()」と「df」を入力して実行しています。 列「exclude_me」の不正なデータ「None」が「False」に置換されています。 そして列のデータ型が「object」型から「bool」型に変わっています。

    click image to zoom!
    図3-6
    図3-6はソードコードの行29のコメントを外して実行した後の画面です。 ここではVSCのインタラクティブ・ウィンドウから「df.info()」と「df」を入力して実行しています。 列「category_name」の不正なデータ「None」が「Null Data」に置換されています。
  4. ここで解説したコードをまとめて掲載

    最後にここで解説したすべてのコードをまとめて掲載しましたので参考にしてください。
    
    # Article023_Python Pandas(Part1) Loading Data(1).py
    # %%
    # Import the necessary libraries
    import pandas as pd
    import datetime as dt
    import numpy as np
    import warnings
    warnings.simplefilter('ignore')
    # %%
    
    # Create DataFrame from dict 
    data = {
        'category_name': ['JavaScript','jQuery','Python','C++','C#'],
        'page_view': [100,150,900,600,700],
        'exclude_me': [False, True, False, False, False],
        'date_added': ['2021-10-01','2021-10-02','2021-10-25','2021-10-30','2021-10-31']
    }
    #print(type(data))
    df = pd.DataFrame(data)
    df['date_added'] = pd.to_datetime(df['date_added'], format='%Y-%m-%d') # Convert string to datetime format
    #df['date_added'] = pd.to_datetime(df['date_added'], format='%Y/%m/%d') # Convert string to datetime format
    #df['date_added'] = pd.to_datetime(df['date_added'], format='%Y/%m/%d %H:%M:%S') # Convert string to datetime format
    #print(df.info())
    
    # %%
    
    # Add Rows One By One To Data
    indices = ['a','b','c','d','e']
    columns = ['category_name', 'page_view', 'exclude_me', 'date_added']
    data = []
    data.append(['JavaScript', 100, False, '2021/10/01 11:29:59'])
    data.append(['jQuery', 150, True, '2021/10/02 12:13:15'])
    data.append(['Python', 900, False, '2021/10/25 05:06:59'])
    data.append(['C++', 600, False, '2021/10/30 03:05:02'])
    data.append(['C#', 700, False, '2021/10/31 01:02:03'])
    
    df = pd.DataFrame(data, columns=columns)  
    #df =pd.DataFrame(data, columns=columns, index=indices)  
    #df = pd.DataFrame.from_records(data, exclude=['date_added'], columns=columns, index=indices) 
    df['date_added'] = pd.to_datetime(df['date_added'], format='%Y/%m/%d %H:%M:%S') # Convert string to datetime format
    #print(df)
    
    # %%
    
    # Ignore invalid data and fixed it
    columns = ['category_name', 'page_view', 'exclude_me', 'date_added']
    data = []
    data.append(['JavaScript', np.nan, False, '2021/10/01 11:29:59'])   # invalid page_view
    data.append(['jQuery', 200, None, '2021/10/02 12:13:15'])           # a null value exclude_me
    data.append(['Python', 900, False, '9999/99/99 05:06:59'])          # invalid date_added(date)
    data.append(['C++', 600, False, '2021/10/30 99:99:99'])             # invalid date_added(time)
    data.append([None, 700, True, '2021/10/31 01:02:03'])               # a null value category_name
    
    df = pd.DataFrame(data, columns=columns) 
    df['date_added'] = pd.to_datetime(df['date_added'], format='%Y-%m-%d %H:%M:%S', errors='coerce') # Convert string to datetime format => NaT
    
    #print(f'df.isnull().sum():\n{df.isnull().sum()}')
    #print(f'df.isnull().sum().sum() = {df.isnull().sum().sum()}')
    
    # Fix page_view: NaN => 0, float => int
    df['page_view'] = df['page_view'].fillna(0)
    df['page_view'] = df['page_view'].astype('int')   # int8, int16, int32, int64
    
    # Fix add_added: NaT => today
    dt_cols = df.select_dtypes(include=['datetime'])
    df[dt_cols.columns] = dt_cols.fillna(pd.to_datetime('today'))
    
    # Fix exclude_me: None => False
    df['exclude_me'] = df['exclude_me'].fillna(False)
    df['exclude_me'] = df['exclude_me'].astype('bool')  # boolean
    
    # Fix category_name: None => 'Null Data'
    df['category_name'] = df['category_name'].fillna('Null Data')
    
    #print(f'df.isnull().sum():\n{df.isnull().sum()}')
    #df.info()
    # %%