初心者データサイエンティストの備忘録

調べたことは全部ここに書いて自分の辞書を作る

pandas.mergeできないときは型を意識する

すごい基本的なことで、かつ調べればすぐわかることですがメモしておきます。

下記のような2つのデータフレームをカラムkeyで結合します。結合の仕方はなんでも良いです。

図1:結合対象のDatFrame

結合するときのスクリプトは下記の通りです。

import pandas as pd
pd.merge(left_df, right_df, on=["key"], how="outer")

ところが結合したら、left_dfとright_dfのkeyを同じものと認識してくれず、図2のようになってしまいました。

図2:意図しない結合結果

理由を調べてみると、keyの型が違うことが原因でした。具体的には、下記のスクリプトを書いて確かめました。 (スクリプト中の -> は出力結果を表しています)

print(type(left_df["key"][0]))
# -> <class 'str'>


print(type(right_df["key"][0]))
# -> <class 'int'>

keyの型が違うことがわかったので、型を揃えて結合させればOKですね。今回は、right_dfのkeyの型をstrにして結合させます。

right_df["key"] = right_df["key"].astype(str)

無事に意図したとおりの出力ができました。

図3:意図通りの結合

Pythonの@propertyの振る舞い

Pythonで@propertyがよくわからなかったので、色々調べてみた。
正直、完璧に理解した感はないが、一旦分かった範囲でまとめてみる。

@propertyとは?

3.4. プロパティ - ゼロから学ぶ Python」よると、@propertyを下記のように説明している。

クラスのメンバで変数のように参照することのできる関数のことをプロパティといいます

ということで、ごく簡単なスクリプトを書いて確認してみる。

class Test:
    def __init__(self, a):
        self._a = a
        
    @property
    def a(self):
        return self._a
    
    def func1(self):
        return self.a

test = Test(a=1)
print(test.func1())

# -> 1 が表示される

func1の中でメソッドaをself.aで呼び出していることがポイント。本来、aはメソッドなので、カッコをつけたself.a()として呼び出す必要がある。しかし、@propertyのお陰で変数のような形式で呼び出すことができている。

@propertyを使う場面

オブジェクト指向設計実践ガイド(下記の本)によれば、すべてのインスタンス変数は隠蔽すべきとのこと。 したがって、変数を直接扱うのではなく、メソッドaをはさみ、隠蔽することが必要だ。その際、@propertyを設定することで、a()ではなくa単体を書けばよいのでコードが少しシンプルになるということらしい。

注意

上記と似たようなコードだが、下記は動かない。

class Test:
    def __init__(self, a):
        self.a = a # 変数aに_がなくなった
        
    @property
    def a(self):
        return self.a
    
    def func1(self):
        return self.a

test = Test(a=1)
print(test.func1())

# エラー:can't set attributeを出力する

これは、変数aとメソッドaの名前が同じだからエラー:can't set attributeを出力してしまう。
なので、propertyを使うときは、必ず_を前に一つつけた変数を用意しましょう。
※_を前にひとつつけた変数は、慣習的にそのクラスの外では使わない変数を指すようです。

【読書記録】オブジェクト指向設計実践ガイド 第1章まとめ

体系的にオブジェクト指向の設計方法を学ぶため、本書を読み始めました。
本書を読んで、過去に自分が作成したダメコードの拡張性を高めたいと思っています。

今回は第1章「オブジェクト指向設計」の要点をまとめようと思います。第1章はポエム的な感じで、コードは出てきません。
私も箇条書きで要点をまとめておくくらいにとどめておこうと思います。

要点まとめ

原則・デザインパターン・メトリクスについて書かれた記事

【読書記録】アダルト・チャイルドが自分と向きあう本

本書を手に取った理由

アダルト・チャイルドからの回復法を調べているうちに、この本にたどり着きました。

以前記事にした本との比較

以前記事にした本は、こちらです。

(前回記事) aisinkakura-datascientist.hatenablog.com

