#python #pandas #grid
#python #панды #сетка
Вопрос:
У меня есть список узлов во фрейме данных pandas, которые выглядят следующим образом:
row col
...
36 182 240
35 182 241
34 182 242
33 182 243
58 183 220
32 183 244
31 183 245
30 183 246
29 183 247
...
Сетка этих узлов выглядит следующим образом:
Мой код помечает каждую грань ячеек X-ed так, что если она подключена к корректирующей ячейке X-ed, она помечается как 0, а если она не подключена (открыта), она помечается как 1. Код не работает должным образом вдоль некоторых ребер:
df["Front Face"] = 1
df["Back Face"] = 1
df["Right Face"] = 1
df["Left Face"] = 1
df = df.sort_values(by=['row','col'], ascending=True)
df = df.reset_index(drop=True)
for ix1 in df.index:
try:
if df["col"][ix1] == df["col"][ix1 1] - 1:
df["Right Face"][ix1] = 0
df["Left Face"][ix1 1] = 0
if df["col"][ix1] == df["col"][ix1 - 1] 1:
df["Left Face"][ix1] = 0
df["Right Face"][ix1 - 1] = 0
except:
pass
df= df.sort_values(by=['col','row'], ascending=True)
df= df.reset_index(drop=True)
for ix2 in df.index:
try:
if df["row"][ix2] == df["row"][ix2 1] - 1:
df["Back Face"][ix2] = 0
df["Front Face"][ix2 1] = 0
if df["row"][ix2] == df["row"][ix2 - 1] 1:
df["Front Face"][ix2] = 0
df["Back Face"][ix2 - 1] = 0
except:
pass
Это часть вывода, в ячейках 182,243 и 183,244 отсутствует одна метка:
row col Front Face Back Face Right Face Left Face
36 182 240 1 1 0 0
35 182 241 1 1 0 0
34 182 242 1 1 0 0
33 182 243 1 0 1 0
58 183 220 1 0 1 1
32 183 244 0 1 0 1
31 183 245 1 1 0 0
30 183 246 1 1 0 0
29 183 247 1 1 0 0
Я обвел проблемные ячейки на картинке здесь:
Ответ №1:
Я предполагаю, что каждая строка в вашей df
метке обозначает занятую позицию, и вы хотите пометить соседние ячейки как передние, задние, левые или правые.
Если это так, вы можете сделать это векторизованным способом, но я должен признать: я много боролся с тем, чтобы заставить индексы и numpy broadcast работать правильно.
# A random 5 * 10 matrix with 10% of rows marked as "occupied"
n, m = 5, 10
count = int(n * m * 0.1)
df = pd.DataFrame({
'row': np.random.randint(n, size=count),
'col': np.random.randint(m, size=count)
}).drop_duplicates()
И давайте построим фрейм result
данных:
from itertools import product
# Every row in `df` marks an occupied position
result = df.set_index(['row', 'col']).assign(Occupied = True)
# Now expand `result` into the full matrix
idx = product(range(n), range(m))
result = result.reindex(idx, fill_value=False)
# Every cell is Open initially
for col in ['Front Face', 'Back Face', 'Right Face', 'Left Face']:
result[col] = 1
# Now start to build out a list of blocked cells
occupied = result.query('Occupied').index.to_frame().to_numpy()
valid_index = result.index
faces = {
'Front Face': [-1, 0],
'Back Face': [1, 0],
'Left Face': [0, -1],
'Right Face': [0, 1]
}
for face, offset in faces.items():
blocked = valid_index.intersection([tuple(i) for i in occupied offset])
result.loc[blocked, face] = 0
Чтобы проиллюстрировать результат, давайте создадим вспомогательную функцию:
from IPython.display import display
def illustrate(result):
display_df = result['Occupied'].map({True: 'x', False: ''}).reset_index()
display_df = display_df.pivot(index='row', columns='col', values='Occupied')
is_open = result[['Front Face', 'Back Face', 'Right Face', 'Left Face']].all(axis=1)
style_df = (
is_open.map({
True: 'background-color: white',
False: 'background-color: rgba(255,0,0,0.2)'
})
.unstack()
)
display(display_df.style.apply(lambda _: style_df, axis=None))
illustrate(result)
Результат (ячейки, выделенные красным цветом, имеют 0 на любой из граней):
Комментарии:
1. Очень элегантное решение.