こんにちは、PyQ開発チームの斎藤です。
PyQへの質問で、pandas関連の質問をご紹介します。 なお、質問内容は、適宜アレンジしています。
質問
2つの表を管理しています。片方の表を更新してマージしているのですが、うまくできたりできなかったりします。何故でしょうか?
表は、pandas.DataFrameとして扱っているそうです。 更新直後は正しくマージできないで、一度ファイルに保存して読み込み直すと正しく保存できるそうです。 不思議ですね。
このときは、実際のデータを見ていないので「一度ファイルに保存して読み込み直すとできる」をヒントとして予想を回答しました。 確認してもらったところ、その通りの原因だったようです。
具体例
実際に、上手く行くケースと、上手くいかないケースを、具体例を通して見ていきましょう。 データは、特に意味のないサンプルです。
上手くいくケース
df1 = pd.DataFrame( [['url_1', 1, '2018/09/01'], ['url_1', 2, '2018/09/02']], columns=['url', 'ver', 'date']) df1
url | ver | date | |
---|---|---|---|
0 | url_1 | 1 | 2018/09/01 |
1 | url_1 | 2 | 2018/09/02 |
df2 = pd.DataFrame( [['url_1', 1, 'A'], ['url_1', 2, 'B']], columns=['url', 'ver', 'owner']) df2
url | ver | owner | |
---|---|---|---|
0 | url_1 | 1 | A |
1 | url_1 | 2 | B |
2つの表をマージしてみましょう。
df1.merge(df2, 'outer')
url | ver | date | owner | |
---|---|---|---|---|
0 | url_1 | 1 | 2018/09/01 | A |
1 | url_1 | 2 | 2018/09/02 | B |
これは、期待通りの結果です。正しいケースになります。
上手くいかないケース
では、正しくないケースを再現してみましょう。
df2.ver = df2.ver.astype(str) df1.merge(df2, 'outer')
url | ver | date | owner | |
---|---|---|---|---|
0 | url_1 | 1.0 | 2018/09/01 | NaN |
1 | url_1 | 2.0 | 2018/09/02 | NaN |
2 | url_1 | 1.0 | NaN | A |
3 | url_1 | 2.0 | NaN | B |
原因
ver
列の同じ値の行が別れています。
もちろん、原因は、df1.ver
がint
なのに、df2.ver
がstr
になっているからですね。
実際には、df1
は、最新版をファイルから読んで、ver
はint
でした。
しかし、df2.ver
はスクレイピングして更新しており、str
でした。
従って、そのままだと上手く行きませんでした。
しかし、一旦、ファイルに保存してから読み込むと、pandasが上手いこと考えて自動的にver
列をint
にしてくれます。
そのため、ファイルを経由すると上手くいっていたのです。
pandasは、色々なところで「よきにはからって」くれますが、このように不思議な現象を起こすこともあるようです。