こちらの本は、アダルト・チャイルドの特徴を知るには良かったです。
しかし、回復の方法を知るには、今回紹介する本の方が適切な気がします。 アダルト・チャイルドの特徴は既に知っており、回復法を知りたい方は今回記事にした本を読むと良いと思います。

本書の内容

本書には、アダルト・チャイルドから回復するためのワークが複数記載されております。
図1は、アダルト・チャイルドの特徴とワークの目的、問いをまとめたものです。
各特徴を改善するためのワークに線を引いています。
また、「代表的な問い」とは各ワークで問いかけられる質問です。
この質問に答えることをきっかけとして、私たちアダルト・チャイルドは自分と向き合うことができ、それが回復につながります。

図1:ACの特徴とワーク

感想

本書の良いところは、ACからの回復に焦点を当てて書かれていることです。
ACに限らず、よくやってしまう間違いは、自分をカテゴライズすることで満足してしまい、そこからの改善を図ろうとしないことだと私は思っています。
ACについてもそれは起きがちで、ACの特徴を見て「私は(僕は)ACなのだ!」とカテゴライズして安心してしまう方もいるのではないでしょうか?
その点、本書はACの特徴や各人のステータスに応じたワークが紹介されており、非常に良かったです。

私事になってしまいますが、このワークに取り組む前に、図1中の「特定したパターンから得られるメッセージを意識的に否定すること」が偶然できたことがあります。
それは音楽を聴くことに関してです。
私の親はなんでも禁止するタイプで、高校生まで読書・テレビ視聴・音楽を聴くこと・友人と遊ぶことなどは親の許可が必要でした。
そのためなのか、私は今でもテレビ視聴・音楽を聴くこと・遊ぶことに罪悪感を持っています。これらのことをしようとすると、精神的な圧迫感を感じたり、口が乾き、心拍数が上がるという身体的な症状が現れたりします。 しかし、先日電車に乗っているときに、周囲の音楽を聴いている人たちを見て、「そうか音楽を聴くことは悪いことではないんだ!!」と思う瞬間がありました。 そのとき、強烈な解放感を得ることができましたし、親から受けていた間違ったメッセージを否定することができたという確信がありました。
それ以降、何か罪悪感を感じるときは「別に悪いことをしているわけではない」と意識的に親から受けたメッセージを否定するようにしています。
そのお陰か、最近は強いうつ状態にならずに済むようになってきました。だから、本書を読み、ACから回復するワークの一つとして、「特定したパターンから得られるメッセージを意識的に否定すること」が存在することを知った時には、非常に腹落ちする感覚がありました。

私もそうですが、ACの方々は過去置かれていた環境で培われた、歪んだ価値観をどうしても引きずってしまう傾向にあると思います。それを意識的に断ち切ることが、ACからの回復の礎になるのだと思いました。

おまけ

ワークは一人で取り組むよりも、仲間や専門家とともに取り組んだ方が効果的で安全だと本書に書かれていました。そこで、自分が調べた専門機関を箇条書きで記載しておきます。

【読書記録】生きづらさの正体はアダルトチルドレン。 - その根本原因を解消し、楽な生き方を手に入れる。

本書を手に取った理由

私はうつ状態になり、日常生活に支障が出ることが多々あります。 そんな折、友人が「自分はアダルトチルドレンかもしれない」と言い出したため調べたところ、自分がアダルトチルドレンの特徴に良くあてはまることに気がつきました。 そこで、アダルトチルドレンについての知識を増やすため、本書を手に取りました。

対象の読者

本書は、アダルトチルドレンの基礎知識を得るには良い本だと思います。逆に言えば、アダルトチルドレンの知識を既に持っている人にとっては、物足りないかもしれません。私はアダルトチルドレンについて、ほとんど知識を持っていなかったので非常に役に立ちました。
私の場合、アダルトチルドレンの特徴を知ることが、自分の過去を振り返る契機となり、特に役に立ったと感じています。

