Pandas - 创建新列,其值取自同一数据框中的其他行

4

我有一个如下的DataFrame

    message_id  reply_to_id     sender
0   1           0               Roozbeh
1   2           1               Amir
2   3           0               Neda
3   4           2               Roozbeh
3   5           2               Neda

如果消息是回复另一条消息,则reply_to_id显示被回复的消息的id,否则为0。现在我想创建另一列reply_to_sender,其中显示被回复的消息的发送者名称(如果它不是回复,可以显示NaN)。 message_id列是唯一的,但reply_to_idsender列显然不是。
我尝试了这个:
data["reply_to_sender"] = data.loc[data["reply_to_id"] == data["message_id"]]["sender"]

但它显然行不通,因为它会查看每一行并执行关系运算。我想做的是查看每一行,然后从其他行找到发送者的名称。对于上面的例子,输出需要像这样:

    message_id  reply_to_id     sender    reply_to_sender
0   1           0               Roozbeh   NaN
1   2           1               Amir      Roozbeh
2   3           0               Neda      NaN
3   4           2               Roozbeh   Amir
3   5           2               Neda      Amir

我该如何做到这一点?
3个回答

6
使用 Series.map 函数,对由 message_idsender 创建的 Series 进行操作。
df['reply_to_sender'] = df['reply_to_id'].map(df.set_index('message_id')['sender'])
print (df)
   message_id  reply_to_id   sender reply_to_sender
0           1            0  Roozbeh             NaN
1           2            1     Amir         Roozbeh
2           3            0     Neda             NaN
3           4            2  Roozbeh            Amir
3           5            2     Neda            Amir

0

首先,让我们看看如何手动完成此操作。然后我们将在代码中实现。

如果我给你一个reply_to_id,你可以告诉我这条消息是回复给谁的,只需查看DataFrame,找到其message_id等于该数字的行,然后告诉我该行sender列中的值即可。这可以像这样完成,其中reply_to_id变量是我给你的数字:

data.loc[data["message_id"] == reply_to_id]["sender"]

现在这个代码返回一个pandas.Series,但我们没有要求返回 Series,我们想要的是发送者的标量值。所以我们需要从Series中提取该值。如果Series中只有一个值(您需要检查一下),我们可以使用 pandas.Series.values [0]进行提取。因此代码变成如下形式:

reply_to_sender_values = data.loc[data["message_id"] == reply_to_id]["sender"].values
if len(reply_to_sender_values) == 1:
    return reply_to_sender_values[0]

现在,如果我给你一个在message_id中找不到的数字,会发生什么?你会告诉我你什么也没找到。翻译成中文就是:

reply_to_sender_values = data.loc[data["message_id"] == reply_to_id]["sender"].values
if len(reply_to_sender_values) == 1:
    return reply_to_sender_values[0]
else:
    return ""

还有一件事情需要注意。正如你所说,reply_to_id中的值可能为零。因此我们需要注意这一点:

if(reply_to_id != 0):
    reply_to_sender_values = data.loc[data["message_id"] == reply_to_id]["sender"].values
    if len(reply_to_sender_values) == 1:
        return reply_to_sender_values[0]
    else:
        return ""
else:
    return ""

正如你所见,我们刚刚建立了一个函数来执行你手动完成的任务。让我们给它一个名称:
def reply_to_sender(reply_to_id):
    if(reply_to_id != 0):
        reply_to_sender_values = data.loc[data["message_id"] == reply_to_id]["sender"].values
        if len(reply_to_sender_values) == 1:
            return reply_to_sender_values[0]
        else:
            return ""
    else:
        return ""

现在我们只需要找到一种方法来将这个函数应用于我们的DataFramereply_to_id列中的所有行。幸运的是,Pandas中有一个方法可以做到这一点,它被称为pandas.DataFrame.apply。现在,我们只需要使用以下代码即可实现:
data["reply_to_sender"] = data["reply_to_id"].apply(lambda x: reply_to_sender(x))

需要注意的一点是,我在 Jupyter Notebook 中测试了这段代码。如果你想从脚本中运行这段代码,你需要将 DataFrame 传递给你的 reply_to_sender 函数。所以代码应该改为:

def reply_to_sender(data, reply_to_id):
    if(reply_to_id != 0):
        reply_to_sender_values = data.loc[data["message_id"] == reply_to_id]["sender"].values
        if len(reply_to_sender_values) == 1:
            return reply_to_sender_values[0]
        else:
            return ""
    else:
        return ""

data["reply_to_sender"] = data["reply_to_id"].apply(lambda x: reply_to_sender(data, x))

0

你可以做到

mymap = {val: df.sender.loc[key] for key, val in df.message_id.to_dict().items()}

然后

df['reply_to_sender'] = df.reply_to_id.map(mymap)

这会给你

   message_id  reply_to_id   sender reply_to_sender
0           1            0  Roozbeh             NaN
1           2            1     Amir         Roozbeh
2           3            0     Neda             NaN
3           4            2  Roozbeh            Amir
3           5            2     Neda            Amir


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接