Python / Pandas - 用另一个数据帧中的值替换一个数据帧中的元素

时间:2016-07-14 09:59:51

标签: python python-2.7 numpy pandas dataframe

我在使用另一个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项目,我称之为 ranking_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 如果<且仅该项目包含在 ranking_items 数组中。之后,应删除交互仍为NaN的所有用户项对(DataFrame的行)(用户1 - itemId不在 ranking_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)

它做什么?它循环遍历 ranking_items 数组中的所有项目。首先,它检查用户1是否与项目进行了交互(if语句的if部分)。如果没有,则转到 ranking_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 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不在 ranking_items 数组中,因此不应发现它们的真实交互。此外,为所有交互填充用户1和itemId 3的交互(a 1)(即使他们的交互不是1但是0)。

有谁可以帮助我吗?

1 个答案:

答案 0 :(得分:3)

简短解决方案

实质上,您希望丢弃给定用户的所有项目互动,但仅限于排名的项目。

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

使用布尔条件进行简单行选择(在原始df上生成只读视图):

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

类似的解决方案,通过删除&#34;无效&#34;来就地修改数据帧。行:

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