アダルトチルドレンの特徴を知り、自分の過去を振り返る

アダルトチルドレンの特徴として「完璧主義である」という特徴が挙げられていました。この特徴を私に当てはめると図1のようになります。

図1:理想と現実

図1で言いたいことは、自分は元来完璧主義ではないのに、家庭環境に適応するために完璧主義になってしまったことです。
私のような元来完璧主義ではない人間は、何事も完璧にこなそうという強い意志もなく、そこに対するメリットを見出すことができません。しかし、完璧主義的発想を後から植え付けられてしまうと、できないのに、理想だけは完璧を目指そうとします。そのため、理想と現実にギャップが生まれます。そのギャップが、今のうつ状態を引き起こす要因の一つであると私は考えました。
このように、私はうつ状態を引き起こす要因の一つを言語化することができました。そういった意味で、アダルトチルドレンの特徴を知ることは私にとって有益でした。

今後の取り組み

本書には、アダルトチルドレンから回復するための方法もいくつか記載されていました。 私は、下記2点に取り組もうと思います。

1.カウンセリングを受ける
本書に下記のように書いてありました。

アダルトチルドレンの改善に最も効果的な方法が、カウンセリングを受けることです。根本的な回復を目指すなら ば、セルフケアだけではどうしても限界があるからです。

これについては、ちょうど勤め先で社外カウンセリング制度が始まったので、利用してみようと思います。カウンセリングはお金がかかるイメージがあったので、非常に助かります。また、カウンセリングの怖いところはエセ心理士に騙されてしまうことです。しかし、会社が契約しているということで、安心感があります。

2.子どもに今までよりも丁寧に接する
本書に記載があったぬいぐるみ療法からヒントを得ました。
ぬいぐるみ療法は、自分が人からして欲しかったことを、ぬいぐるみにしてあげることで癒しを得る療養法だそうです。私の場合、ぬいぐるみではなく子どもに対して色々してあげることが、子どものためにも自分のためにもなると思いました。
では、自分が親からして欲しかったことは何か?それは、子どもをもっとよく見て子育てをすることです。 そのため、私は子どもをよく観察し、子どもが親にして欲しいことを感じ取り、子育てをしていこうと思います。
例としては、子どもを抱っこしてあげる時間を増やそうと思います。我が子は抱っこされることが本当に好きで「すぐに抱っこして」とアピールします。基本的にはすぐに抱っこしているのですが、家事をしている最中はどうしても後回しになってしまうこともあります。ですが、子どもが生まれて1年半の時間が経過し、親も片手でできることが増えてきました。片手でできる家事をしながら、子どもを抱っこするということを意識していこうと思います。
「子どもが親にしてもらいたいことは何か?」ということを子育てのベースにしていこうと思います。

まとめ

本書を読むことで、アダルトチルドレンの特徴や改善の方向性を知ることができます。本書だけでは、根本的な回復は難しいと思いますが、「自分がアダルトチルドレンかも」と思う人にはとても良いと思います。

継承できないメソッド・変数

車輪の再開発ですが、Pythonにおいて継承できないメソッド・変数をまとめます。

継承できないメソッド・変数

結論からいうと、__(アンダースコアが2個)が冒頭についているメソッド・変数は継承できません。

次のスクリプトを見てみましょう。

class Parent:
    def __init__(self, v):
        self.v = v
        
    def func(self):
        print(self.v)
        
    def _func(self):
        print(self.v)
        
    def __func(self):
        print(self.v)
        
class Child(Parent):
    def do(self):
        self.func()
        self._func()
        self.__func()
        
child = Child(v=1)
child.do()

このスクリプトは「'Child' object has no attribute '_Child__func'」というエラーが出力されて動きません。 Parentで定義した__funcメソッドにマングリング機構が働き、メソッド名が_Child__funcに変更してしまったためアクセスできなくなりました。

変数についても同じです。

class Parent:
    def __init__(self, v, _v, __v):
        self.v = v
        self._v = _v
        self.__v = __v
        
    def func(self):
        print(self.v)
        print(self._v)
        print(self.__v)
                
