【问题标题】:Python/Pandas - Replacing an element in one dataframe with a value from another dataframePython/Pandas - 用另一个数据帧中的值替换一个数据帧中的元素
【发布时间】:2016-11-17 04:37:11
【问题描述】:

我在将一个 pandas DataFrame 中的元素替换为另一个 pandas DataFrame 中的值时遇到问题。为长篇道歉。我试图给出许多中间的例子来澄清我的问题。我使用 Python 2.7.11 (Anaconda 4.0.0, 64bit)。

数据

我有一个包含许多用户项目对的 pandas DataFrame。这个DataFrame(我们称之为initial_user_item_matrix)的形式是:

   userId itemId  interaction
1       1      1            1
2       1      2            0
3       1      3            1
4       1      4            1
5       2      9            1
6       3      3            1
7       3      5            0

此外,我有一个仅包含用户 1 的用户项对的 DataFrame。我将其称为 cold_user_item_matrix,此 DataFrame 的形式为:

   userId itemId  interaction
1       1      1            1
2       1      2            0
3       1      3            1
4       1      4            1

接下来,我有一个带有项目的 numpy ndarray,我称之为 ranked_items。它的形式是:

[9 5 3 4]

最后,我将 initial_user_item_matrix 中用户 1 的交互更改为 NaN,它提供了以下 DataFrame(称为 new_user_item_matrix):

   userId itemId  interaction
1       1      1          NaN
2       1      2          NaN
3       1      3          NaN
4       1      4          NaN
5       2      9            1
6       3      3            1
7       3      5            0

我想达到什么目标?

