#python #arrays #pandas #dataframe #nested
#питон #массивы #панды #фрейм данных #вложенный
Вопрос:
Не мог бы кто-нибудь, пожалуйста, помочь мне со следующим?
У меня есть один фрейм данных с двумя столбцами: продукты и интернет-магазины (n x 2) с n продуктами. Теперь я хотел бы получить двоичную матрицу (n x n) со всеми продуктами, перечисленными в качестве индексов, и всеми продуктами, перечисленными в качестве имен столбцов. Затем каждая ячейка должна содержать 1 или 0, обозначающие, был ли продукт в индексе и названии столбца из одного и того же интернет-магазина.
Следующий код возвращает то, чего я хотел бы достичь.
dist = np.empty((len(df_title), len(df_title)), int) for i in range(0,len(df_title)): for j in range(0,len(df_title)): boolean = df_title.values[i][1] == df_title.values[j][1] dist[i][j] = boolean df = pd.DataFrame(dist)
Однако этот код занимает довольно значительное время уже для n = 1624. Поэтому мне было интересно, есть ли у кого-нибудь идея для более быстрого алгоритма.
Спасибо!
Ответ №1:
Похоже, что вас в любом случае интересует только элемент в позиции 1
для каждого столбца, поэтому создание временной переменной для облегчения поиска может помочь:
lookup = df_title.values[:, 1]
Кроме того, поскольку вы хотите интерпретировать полученную матрицу как bool
-матрицу, вам, вероятно, следует указать dtype=bool
(1 байт на поле) вместо dtype=int
(8 байт на поле), что также сокращает потребление памяти на 8.
dist = np.empty((len(df_title), len(df_title)), dtype=bool)
Ваша матрица в любом случае будет симметричной по диагонали, поэтому вам нужно вычислить только «половину» матрицы, также если i == j
мы знаем, что соответствующее поле в матрице должно быть True
.
lookup = df_title.values[:, 1] dist = np.empty((len(df_title), len(df_title)), dtype=bool) for i in range(len(df_title)): for j in range(len(df_title)): if i == j: # diagonal dist[i, j] = True else: # symmetric along diagonal dist[i, j] = dist[j, i] = lookup[i] == lookup[j]
Кроме того, используя numpy-широковещание, вы могли бы фактически преобразовать все это в одну строку кода, что на порядки быстрее, чем for
решение с двойным циклом:
lookup = df_title.values[:, 1] dist = lookup[None, :] == lookup[:, None]
Комментарии:
1. Большое спасибо! Это было именно то, что я искал, и очень информативно.