У меня есть фрейм данных с 4 столбцами. Мне нужно выполнить несколько поисков, а затем присвоить значение в одном из столбцов. Вот образец данных:
CategoryId ParentCategoryId SourceCategoryId SourceParentCategoryId
1 100 0
2 101 0
3 9.0 102 108
4 20.0 103 100
5 4.0 104 103
6 105 103
7 106 103
8 107 103
9 108 0
10 109 108
11 110 103
12 111 103
13 112 103
14 113 100
15 114 113
16 115 113
17 116 113
18 117 113
19 118 113
20 100 113
Я пытаюсь заполнить значения в столбце ParentCategoryId следующей логикой: Для каждой строки мы будем искать значение в SourceParentCategoryId, и если оно равно нулю, мы его пропустим. Если значение в SourceParentCategoryId отличается от нуля, как в строке 3, мы видим, что SourceParentCategoryId равно 108. Затем мне нужно найти это значение в SourceCategoryId и определить, к какому CategoryId оно принадлежит. В приведенном мной примере мы видим, что CategoryId имеет CategoryId 9, что является значением, которое мне нужно вставить в строку 3 в моем столбце ParentCategoryId.
По той же логике строка 4 имеет SourceParentCategoryId = 100, что основано на SourceCategoryId, имеющем CategoryId = 20, а затем значение 20 добавляется в строку 4 в столбце ParentCategoryId.
Питоном занимаюсь несколько лет и уже провел кучу исследований по этому поводу, однако до сих пор не понимаю, как вообще начать с решения этой проблемы.
Не могли бы вы помочь мне решить эту проблему или хотя бы дать мне несколько советов?
Предполагая, что у вас еще нет данных в столбце ParentCategoryId, вы можете использовать следующий подход:
SourceParentCategoryId == SourceCategoryId
.SourceParentCategoryId == 0
.df = df.merge(df, left_on = "SourceParentCategoryId", right_on = "SourceCategoryId", how = "left", suffixes=("", "_delete"))
# If there are multiple matches, then the self join may have repeated records. Limit this by retaining first record.
df = df.groupby(["CategoryId", "SourceCategoryId", "SourceParentCategoryId"])["CategoryId_delete"].first().reset_index()
df = df.rename(columns = {"CategoryId_delete": "ParentCategoryId"})
# Reset values for `SourceParentCategoryId == 0`.
df["ParentCategoryId"] = df.apply(lambda row: None if row["SourceParentCategoryId"] == 0 else row["ParentCategoryId"], axis=1)
Выход:
CategoryId SourceCategoryId SourceParentCategoryId ParentCategoryId
0 1 100 0 NaN
1 2 101 0 NaN
2 3 102 108 9.00
3 4 103 100 1.00
4 5 104 103 4.00
5 6 105 103 4.00
6 7 106 103 4.00
7 8 107 103 4.00
8 9 108 0 NaN
9 10 109 108 9.00
10 11 110 103 4.00
11 12 111 103 4.00
12 13 112 103 4.00
13 14 113 100 1.00
14 15 114 113 14.00
15 16 115 113 14.00
16 17 116 113 14.00
17 18 117 113 14.00
18 19 118 113 14.00
19 20 100 113 14.00
Используйте DataFrame.drop_duplicates для удаления дубликатов с помощью SourceCategoryId, поэтому возможное сопоставление SourceParentCategoryId отфильтровано без 0 значений в SourceParentCategoryId с помощью Series.map:
m = df['SourceParentCategoryId'].ne(0)
s = df.drop_duplicates('SourceCategoryId').set_index('SourceCategoryId')['CategoryId']
df['ParentCategoryId'] = df.loc[m, 'SourceParentCategoryId'].map(s)
print (df)
CategoryId ParentCategoryId SourceCategoryId SourceParentCategoryId
0 1 NaN 100 0
1 2 NaN 101 0
2 3 9.0 102 108
3 4 1.0 103 100
4 5 4.0 104 103
5 6 4.0 105 103
6 7 4.0 106 103
7 8 4.0 107 103
8 9 NaN 108 0
9 10 9.0 109 108
10 11 4.0 110 103
11 12 4.0 111 103
12 13 4.0 112 103
13 14 1.0 113 100
14 15 14.0 114 113
15 16 14.0 115 113
16 17 14.0 116 113
17 18 14.0 117 113
18 19 14.0 118 113
19 20 14.0 100 113
Для сохранения последних повторяющихся значений используйте параметр keep='last':
m = df['SourceParentCategoryId'].ne(0)
s = df.drop_duplicates('SourceCategoryId', keep='last').set_index('SourceCategoryId')['CategoryId']
df['ParentCategoryId'] = df.loc[m, 'SourceParentCategoryId'].map(s)
print (df)
CategoryId ParentCategoryId SourceCategoryId SourceParentCategoryId
0 1 NaN 100 0
1 2 NaN 101 0
2 3 9.0 102 108
3 4 20.0 103 100
4 5 4.0 104 103
5 6 4.0 105 103
6 7 4.0 106 103
7 8 4.0 107 103
8 9 NaN 108 0
9 10 9.0 109 108
10 11 4.0 110 103
11 12 4.0 111 103
12 13 4.0 112 103
13 14 20.0 113 100
14 15 14.0 114 113
15 16 14.0 115 113
16 17 14.0 116 113
17 18 14.0 117 113
18 19 14.0 118 113
19 20 14.0 100 113
@Azharkan и Jezrael - спасибо вам обоим за эти два подхода. Эти работы. Я был так далек от понимания этого. Еще раз спасибо.