Python: Почему мне не нужны 2 переменные при распаковке словаря? - PullRequest
0 голосов
/ 10 июля 2020
movie_dataset = {'Avatar': [0.01940156245995175, 0.4812286689419795, 0.9213483146067416], "Pirates of the Caribbean: At World's End": [0.02455894456664483, 0.45051194539249145, 0.898876404494382], 'Spectre': [0.02005646812429373, 0.378839590443686, 0.9887640449438202], ... }

movie_ratings = {'Avatar': 7.9, "Pirates of the Caribbean: At World's End": 7.1, 'Spectre': 6.8, ...}

def distance(movie1, movie2):
  squared_difference = 0
  for i in range(len(movie1)):
    squared_difference += (movie1[i] - movie2[i]) ** 2
  final_distance = squared_difference ** 0.5
  return final_distance

def predict(unknown, dataset, movie_ratings, k):
  distances = []
  #Looping through all points in the dataset
  for title in dataset:
    movie = dataset[title]
    distance_to_point = distance(movie, unknown)
    #Adding the distance and point associated with that distance
    distances.append([distance_to_point, title])
  distances.sort()
  #Taking only the k closest points
  neighbors = distances[0:k]
  total_rating = 0
  for i in neighbors[1]:
    total_rating += movie_ratings[i]  <----- Why is this an error?
  return total_rating / len(neighbors) <----- Why can I not divide by total rating
  #total_rating = 0
  #for i in neighbors:
    # title = neighbors[1]
    #total_rating += movie_ratings[title]  <----- Why is this not an error?
  #return total_rating / len(neighbors)

print(movie_dataset["Life of Pi"])
print(movie_ratings["Life of Pi"])
print(predict([0.016, 0.300, 1.022], movie_dataset, movie_ratings, 5))

Здесь два вопроса. Во-первых, почему это ошибка?

for i in neighbors[1]:

    total_rating += movie_ratings[i]

Кажется, это то же самое, что

for i in neighbors:
    title = neighbors[1]
    total_rating += movie_ratings[title]

Во-вторых, почему я не могу разделить на len (total_rating)?

Ответы [ 2 ]

1 голос
/ 10 июля 2020

расстояния генерируются в форме:

[
[0.08565491616637051, 'Spectre'],
[0.1946446017955758, "Pirates of the Caribbean: At World's End"],
[0.20733104650812437, 'Avatar']
]

, что является производным от соседей, а имена находятся в позиции 1 каждого списка. neighbors[1] будет просто извлекать [0.1946446017955758, "Pirates of the Caribbean: At World's End"] или единственный элемент, который не похож на то, что вы хотите. Он попытался бы использовать 0.19... и Pirates... в качестве ключей в dict movie_ratings.

Я предполагаю, что вы хотите это, чтобы усреднить все рейтинги ближайшего по извлеченным значениям расстояния из набора данных? :

  for dist, name in neighbors:
    total_rating += movie_ratings[name]
  return total_rating / len(neighbors)
1 голос
/ 10 июля 2020

Сначала второй вопрос, потому что он более простой:

Во-вторых, почему я не могу разделить на len (total_rating)?

Вы пытаетесь вычислить средний, правда? Итак, вы хотите разделить сумму оценок на количество оценок?

Хорошо. Итак, вы пытаетесь выяснить, сколько существует оценок. Какое правило говорит вам об этом? Похоже, вы рассчитываете подсчитать рейтинги с того места, где они хранятся. Где они хранятся? Это не total_rating; вот где вы сохранили числовую сумму. Откуда взялись рейтинги? Они пришли из поиска названий фильмов в movie_ratings. Таким образом, рейтинги были , а не на самом деле вообще; не на чем измерить len оф. Правильно? Не совсем так. Какое правило определяет рейтинги, которые мы складываем? Мы ищем их в movie_ratings по заголовку . Так сколько их там? Сколько есть титулов. Где хранились названия? Они были сопоставлены с расстояниями в neighbors. Так что титулов столько, сколько соседей (что бы здесь ни значило слово «сосед»; я действительно не понимаю, почему вы так назвали его). Итак, , что - это то, что вы хотите len() из.

Далее, чтобы исправить суммирование.

total_rating = 0
for i in neighbors[1]:
    total_rating += movie_ratings[i]

Сначала вычисляется neighbors[1], которое будет одна из пар [distance_to_point, title], которая была .append добавлена ​​в список (при условии, что таких значений как минимум два, чтобы индекс [1] действовал).

Затем l oop повторяется над этим двухэлементным списком, поэтому он выполняется дважды: в первый раз i равно значению расстояния, а во второй раз - заголовку. Ошибка возникает из-за того, что заголовок является строкой, и вы пытаетесь вычислить с ней.

total_rating = 0
for i in neighbors:
    title = neighbors[1]
    total_rating += movie_ratings[title]

Это l oop заставляет i принимать каждую из пар как значение. title = neighbors[1] сломан; теперь мы полностью игнорируем значение i и вместо этого всегда используем специфицированную пару c, а также пытаемся использовать пару (которая является списком) в качестве заголовка (нам нужна строка).

Предположительно, вы хотели:

total_rating = 0
for neighbor in neighbors:
    title = neighbor[1]
    total_rating += movie_ratings[title]

Обратите внимание, я использую более четкое имя для переменной l oop, чтобы избежать путаницы. neighbor - одно из значений из списка neighbors, то есть одна из пар расстояние-заголовок. Отсюда мы можем получить заголовок, а затем из данных рейтингов и заголовка мы можем получить рейтинг.

Я могу сделать его более понятным, используя распаковку аргументов:

total_rating = 0
for neighbor in neighbors:
    distance, title = neighbor
    total_rating += movie_ratings[title]

Вместо того, чтобы понимать причину появления индекса [1], теперь мы помечаем каждую часть значения neighbor, а затем используем ту, которая имеет отношение к нашей цели.

Я могу сделать это проще, выполнив распаковку сразу:

total_rating = 0
for distance, title in neighbors:
    total_rating += movie_ratings[title]

Я могу сделать его более элегантным, не пытаясь объяснить Python, как вычислять суммы, а просто сообщая ему, что суммировать:

total_rating = sum(movie_ratings[title] for distance, title in neighbors)

Здесь используется выражение генератора вместе со встроенной функцией суммы , которая делает именно то, что звучит.

...