Сравнение нескольких строк в кадре данных с одной строкой по столбцу - PullRequest
0 голосов
/ 17 апреля 2020

Предположим, у меня есть такой фрейм данных, как показано ниже:

user       email                  day_diff  

tom        tommy@email.com         -10
tom        thomas@email.com        -2
tom        tom@email.com            3
bob        bob123@email.com        -11
bob        bob123@email.com         1
bob        bobby@email.com          2
alice      alice@email.com          4
Mary       mary@email.com          -5

Я хочу, чтобы каждый пользователь получал каждое электронное письмо с положительным значением day_diff и первой записью, где day_diff отрицательный, но ближе к 0. Затем сравните эти значения, и если какое-либо из них будет другим, в новом столбце значение будет «да», а если они все одинаковые, то значение будет «нет»

Так что для Тома я бы взял электронную почту где day_diff равен 3, tom@email.com, так как это единственный положительный day_diff и сравните его с thomas@email.com. Так как он отличается, новый столбец для каждой строки для Tom будет 'yes'

Для Боба я бы взял адреса электронной почты, где day_diff равен 1 и 2, и сравнить его с -11. Поскольку адреса электронной почты в 2 и -11 различны, новым значением столбца будет «да».

Если у пользователя есть только одна строка, а day_diff положителен, новым значением столбца будет «да», если У пользователя есть только электронные письма с отрицательным значением day_diff, новым значением столбца является «нет»

Любая помощь будет принята с благодарностью. Я крутился в кругах, пытаясь понять это.

Результат будет выглядеть как

user       email                  day_diff    email_change

tom        tommy@email.com         -10        yes
tom        thomas@email.com        -2         yes
tom        tom@email.com            3         yes
bob        bob123@email.com        -11        yes
bob        bob123@email.com         1         yes
bob        bobby@email.com          2         yes
alice      alice@email.com          4         yes
Mary       mary@email.com          -5         no

1 Ответ

1 голос
/ 18 апреля 2020

Вот что я предлагаю:

import pandas as pd
import numpy as np

df = pd.DataFrame({"user": ["tom", "tom", "tom", "bob", "bob", "bob", "alice", "mary"],
                   "email": ["tommy@email.com", "thomas@email.com", "tom@email.com", "bob123@email.com",
                             "bob123@email.com", " bobby@email.com", "alice@email.com", "mary@email.com"],
                   "day_dif": [-10, -2, 3, -11, 1, 2, 4, -5]})

# Treat case where no duplicates
df["dup"] = df["user"].duplicated(keep=False)
df["output"] = np.select([(df["dup"] == False) & (df["day_dif"] > 0), 
                          (df["dup"] == False) & (df["day_dif"] < 0)],
    ["yes", "no"], default=np.NaN)

# Treat duplicates
temp = df.loc[df["dup"], :]
temp = temp.copy()
temp["neg"] = np.where(temp["day_dif"] < 0, temp["day_dif"], np.NaN)
idx = temp.groupby("user")["neg"].nlargest(1).reset_index().level_1
# Create grouping variable that will help us make comparison
temp["pos"] = np.where(temp.index.isin(idx), 1,(temp["day_dif"] > 0) * 1)

groups = (temp.groupby(['user', "pos"])["email"].apply(list).reset_index()
              .sort_values(["user", "pos"]))
# compare all email in list by user and group pos
groups["output"] = groups["email"].apply(lambda x: all(w == x[0] for w in x))
# put on same line value for pos = 0 and pos = 1 for each user
groups["temp"] = groups["output"].shift(periods=-1)

# Apply your rules
groups["output"] = np.select([(groups.pos == 1) & (groups["output"] == False),
                              (groups.pos == 0) & (groups["temp"] == False)],
    ["yes", "yes"], default="no")
# reunite duplicates and non duplicates in one dataframe
new_df = pd.merge(df.loc[:, ["user", "email", "day_dif", "output"]],
                  groups[["user", "email", "output"]].explode(column="email"), 
                  on=["user", "email"], how="outer")
new_df["output"] = np.where(new_df["output_y"].isnull(), 
                            new_df["output_x"], new_df["output_y"])
new_df = new_df.drop(columns=["output_x", "output_y"]).drop_duplicates()

И вывод:

   user             email  day_dif output
0    tom   tommy@email.com      -10    yes
1    tom  thomas@email.com       -2    yes
2    tom     tom@email.com        3    yes
3    bob  bob123@email.com      -11    yes
5    bob  bob123@email.com        1    yes
7    bob   bobby@email.com        2    yes
8  alice   alice@email.com        4    yes
9   mary    mary@email.com       -5     no
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...