唆のメモ

ラボに配属されて遺伝子発現解析などでデータ解析とかが必要になりそうな大学生の技術学習メモ。あくまでもメモです。もし、このブログを参考にする場合は自己責任でお願いします。

Pandas DataFrameのサブクラス

DataFrameに格納されたデータに対してルーティンで施す処理が多いので、DataFrameのサブクラスを作成して、そこにメソッドをつけようとしたら苦戦したのでメモ

サブクラス作成

まずは必要なライブラリをimport

import pandas as pd
import numpy as np
import copy

クラスを作成。単純なmethodをつける。

class MyDataFrame(pd.DataFrame):
    def __init__(self,data,school):
        super( MyDataFrame,self).__init__(data)
        self.school=school
        
    def showschool(self):
        print(self.school)

インスタンスを作成し、操作してみる。

data=[['Kumiko', 1, 'euphonium'], ['Reina', 1, 'trumpet'], ['Asuka', 3, 'euphonium'], ['Yuko', 2, 'trumpet']]
mdf=MyDataFrame(data,'Kitauji')
mdf.index=['Omae', 'Kosaka', 'Tanaka', 'Yoshikawa']
mdf.columns=['name', 'grade', 'instrument']
print(mdf)
print(type(mdf))
mdf.showschool()

出力

            name  grade instrument
Omae       Kumiko      1  euphonium
Kosaka      Reina      1    trumpet
Tanaka      Asuka      3  euphonium
Yoshikawa    Yuko      2    trumpet
<class '__main__.MyDataFrame'>
Kitauji

上手くいっていそうな気がする。

ところが

DataFrame.copy()を流用すると、

mdf2=mdf.copy()
print(type(mdf2))

出力

<class 'pandas.core.frame.DataFrame'>

なんと(当たり前と言えば当たり前だが)、元のDataFrameクラスのインスタンスに戻っている。DataFrame.copy()はDataFrameクラスのインスタンスを返すようにできているからだろう。

必要に応じて自作クラスを返すように定義するしかないらしい。

例えば、

class MyDataFrame(pd.DataFrame):
    def __init__(self,data,school):
        super( MyDataFrame,self).__init__(data)
        self.school=school
        
    def showschool(self):
        print(self.school)
        
    def copy(self):
        cp=MyDataFrame(data=self, school=self.school)
        attr=copy.deepcopy(self.__dict__)
        cp.__dict__.update(attr)
        return cp
    
    def __copy__(self):
        return self.copy()
    
    def __deepcopy__(self,memo):
        return self.copy()

これで、

mdf2=mdf.copy()
print(type(mdf2))
mdf2.showschool()

出力

<class '__main__.MyDataFrame'>
Kitauji

上手くいったようだ。

locやilocも同様にしたいのだけど、もともとどういう実装になっているのかわからなくて調査中。いいやり方があったら教えてほしい。