сравните два показателя по умолчанию и сохраняйте только записи, удовлетворяющие условию

#python #python-3.x #list #dictionary #defaultdict

Вопрос:

У меня есть df, который я хочу преобразовать в dict таким образом, чтобы идентификатор был ключом, а затем получал список словарей в качестве значения:

 d = {'id': [1,1,1,1,2,2,3,3,3,4,4,4,4],
     'label':['A','A','B','G','A','BB','C','C','A','BB','B','AA','AA']
    ,'amount':[2,-12,12,-12,5,-5,2,3,5,3,3,10,-10]}
df = pd.DataFrame(d)

d = defaultdict(lambda: defaultdict(list))   

#only append the negative amounts
for index,row in df.iterrows():
    if row["amount"] < 0:
        d[row["id"]][row["amount"]].append(
            { "id": row["id"],
                "label": row["label"]})
print(d)       
Out: defaultdict(<function __main__.<lambda>()>,
            {1: defaultdict(list,
                           {-12: [{'id': 1, 'description': 'A'},
                           {'id': 1, 'description': 'G'}]}),
             2: defaultdict(list, {-5: [{'id': 2, 'description': 'BB'}]}),
             4: defaultdict(list, {-10: [{'id': 4, 'description': 'AA'}]})})

d2 = defaultdict(lambda: defaultdict(list)) 
#only append the positive amounts

for index,row in df.iterrows():
    account_id = row["id"]
    amount = row["amount"]
    
    if amount > 0:
        d2[account_id][amount].append( { "id": row["id"],
                "label": row["label"]})
print(d2)

Out: defaultdict(<function __main__.<lambda>()>,
            {1: defaultdict(list,
                         {2: [{'id': 1, 'description': 'A'}],
                         12: [{'id': 1, 'description': 'B'}]}),
             2: defaultdict(list, {5: [{'id': 2, 'description': 'A'}]}),
             3: defaultdict(list,
                         {2: [{'id': 3, 'description': 'C'}],
                          3: [{'id': 3, 'description': 'C'}],
                          5: [{'id': 3, 'description': 'A'}]}),
             4: defaultdict(list,
                         {3: [{'id': 4, 'description': 'BB'},
                           {'id': 4, 'description': 'B'}],
                          10: [{'id': 4, 'description': 'AA'}]})})
 

Как я могу сравнить два диктанта таким образом, чтобы получить записи, содержащие совпадающие положительные и отрицательные числа для одного и того же пользователя, чтобы мой диктант выглядел так, как показано ниже? Я хочу использовать только диктанты, а не операции с пандами.d

 defaultdict(<function __main__.<lambda>()>,
            {1: defaultdict(list,
                         {-12: [{'id': 1, 'description': 'A'},
                               {'id': 1, 'description': 'G'}], 
                           12: [{'id': 1, 'description': 'B'}]},
             2: defaultdic (list, {-5: [{'id': 2, 'description': 'BB'},
                                    5: {'id': 2, 'description': 'A'}]}),
             4: defaultdict(list, {-10: [{'id': 4, 'description': 'AA'}],
                                   10: [{'id': 4, 'description': 'AA'}]}))
 

Ответ №1:

Таким образом, вы в основном хотите отфильтровать суммы, которые существуют как в виде положительного, так и отрицательного целого числа для каждого идентификатора? Я предлагаю отфильтровать это в панд, прежде чем преобразовывать его в дикт. Вы можете id сгруппировать, а затем отфильтровать группы, сравнив, какие суммы также существуют в одном и том же отрицательном Series :

 new_df = df.groupby('id').apply(lambda g: g[g['amount'].isin(g['amount']*-1)]).reset_index(drop=True)
 

Выход:

ID этикетка сумма
0 1 A -12
1 1 B 12
2 1 G -12
3 2 A 5
4 2 бб -5
5 4 aa 10
6 4 aa -10

Затем вы можете экспортировать весь df, как вам заблагорассудится:

 d = defaultdict(lambda: defaultdict(list))   

for index,row in new_df.iterrows():
    d[row["id"]][row["amount"]].append(
        { "id": row["id"],
            "label": row["label"]})
 

В случае, если вы просто хотите сравнить дикты, вы можете повторить один, сравнить, существуют ли отрицательные значения в другом дикте, а затем записать оба значения в новый дикт:

 new_dict = {}

for item in d:
    for i in d[item]:
        if i*-1 in [i for item in d2 for i in d2[item]]:
            new_dict[item] = {i:d[item][i], -i:d2[item][-i]}
 

Результат:

 {1: {-12: [{'id': 1, 'label': 'A'}, {'id': 1, 'label': 'G'}],
  12: [{'id': 1, 'label': 'B'}]},
 2: {-5: [{'id': 2, 'label': 'BB'}], 5: [{'id': 2, 'label': 'A'}]},
 4: {-10: [{'id': 4, 'label': 'AA'}], 10: [{'id': 4, 'label': 'AA'}]}}
 

Комментарии:

1. Спасибо за ответ. Можно ли это сделать без каких-либо операций с пандами? Я имею в виду чисто манипулирование словарями.

2. Конечно, я обновил ответ!