71326


pandasで.jsonファイルを読み取り、データの更新をして保存するコードを書いています。  
以下のような二つのデータフレームがあり、連結し、  
重複したデータが出ないように果物と店の列を重複したものを  
`df.drop_duplicates(subset=['fruit', 'store'])`で削除しています。

[code]

    df1 = pd.DataFrame({'fruit':['apple', 'orange', 'banana'], 'price': [300, 200, 150], 'store': ['A', 'B', 'C']})
    df2 = pd.DataFrame({'fruit':['apple', 'orange', 'banana', 'strawberry'], 'price': [300, 200, 200, 120], 'store': ['A', 'C', 'C', 'A']})
    pd.concat([df1, df2]).drop_duplicates(subset=['fruit', 'store'], ignore_index=True)
    
[/code]

[code]

        　　fruit  price store
    0       apple    300     A
    1      orange    200     B
    2      banana    150     C
    3      orange    200     C
    4  strawberry    120     A
    
[/code]

重複データは削除したいのですが、追加データの価格だけは更新したく、  
以下のようなデータフレームにしたいと考えています。  
何かシンプルで良い方法はありませんでしょうか。

[code]

    　　　　fruit  price store
    0       apple    300     A
    1      orange    200     B
    2      banana    200     C
    3      orange    200     C
    4  strawberry    120     A
    
[/code]

`drop_duplicates`を`keep='last'`で後者のデータを残せばよいのですが、  
データの順序を変えたくなく、良い方法を探しています。  
よろしくお願いします。

【2020/10/21 追記】  
おおよそ解決したのですが、仮にもっとデータの列があった場合、  
例えば連結したデータフレームが以下のように'rank'があったとします。

[code]

            fruit  price store     rank
    0       apple    300     A  Awesome
    1      orange    200     B    Great
    2      banana    150     C     Good
    3       apple    300     A  Awesome
    4      orange    200     C     Good
    5      banana    200     C     Good
    6  strawberry    120     A    Great
    
[/code]

重複を削除し、`'rank'`のデータは更新せずに`'price'`だけを更新したく、  
私は以下のようにコードを記述しました。

[code]

    for x in dfx.groupby(['fruit', 'store']).groups.items():
    　  if len(x[1]) > 1:
           dfx.iloc[x[1][-1]]['price'], dfx.iloc[x[1][0]]['price'] = dfx.iloc[x[1][0]]['price'].copy(), dfx.iloc[x[1][-1]]['price'].copy()
    
[/code]

しかし以下のメッセージが生じ、SettingWithCopyWarningが出ました。

[code]

     A value is trying to be set on a copy of a slice from a DataFrame
    See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
    
[/code]

やっていることに間違いがない気がし、エラーのメッセージもデータが連鎖していることが原因だと思うのですが解決方法が思いつきませんでした。

何か良い解決方法があればよろしくお願いします。


CC BY-SA 4.0
2020-10-19T07:51:51.423
71323
2020-10-21T15:06:37.090
2020-10-21T00:49:47.187
42380
42380
question
python python3 pandas
pandasの重複したデータの更新


> 【2020/10/21 追記】  
>  おおよそ解決したのですが、仮にもっとデータの列があった場合、例えば連結したデータフレームが以下のように'rank'があったとします。
[code]

>             fruit  price store     rank
>     0       apple    300     A  Awesome
>     1      orange    200     B    Great
>     2      banana    150     C     Good
>     3       apple    300     A  Awesome
>     4      orange    200     C     Good
>     5      banana    200     C     Good
>     6  strawberry    120     A    Great
>  
[/code]

`SettingWithCopyWarning`
を回避するために、[pandas.DataFrame.iloc](https://pandas.pydata.org/pandas-
docs/stable/reference/api/pandas.DataFrame.iloc.html)
ではなく、[pandas.DataFrame.loc](https://pandas.pydata.org/pandas-
docs/stable/reference/api/pandas.DataFrame.loc.html) を使います。  
また、値をスワップする必要はなく、各グループ内の先頭(最初)の価格データに末尾(最後)の価格をコピーするだけにしています。

[code]

    import pandas as pd
    df1 = pd.DataFrame({
      'fruit': ['apple', 'orange', 'banana'],
      'price': [300, 200, 150],
      'store': ['A', 'B', 'C'],
       'rank': ['Awesome', 'Great', 'Good']
    })
    df2 = pd.DataFrame({
      'fruit': ['apple', 'orange', 'banana', 'strawberry'],
      'price': [300, 200, 200, 120],
      'store': ['A', 'C', 'C', 'A'],
       'rank': ['Awesome', 'Good', 'Good', 'Great']
    })
    
    dfx = pd.concat([df1, df2], ignore_index=True)
    for x in dfx.groupby(['fruit', 'store']).groups.items():
      if len(x[1]) > 1:
        dfx.loc[x[1][0], 'price'] = dfx.loc[x[1][-1], 'price']
    
    dfx.drop_duplicates(subset=['fruit', 'store'], ignore_index=True, inplace=True)
    print(dfx)
    
    =>
            fruit  price store     rank
    0       apple    300     A  Awesome
    1      orange    200     B    Great
    2      banana    200     C     Good
    3      orange    200     C     Good
    4  strawberry    120     A    Great
    
[/code]

~~シンプルで良い方法、ではありませんが、`pandas.DataFrame.groupby`
でグループ化した後、それぞれのグループ内で、先頭(最初)と末尾(最後)の index 値に対応する行を入れ替えます(swap)。この状態で
`drop_duplicates` を実行すると、`price` の値は最後に追加したデータの値になります。

[code]

    dfx = pd.concat([df1, df2], ignore_index=True)
    for x in dfx.groupby(['fruit', 'store']).groups.items():
      if len(x[1]) > 1:
        ## swap head and tail
        dfx.iloc[x[1][-1]], dfx.iloc[x[1][0]] = dfx.iloc[x[1][0]].copy(), dfx.iloc[x[1][-1]].copy()
    
    dfx.drop_duplicates(subset=['fruit', 'store'], ignore_index=True, inplace=True)
    print(dfx)
    
    =>
            fruit  price store
    0       apple    300     A
    1      orange    200     B
    2      banana    200     C
    3      orange    200     C
    4  strawberry    120     A
    
[/code]

~~


CC BY-SA 4.0
2020-10-19T11:00:14.803
71326
2020-10-21T15:06:37.090
2020-10-21T15:06:37.090
71323
answer