我想将 new_user_item_matrix(当前为 NaN's)中用户 1 - 项目对的交互更改为 initial_user_item_matrix 中特定交互的值> 如果且仅当项目包含在 ranked_items 数组中。之后,应该删除交互仍为NaN 的所有用户项目对(DataFrame 的行)(用户 1 - itemId 不在 ranked_items 中的项目对)。看看下面的结果集应该是什么样子。

中间结果:

   userId itemId  interaction
1       1      1          NaN
2       1      2          NaN
3       1      3            1
4       1      4            1
5       2      9            1
6       3      3            1
7       3      5            0

最终结果:

   userId itemId  interaction
3       1      3            1
4       1      4            1
5       2      9            1
6       3      3            1
7       3      5            0

我尝试了什么?

这是我的代码:

for item in ranked_items:
    if new_user_item_matrix.loc[new_user_item_matrix['userId']==cold_user].loc[new_user_item_matrix['itemId']==item].empty:
        pass
    else: new_user_item_matrix.replace(to_replace=new_user_item_matrix.loc[new_user_item_matrix['userId']==1].loc[new_user_item_matrix['itemId']==item].iloc[0,2],value=cold_user_item_matrixloc[cold_user_item_matrix['itemId']==item].iloc[0,2],inplace=True)

new_user_item_matrix.dropna(axis=0,how='any',inplace=True)

它有什么作用?它循环遍历 ranked_items 数组中的所有项目。首先,它检查用户 1 是否与项目交互(if 语句的 if 部分)。如果不是,则转到 ranked_items 数组中的下一项(通过)。如果用户 1 确实与项目交互(if 语句的 else 部分),则将用户 1 的交互替换为 new_user_item_matrix(当前为 NaN)中的项目,并替换为用户 1 与 cold_user_item_matrix 中的项目的交互,该项目是 1 或 0(我希望你们都还在我身边)。

出了什么问题?

if 语句的 if 部分没有任何问题。当我尝试替换 new_user_item_matrix (if 语句的 else 部分)中的值时,它会出错。替换特定元素(交互)时,它不仅替换该元素,还替换 new_user_item_matrix 中的 ALL 其他 NaN 值。为了说明,如果循环开始,它首先循环 itemId 的 9 和 5,用户 1 没有与之交互(因此没有任何反应)。接下来,它遍历 itemId 3,userId 1 和 itemId 3 的交互应该从NaN 更改为 0。但它不仅将 userId 1 和 itemId 3 的交互更改为 0,而且用户的所有其他交互1 是NaN 的。给出以下结果集:

   userId itemId  interaction
1       1      1            1
2       1      2            1
3       1      3            1
4       1      4            1
5       2      9            1
6       3      3            1
7       3      5            0

这显然是不正确的,因为 itemId 1 和 2 不在 ranked_items 数组中,因此不应发现它们的真实交互。此外,用户 1 和 itemId 3 的交互 (a 1) 将针对所有交互进行填充(即使它们的交互不是 1 而是 0)。

有谁能帮帮我吗?

【问题讨论】:

  • 我尝试过的其他方法,new_user_item_matrix.loc[new_user_item_matrix['userId']==1].loc[new_user_item_matrix['itemId']==item].iloc[0,2] = cold_user_item_matrix.loc[cold_user_item_matrix['itemId']==item].iloc[0,2],它替换了 else 部分中的语句。这个也不行。

标签: python python-2.7 numpy pandas dataframe


【解决方案1】:

短解决方案

本质上,您想丢弃给定用户的所有项目交互,但只针对排名的项目。

为了使建议的解决方案更具可读性,假设df = initial_user_item_matrix

带有布尔条件的简单行选择(在原始df 上生成只读视图):

filtered_df = df[(df.userID != 1) | df.itemID.isin(ranked_items)]

通过删除“无效”行就地修改数据框的类似解决方案:

df.drop(df[(df.userID == 1) & ~df.itemID.isin(ranked_items)].index, inplace=True)

使用所有中间结构的逐步解决方案

假设上面提到的所有中间工件都是必需的,可以得到期望的结果如下:

import pandas as pd
import numpy as np

initial_user_item_matrix = pd.DataFrame([[1, 1, 1], 
                                        [1, 2, 0], 
                                        [1, 3, 1], 
                                        [1, 4, 1], 
                                        [2, 9, 1], 
                                        [3, 3, 1], 
                                        [3, 5, 0]],
                                        columns=['userID', 'itemID', 'interaction'])
print("initial_user_item_matrix\n{}\n".format(initial_user_item_matrix))

ranked_items = np.array([9, 5, 3, 4]) 

cold_user = 1 

cold_user_item_matrix = initial_user_item_matrix.loc[initial_user_item_matrix.userID == cold_user]
print("cold_user_item_matrix\n{}\n".format(cold_user_item_matrix))

new_user_item_matrix = initial_user_item_matrix.copy()
new_user_item_matrix.ix[new_user_item_matrix.userID == cold_user, 'interaction'] = np.NaN
print("new_user_item_matrix\n{}\n".format(new_user_item_matrix))

new_user_item_matrix.ix[new_user_item_matrix.userID == cold_user, 'interaction'] = cold_user_item_matrix.apply(lambda r: r.interaction if r.itemID in ranked_items else np.NaN, axis=1)
print("new_user_item_matrix after replacing\n{}\n".format(new_user_item_matrix))

new_user_item_matrix.dropna(inplace=True)
print("new_user_item_matrix after dropping nans\n{}\n".format(new_user_item_matrix))

产生

initial_user_item_matrix
   userID  itemID  interaction
0       1       1            1
1       1       2            0
2       1       3            1
3       1       4            1
4       2       9            1
5       3       3            1
6       3       5            0

cold_user_item_matrix
   userID  itemID  interaction
0       1       1            1
1       1       2            0
2       1       3            1
3       1       4            1

new_user_item_matrix
   userID  itemID  interaction
0       1       1          NaN
1       1       2          NaN
2       1       3          NaN
3       1       4          NaN
4       2       9            1
5       3       3            1
6       3       5            0

new_user_item_matrix after replacing
   userID  itemID  interaction
0       1       1          NaN
1       1       2          NaN
2       1       3            1
3       1       4            1
4       2       9            1
5       3       3            1
6       3       5            0

new_user_item_matrix after dropping nans
   userID  itemID  interaction
2       1       3            1
3       1       4            1
4       2       9            1
5       3       3            1
6       3       5            0

【讨论】:

  • 感谢您的回答。中间的人工制品是不必要的。我唯一需要的是一个 new_user_item_matrix ,其中冷用户(在我的示例中为用户 1)的用户项目对被删除,除非它们在 ranked_items 数组中。在我的原始代码中,我使用了其他变量名,但为了澄清起见,我选择了这些。
  • 感谢您的澄清。我添加了一个较短的 sn-p 以避免中间结构。这是你想要的吗?
  • 到底缺少什么?上面的代码生成了你想要的确切结果,不是吗?
  • 抱歉,您的最后一次编辑(避免使用np.NaN)是完美的解决方案。感谢您的努力!
  • 谢谢!我再次更新了答案,以帮助其他人更清楚地看到解决方案。另外,请注意这些解决方案之间的差异。一个创建只读视图(当然可以将其复制为副本以使用它),另一个就地修改矩阵。
猜你喜欢
  • 2016-07-24
  • 2018-01-23
  • 2015-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多