class Child(Parent):
    def do(self):
        self.func()
        
child = Child(v=1, _v=2, __v=3)
child.do()

このときは、「__init__() got an unexpected keyword argument '__v'」というエラーを出力してしまいました。

使いどころ

__(アンダースコア2個)の変数は、継承できないことを利用して、名前衝突を防ぐことができます。一番分かりやすいのはコンストラクタ。

class Parent:
    def __init__(self, v):
        self.v = v

class Child(Parent):
    def __init__(self, b):
        self.b = b

Parentの__init__にマングリング機構が働くことで、Childの__init__とは別のメソッドとなるのですね。(今まで、子クラスのコンストラクタで親クラスのコンストラクタをオーバライドしていると思っていましたが、勘違いでした)

まとめ

メソッド・変数ともに__(アンダースコア2個)が付いている場合は、継承できない。

【読書記録】「速習 Python3 オブジェクト指向編」~プログラミングを書く際に意識すること~

本記事は「速習 Python3 オブジェクト指向編」で学んだ内容のうち、プログラミングを書く際に意識することと本書から学べなかったことをまとめました。
この記事は完全に私の備忘録なので、書きたいことを箇条書きで書いていくだけです。粒度もそろっていませんし、順不同です。あまり人の役に立たない記事であることをあらかじめお詫びしておきます。

意識すること

  • データ構造を意識して設計する。要点は下記3点。
    • who:誰がデータを持つのか?
    • what:どんなデータを持つのか?
    • how:どのように持つのか?
  • 「クラス = 構造体(型を指定した変数を複数持っている構造)+ メソッド」ととりあえず理解する。
    例えば、下記の場合クラスExampleの構造体は、a, b、メソッドは__init__とfunc1と理解している。
class Example:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def func1(self):
        print(self.a, self.b)
  • メソッドは、そのクラスが持つデータを操作するような処理に使う。(つまり、クラスの外で定義されたグローバル変数をクラスの中で処理しない)
  • インスタンス生成直後にインスタンス変数を初期化すべきときは、コンストラクタ内で初期化する。
    • 文法的な制約ではなく、可読性の観点からそうすべきとのこと。
  • メソッドや変数は何をクラスの外に見せて、何を外に見せないかきっちり決めて設計する。
  • クラス間のやり取りはツリー構造にすべき。
    例えば、下記クラスにおいてclass B, C間で変数のやり取りがあると複雑になってしまい、設計が難しくなる。

  • 「AがBのインスタンスを持つ」というスタイルでできるだけ設計する。
    継承を避けるべきとのこと。例えば、クラスExample1の変数やメソッドをクラスExample2で使おうと思ったら、下記のように実装すべきとのこと。
class Example1:
    def __init__(self, a):
        self.a = a

class Example2:
    def __init__(self, ex1):
        self.ex1 = Example1(a=1)

ただ、継承を避けるべき理由が私はよくわかっていない。下記を見ると、「基底クラスと派生クラスの役割(責務)の分担が非常に難しい」と書かれているが、その感覚がイマイチわからぬ...。 jp.quora.com まあ、今後クラス設計の経験をたくさん積んでいけば、わかるようになるでしょうということで一旦放置。

  • クラス間のやりとりをする場合は、呼び出し側のクラスにも呼び出される側のクラスにもメソッドが必要。
  • 継承がどうしても必要なときは、呼び出されるメソッドは親クラスに書く。つまり、子クラスではメソッドの内部を変更するくらいにとどめて、新規に新しいメソッドを作らない。
  • グローバル変数は参照するだけにして、書き換えない。
  • クラスやメソッドを定義するときは、ドキュメントを必ず記載する。

残件(学べなかったこと)

  • 設計方法はほとんど学べなかった
    • クラス単位で処理すべきものと、メソッド単位で処理すべきものの違いは何か?
    • クラスはどうやって分ける?