/ / Python pandas groupby умовно об'єднати рядки в декілька стовпців - python, pandas, group-by, умовний, string-concatenation

Python pandas group з умовним зв'язуванням рядків у декілька стовпчиків - python, pandas, group-by, conditional, string-concatenation

Я намагаюся згрупувати один кадр даних на одномустовпець, утримуючи декілька стовпців з одного рядка в кожній групі і об'єднуючи рядки з інших рядків у декілька стовпців на основі значення одного стовпця. Ось приклад ...

df = pd.DataFrame({"test" : ["a","a","a","a","a","a","b","b","b","b"],
"name" : ["aa","ab","ac","ad","ae","ba","bb","bc","bd","be"],
"amount" : [1, 2, 3, 4, 5, 6, 7, 8, 9, 9.5],
"role" : ["x","y","y","x","x","z","y","y","z","y"]})

дф

      amount    name    role    test
0        1.0    aa      x       a
1        2.0    ab      y       a
2        3.0    ac      y       a
3        4.0    ad      x       a
4        5.0    ae      x       a
5        6.0    ba      z       a
6        7.0    bb      y       b
7        8.0    bc      y       b
8        9.0    bd      z       b
9        9.5    be      y       b

Хотілося б групувати на тесті, зберігати ім'я ісума, коли role = "z", створює стовпець (назвемо його X), який об'єднує значення імені, коли role = "x" і інший стовпець (давайте назвемо його Y), що об'єднує значення імені при ролі = "y". [Копіровані значення розділені «;»] Можуть бути нульовими багато рядків з роллю = "х", нуль до багатьох рядків з роллю = "у" і одним рядком з роллю = "z" за значенням тесту. Для X і Y вони можуть бути нульовими, якщо для цього тесту немає рядків. Значення суми скидається для всіх рядків з роллю = "x" або "y". Бажаний результат буде таким:

     test   name     amount        X              Y
0    a      ba          6.0        aa; ad; ae     ab; ac
1    b      bd          9.0        None           bb; bc; be

Для конкатенуючої частини, я знайшов x.ix[x.role == "x", X] = "{%s}" % "; ".join(x["name"]), які я міг би повторити для y. Я спробував кілька речей по лінії name = x[x.role == "z"].name.first() для назви та суми. Я також спробував спустити обидва шляхи певної функції і лямбда-функцію без успіху. Оцініть будь-які думки.

Відповіді:

1 для відповіді № 1

Ви можете створювати спеціальні стовпці в apply функція після groupby наступним чином де g може розглядатися як субкадр з одним значенням у тестовому стовпці, і оскільки потрібно повернути кілька стовпців, потрібно створити a Series Об'єкт для кожної групи, де індекси є відповідними заголовками в результаті:

df.groupby("test").apply(lambda g: pd.Series({"name": g["name"][g.role == "z"].iloc[0],
"amount": g["amount"][g.role == "z"].iloc[0],
"X": "; ".join(g["name"][g.role == "x"]),
"Y": "; ".join(g["name"][g.role == "y"])
})).reset_index()

введіть опис зображення тут


1 для відповіді № 2
# set index and get crossection where test is "z"
z = df.set_index(["test", "role"]).xs("z", level="role")
# get rid of "z" rows and group by "test" and "role" to join names
xy = df.query("role != "z"").groupby(["test", "role"])["name"].apply(";".join).unstack()
# make columns of xy upper case
xy.columns = xy.columns.str.upper()

pd.concat([z, xy], axis=1).reset_index()

введіть опис зображення тут