Python
 Computer >> コンピューター >  >> プログラミング >> Python

Python Pandasでテンプレートを活用してDataFrameに新しい行を追加する方法

PythonのPandasライブラリを使って、テンプレートを活用しながらDataFrameに新しい行を追加する方法を解説します。

はじめに

データエンジニアリングのスペシャリストとして働いていると、派生列(カラム)を作成する機会の方が、行(レコード)そのものを作成する機会よりも多くなりがちです。分析用データの生成や送信は、本来ならデータベースの専門チームが担当すべき役割だからです。しかし、常にそうとは限りません。

データ専門チームからの納品を待つ代わりに、サンプルとなる行を自分で作成しなければならない場面も出てきます。本記事では、行をスマートに作成するための便利なテクニックを紹介します。

実装の流れ

このレシピでは、まず小さなデータセットに対して.loc属性を使って行を追加する方法から始め、続いて.appendメソッドの使い方を見ていきます。

ステップ1:行を追加するためのDataFrameを作成する

まずは、後ほど行を追加していく基礎となるDataFrameを作成しましょう。

import pandas as pd
import numpy as np

players_info = pd.DataFrame(data=[
{"players": "Roger Federer", "titles": 20},
{"players": "Rafael Nadal", "titles": 20},
{"players": "Novak Djokovic", "titles": 17},
{"players": "Andy Murray", "titles": 3}], columns=["players", "titles"])

出力結果

print(players_info.info())
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 2 columns):
#   Column   Non-Null Count  Dtype 
---  ------   --------------  ----- 
0   players  4 non-null      object
1   titles   4 non-null      int64 
dtypes: int64(1), object(1)
memory usage: 192.0+ bytes
None

ステップ2:.loc属性で新しい選手を追加する

次に、.loc属性を使って新しい選手「Dominic Thiem」をDataFrameに追加してみましょう。

new_Player = ['Dominic Thiem', 1]
players_info.loc[4] = new_Player

出力結果

print(players_info)
          players  titles
0   Roger Federer      20
1    Rafael Nadal      20
2   Novak Djokovic      17
3     Andy Murray       3
4   Dominic Thiem       1

ステップ3:辞書型で新しい行を追加する

同じく.loc属性を使って、今度は辞書型のデータを行として追加してみます。len(players_info)をインデックスに指定することで、常にDataFrameの末尾に追加できるのがポイントです。

new_player = {'players': 'Daniel Medvedev', 'titles': 0}
players_info.loc[len(players_info)] = new_player

出力結果

print(players_info)
           players  titles
0   Roger Federer      20
1    Rafael Nadal      20
2   Novak Djokovic      17
3     Andy Murray       3
4   Dominic Thiem       1
5  Daniel Medvedev       0

ステップ4:Seriesオブジェクトで行を追加する

PandasのSeriesオブジェクトに格納したデータを追加することも可能です。

players_info.loc[len(players_info)] = pd.Series({'players': 'Andy Zverev', 'titles': 0})

出力結果

print(players_info)
           players  titles
0   Roger Federer      20
1    Rafael Nadal      20
2   Novak Djokovic      17
3     Andy Murray       3
4   Dominic Thiem       1
5  Daniel Medvedev       0
6     Andy Zverev       0

まとめ:.locメソッドによる追加

ここまで4つのステップで.locメソッドを使ってデータを追加してきました。.loc属性は元のDataFrameを直接変更(in-place)する点が特徴です。

次に紹介するのは.appendメソッドです。こちらは呼び出し元のDataFrameを変更せず、行を追加した新しいコピーを返します。.appendの第一引数には、別のDataFrame、Series、辞書、またはリストを指定できます。

.appendメソッドの使い方と注意点

まずはインデックス付きのDataFrameを作成し直します。

# インデックス付きのDataFrameを作成
players_info = pd.DataFrame(data=[
{"players": "Roger Federer", "titles": 20},
{"players": "Rafael Nadal", "titles": 20},
{"players": "Novak Djokovic", "titles": 17},
{"players": "Andy Murray", "titles": 3}], columns=["players", "titles"],
index=["roger", "nadal", "djokovic", "murray"])

続いて、辞書型のデータを.appendメソッドで追加してみます。

# 辞書型の新しい行を.appendメソッドで追加
players_info.append({'players': 'Daniel Medvedev', 'titles': 0})

すると、以下のようなエラーが発生しました。

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
in
      1 # Add a new row(dictionary) to DataFrame using .append method.
----> 2 players_info.append({'players': 'Daniel Medvedev', 'titles': 0})

TypeError: Can only append a Series if ignore_index=True or if the Series has a name

辞書を追加しようとしたところ、「ignore_index=Trueパラメータを使うように」という例外が発生しました。指示通りにパラメータを追加して、挙動を確認してみましょう。

new_df = players_info.append({'players': 'Daniel Medvedev', 'titles': 0}, ignore_index=True)

出力結果

print(f" *** Original with index \n {players_info} \n\n\n *** Modified index \n {new_df}")
*** Original with index
           players  titles
roger  Roger Federer      20
nadal   Rafael Nadal      20
djokovic Novak Djokovic     17
murray   Andy Murray        3

*** Modified index
           players  titles
0   Roger Federer      20
1    Rafael Nadal      20
2   Novak Djokovic      17
3     Andy Murray       3
4  Daniel Medvedev       0

出力結果から何がわかるでしょうか?そう、ignore_index=Trueを設定すると、元のインデックスは完全に削除され、0からn-1までのRangeIndexに置き換えられます。

