こんにちは、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は、色々なところで「よきにはからって」くれますが、このように不思議な現象を起こすこともあるようです。