#python #dictionary #bigdata #matching
Вопрос:
У меня есть два набора данных, которые находятся в формате словаря:
ch1 = {1000: 128,
2830: 1022,
3438: 198,
5908: 109}
ch2 = {1295: 1203,
2836: 1238,
4901: 8367,
7608: 249}
В настоящее время у меня есть код для поиска совпадений между ключами в одном словаре и ключами в другом:
coin = [int(ch1[key]) int(ch2[key]) for key in ch1.keys() amp; ch2.keys()]
Я хочу изменить этот код, чтобы он находил ключи, которые находятся в заданном диапазоне друг от друга. Например, если в диапазоне 10, выходной список из примеров словарей будет [2260]
равен сумме 1022 1238, путем сопоставления ключей 2830 из dic1 и 2836 из dic2.
Одним из ограничений является то, что файлы данных большие (~500 МБ), что ограничивает решения, о которых я думал, повторяя данные списка.
В том редком случае, когда в одном словаре есть два ключа, которые находятся в диапазоне ключа в другом словаре, это должно дать одно совпадение.
ch1 = {1000: 128,
2830: 1022,
3438: 198,
5908: 109}
ch2 = {1295: 1203,
2836: 1238,
2839: 8367,
7608: 249}
Все равно должен уступить [5825]
, раунд((1238 8367)/2 1022).
В еще более редком случае, когда есть две пары, не имеет значения, какая из них сопоставлена вместе. В этом случае должно быть только два выхода. Напр.:
ch1 = {1000: 128,
2837: 1022,
2838: 198,
5908: 109}
ch2 = {1295: 1203,
2836: 1238,
2839: 8367,
7608: 249}
Результат = [2260, 8565] , который исходит из 1022 1238, 198 8367
Комментарии:
1. Что вы хотите/ожидаете, если будет несколько ключей, соответствующих вашему критерию диапазона? Например, измените 4901 во 2-м словаре на 3439. Ожидали бы вы двух значений?
2.
0128
является синтаксической ошибкой в python3. Извините, я добавил потенциальные исключения и исправил проблему с ch1
4. Пожалуйста, добавьте свой код для трех критериев, ваше текстовое описание чрезвычайно запутанно.
Ответ №1:
Я предлагаю простой ответ, который выполняется за 9 секунд для двух словарей объемом 15 МБ каждый (всего 31 МБ), поэтому его можно использовать в качестве основы для сравнения. Какова желаемая скорость?
Я не суммирую результаты, а нахожу все подходящие пары, так как, по-моему, не совсем понимаю, как их следует суммировать. Я считаю, что, уже имея комбинации, может быть довольно легко применять свои собственные правила.
Создайте два словаря
import sys
from numpy.random import default_rng
rng = rng = default_rng(12345)
MAX_KEY = 10000000
MAX_VALUE = 10000
M = 1000000
dictionaries = {'1': {}, '2':{}}
for i in range(M):
for i in dictionaries:
key = rng.integers(low=1, high=MAX_KEY)
value = rng.integers(low=1, high=MAX_VALUE)
dictionaries[i][key] = value
ch1 = dictionaries['1']
ch2 = dictionaries['2']
TOT_SIZE = 0
TOT_SIZE = sys.getsizeof(list(ch1))
TOT_SIZE = sys.getsizeof(list(ch2))
TOT_SIZE = sys.getsizeof([ch1[key] for key in ch1])
TOT_SIZE = sys.getsizeof([ch2[key] for key in ch2])
TOT_SIZE /= (1024**2)
print(f"TOT_SIZE = {TOT_SIZE} MB")
Функция
def get_possiblePairs(TH = TH):
possible_sums = {}
list_keys = (list(ch1) list(ch2))
list_keys.sort()
N = len(list_keys)
possible_sums = {}
coin_list = []
for i in range(N):
for j in range(i 1, N):
key1 = list_keys[i]
key2 = list_keys[j]
if key2<key1 TH:
if key1 in ch1 and key2 in ch2:
coin = ch1[key1] ch2[key2]
possible_sums[(key1,key2)] = coin
else:
break
for j in range(N):
for i in range(i 1, N):
key1 = list_keys[i]
key2 = list_keys[j]
if key1<key2 TH:
if key1 in ch1 and key2 in ch2:
coin = ch1[key1] ch2[key2]
possible_sums[(key1,key2)] = coin
else:
break
return possible_sums
Ответ №2:
Мне нравится решение, опубликованное конрадом-h, но я решил написать свое, которое несколько проще, и, похоже, в нем меньше циклов. Однако он больше полагается на функции numpy, поэтому я не уверен, какая из них более эффективна, и у моей есть недостаток — она не будет работать в 3-м случае.
Я представлю решение и объясню, почему я считаю, что 3-й случай трудно решить, независимо от подхода.
Итак, мой подход таков:
1.) Создайте массив ключей numpy. Я называю эти массивы c1_keys
и c2_keys
, для словарей ch1
и ch2
соответственно.
2.) Для каждого key1
входа c1_keys
я нахожу все ключи, ключи в ch2_keys
которых есть -10
key1
.
3.) Создайте avg_
все key2
найденные (их соответствующие значения из ch2
).
4.) К списку results
добавьте сумму avg
и значение из ch1
предоставленного key1
.
5.) Удалите найденные ключи 2 из массива numpy ch2_keys
.
def find_pairs(ch1, ch2):
# dict keys to np array
c1_keys = np.array(list(ch1.keys()))
c2_keys = np.array(list(ch2.keys()))
results = []
# find pairs of keys
for key1 in c1_keys:
indices = np.logical_and(key1 - 10 <= c2_keys, c2_keys <= key1 10)
sum_ = 0
if np.any(indices):
for index in c2_keys[indices]:
sum_ = ch2[index]
sum_ = sum_ / indices.sum()
results.append(round(ch1[key1] sum_))
c2_keys = c2_keys[~indices]
return results
Профи:
-Это решение будет работать все быстрее и быстрее по мере продвижения поиска, потому что мы удаляем ключи из 2-го словаря (то есть из np.массива)
-Это решит самый распространенный и редкий случай
Кон:
-Это не решит 3-е дело.
Объяснение:
Как также заявил @konrad-h, он не знал, как суммировать подходящие пары, потому что это несколько сбивает с толку. Вот почему в его решении больше петель. Предположим, что словари выглядят так:
ch1 = {
1: 100,
2: 200,
3: 300,
...
}
ch2 = {
1: 100,
2: 200,
3: 300,
...
}
Как нам с этим справиться? Для -10
допуска все клавиши 1-10 в ch1 будут совместимы со всеми клавишами 1-10 из ch2. Единственный способ, которым мы можем узнать, что существуют идеальные пары, — это выполнить полный поиск два раза. Во-первых, мы находим все подходящие пары (что и сделал Конрад-х.). Во-вторых, мы находим лучшие парные комбинации (что также непросто).
Вот почему я настоятельно рекомендую вам уменьшить допустимый допуск и суммировать первые подходящие пары, с которыми вы столкнетесь. Невозможно узнать, существуют ли две пары в ch1
и ch2
, не проходя через них дважды. Но вы можете легко выполнить случаи 1 и c2.