.appendメソッドは、複数の行を一度にまとめて追加したい場合に特に便利です。

player1 = pd.Series({'players': 'Andy Zverev', 'titles': 0}, name='zverev')
player2 = pd.Series({'players': 'Dominic Thiem', 'titles': 1}, name='theim')
new_df_1 = players_info.append([player1, player2])

出力結果

print(new_df_1)
            players  titles
roger   Roger Federer      20
nadal    Rafael Nadal      20
djokovic Novak Djokovic     17
murray    Andy Murray        3
zverev    Andy Zverev        0
theim    Dominic Thiem       1

注意: DataFrame.append()メソッドはPandas 1.4以降で非推奨となり、Pandas 2.0で削除されました。最新バージョンでは、代わりにpd.concat([df, new_row], ignore_index=True)を使用してください。

多数のカラムを持つDataFrameへの行追加:テンプレート活用術

行追加の基本がわかったところで、次は多くのカラムを持つDataFrameへの行追加方法を見ていきましょう。

df = pd.read_csv("https://raw.githubusercontent.com/sasankac/TestDataSet/master/movies_data.csv")

出力結果

print(df.info())
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4803 entries, 0 to 4802
Data columns (total 12 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   budget             4803 non-null   int64  
 1   id                 4803 non-null   int64  
 2   original_language  4803 non-null   object 
 3   original_title     4803 non-null   object 
 4   popularity         4803 non-null   float64
 5   release_date       4802 non-null   object 
 6   revenue            4803 non-null   int64  
 7   runtime            4801 non-null   float64
 8   status             4803 non-null   object 
 9   title              4803 non-null   object 
 10  vote_average       4803 non-null   float64
 11  vote_count         4803 non-null   int64  
dtypes: float64(3), int64(4), object(5)
memory usage: 450.4+ KB
None

このGoogle提供のデータセットには12個のカラムがあります。手作業で新しい行のデータを入力する場合、カラム名の入力ミスや入力忘れが起こりやすいのが実情です。この問題をどう回避すればよいのでしょうか?答えはシンプル、カラム名のテンプレートを作成することです。

columns_dictionary = df.iloc[0].to_dict()

出力結果

print(columns_dictionary)
{'budget': 237000000, 'id': 19995, 'original_language': 'en', 'original_title': 'Avatar', 'popularity': 150.437577, 'release_date': '10/12/2009', 'revenue': 2787965087, 'runtime': 162.0, 'status': 'Released', 'title': 'Avatar', 'vote_average': 7.2, 'vote_count': 11800}

お気づきでしょうか?最初の行を取り出して辞書型に変換したのです。これでカラム名と値の両方が取得できました。次に、辞書内包表記を使って古い値をクリアします。文字列だった値は空文字列に、それ以外は欠損値(NaN)に置き換えましょう。

こうしてできた辞書は、これから入力したいあらゆる新規データのテンプレートとして使えます。

テンプレートの作成例

import datetime

new_data_dict = {}
for a, b in columns_dictionary.items():
    if isinstance(b, str):
        new_data_dict[a] = np.random.choice(list('abcde'))
    elif isinstance(b, datetime.date):
        new_data_dict[a] = np.nan
    else:
        new_data_dict[a] = np.nan

出力結果

print(new_data_dict)
{'budget': nan, 'id': nan, 'original_language': 'e', 'original_title': 'a', 'popularity': nan, 'release_date': 'b', 'revenue': nan, 'runtime': nan, 'status': 'e', 'title': 'c', 'vote_average': nan, 'vote_count': nan}

まとめ

本記事では、PandasのDataFrameに新しい行を追加する複数の方法を学びました。

  • .loc属性:元のDataFrameを直接変更しながら行を追加できる。リスト・辞書・Seriesいずれにも対応。
  • .appendメソッド:元のDataFrameを変更せず、新しいコピーを返す。複数行の一括追加に便利だが、最新のPandasではpd.concatへの移行が必要。
  • テンプレート化:既存の行を辞書に変換して値をクリアしておけば、カラム数の多いDataFrameでも入力ミスを防げる。

特にカラム数の多い実務データでは、テンプレートを活用することで作業効率と正確性が大きく向上します。ぜひ日々のデータ処理に取り入れてみてください。

  1. PythonでpandasのDataFrameをCSVファイルに書き込む方法【to_csv()の使い方】

    pandasのDataFrameをCSVファイルに出力する基本 PythonでpandasのDataFrameをCSVファイルに書き込むには、to_csv()メソッドを使用します。このメソッドは、DataFrameの内容をそのままCSV形式で保存できる、最もシンプルで一般的な方法です。 まずはサンプルデータとして、リストを値にもつ辞書を作成しましょう。 # リストの辞書を定義 d = {Car: [BMW, Lexus, Audi, Mercedes, Jaguar, Bentley], Date_of_purchase: [2020-10-10, 2020-10-12, 2020-

  2. 【Python】Pandas DataFrameからnull(欠損値)行を削除する方法|dropna()の使い方

    PandasのDataFrameからnull(NaN)行を削除するには、dropna()メソッドを使用します。この記事では、NaNを含むCSVファイルを読み込み、dropna()で欠損値を含む行を取り除くまでの手順を、サンプルコードと実行結果とともにわかりやすく解説します。前提:NaNを含むCSVファイル今回の例では、一部にNaN(null値)が含まれる以下のようなCSVファイル(CarRecords.csv)を使用します。手順1:read_csv()でCSVファイルを読み込むまずpandasをインポートし、read_csv()を使ってCSVファイルを読み込みます。ここではデスクトップ上に保存