#python #pandas #dataframe
#python #pandas #фрейм данных
Вопрос:
У меня есть два df1
фрейма данных и df2
. Первый столбец в обоих — это идентификатор клиента, который является an int
, но другие столбцы содержат различные строковые значения. Я хочу создать новый df3
фрейм данных, который содержит для каждого идентификатора клиента набор значений, найденных в df2
, но не в df1
.
Пример:
df1
:
v1 v2 v3 v4
cust
1 A B B A
2 A A A A
3 B B A A
4 B C A A
df2
:
v1 v2 v3 v4
cust
1 A A C B
2 A A C B
3 C B B A
4 C B B A
Ожидаемый результат:
cust
1 {C}
2 {B, C}
3 {C}
4 {}
Комментарии:
1. Пожалуйста, не добавляйте изображения, добавляйте фреймы данных таким образом, чтобы их можно было скопировать в скрипт Python.
2. @DaniMesejo Я здесь новичок. Я пробовал другой формат, но он не работает. Надеюсь, я получу от вас помощь.
Ответ №1:
In [2]: df_2 = pd.DataFrame({"KundelID" : list(range(1,11)),
...: 'V1' : list('AACCBBBCCC'),
...: 'V2' : list('AABBBCCCAA'),
...: 'V3' : list('CCBBBBBAAB'),
...: 'V4' : list('BBAACAAAAB')})
...: df_1 = pd.DataFrame({"KundelID" : list(range(1,11)),
...: 'V1' : list('AABBCCCCCC'),
...: 'V2' : list('BABCCCCAAA'),
...: 'V3' : list('BAAAAABBBB'),
...: 'V4' : list('AAAACCCCBB')})
In [3]: df_1
Out[3]:
KundelID V1 V2 V3 V4
0 1 A B B A
1 2 A A A A
2 3 B B A A
3 4 B C A A
4 5 C C A C
5 6 C C A C
6 7 C C B C
7 8 C A B C
8 9 C A B B
9 10 C A B B
In [4]: df_2
Out[4]:
KundelID V1 V2 V3 V4
0 1 A A C B
1 2 A A C B
2 3 C B B A
3 4 C B B A
4 5 B B B C
5 6 B C B A
6 7 B C B A
7 8 C C A A
8 9 C A A A
9 10 C A B B
In [7]: pd.DataFrame({"KundeID" : df_2.KundelID,
...: 'Not-in-df_1' : [','.join([i for i in df_2_ if not i in df_1_]) if [i for i in df_2_ if not i in df_1_] else None for df_1_,df_2_ in zip(df_1.T[1:].apply(np.unique), df_2.T[1:].apply(np.unique))]})
Out[7]:
KundeID Not-in-df_1
0 1 C
1 2 B,C
2 3 C
3 4 None
4 5 B
5 6 B
6 7 A
7 8 None
8 9 None
9 10 None
Комментарии:
1. Хотя (судя по выводам) это обеспечивает и ответ, вы можете сделать свой ответ более ценным, предоставив объяснение того, как вы достигли результата. Возможно, разделение (и объяснение) длинной строки кода Python может помочь?
Ответ №2:
Идея состоит в том, чтобы преобразовать все значения в каждой строке в set
. Затем мы можем взять установленную разницу для каждого идентификатора клиента. Это позволяет избежать циклов и понимания списка:
df3 = (
pd
.concat([
df1.reindex(index=df2.index).apply(set, axis=1),
df2.apply(set, axis=1),
], axis=1)
.apply(lambda r: r[1].difference(r[0]), axis=1)
)
print(df3)
# Out:
cust
1 {C}
2 {B, C}
3 {C}
4 {}
Примечания:
- Бит
df1.reindex(index=df2.index)
используется в случае, если некоторые идентификаторы отсутствуют вdf1
ordf2
). - Тривиально преобразовать выходные данные во что-то другое вместо a
set
. Например','.join(r[1].difference(r[0]))
, как лямбда-выражение будет создавать строки.
Настройка:
Для дальнейшего использования, чтобы упростить воспроизводимый пример, было бы неплохо предоставить некоторый код, который может быть скопирован / вставлен непосредственно пользователями для быстрого запуска вашей проблемы.
df1 = pd.read_csv(io.StringIO("""
1 A B B A
2 A A A A
3 B B A A
4 B C A A
"""), sep=' ', names='cust v1 v2 v3 v4'.split()).set_index('cust')
df2 = pd.read_csv(io.StringIO("""
1 A A C B
2 A A C B
3 C B B A
4 C B B A
"""), sep=' ', names='cust v1 v2 v3 v4'.split()).set_index('cust')
Ответ №3:
Вы преобразуете каждый фрейм данных в серию наборов, затем выполняете операцию набора по всей серии, используя внутреннее выравнивание данных из серии pandas:
df2.apply(set, axis=1) - df1.apply(set, axis=1)
Вывод:
cust
1 {C}
2 {C, B}
3 {C}
4 {}
dtype: object
Если вам нужна симметричная разница между наборами данных (т.Е. Элементами либо в наборе, либо в другом, но не в обоих), тогда лучше использовать pd.concat
:
dfs = [df1, df2]
pd.concat([df.apply(set, 1) for df in dfs], 1).apply(lambda x: x[0]^x[1], 1)
где 1 здесь означает axis=1
. Кроме того, замена x[0]^x[1]
на set.symmetric_difference(*x)
также должна работать.
Интересно, Series_A ^ Series_B
что работает не так, как ожидалось, вместо этого (по-видимому) он возвращает серию bool, сообщающую нам, не являются ли возвращаемые значения из операций set пустыми.