前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >数据挖掘实践指南读书笔记1

数据挖掘实践指南读书笔记1

作者头像
公众号---人生代码
发布2019-10-30 11:38:01
3380
发布2019-10-30 11:38:01
举报
文章被收录于专栏:人生代码

写在之前

本书涉及的源程序和数据都可以在以下网站中找到:http://guidetodatamining.com/ 这本书理论比较简单,书中错误较少,动手锻炼较多,如果每个代码都自己写出来,收获不少。总结:适合入门。欢迎转载,转载请注明出处,如有问题欢迎指正。合集地址:https://www.zybuluo.com/hainingwyx/note/559139

协同过滤

相似用户评判标准:曼哈顿距离、欧氏距离、明氏距离。

代码语言:javascript
复制
# Manhattan.py
users = {
"Angelica": {"Blues Traveler": 3.5, "Broken Bells": 2.0, "Norah Jones": 4.5,
"Phoenix": 5.0, "Slightly Stoopid": 1.5, "The Strokes": 2.5, 
"Vampire Weekend": 2.0},
"Bill":{"Blues Traveler": 2.0, "Broken Bells": 3.5, "Deadmau5": 4.0, 
"Phoenix": 2.0,"Slightly Stoopid": 3.5, "Vampire Weekend": 3.0},
"Chan": {"Blues Traveler": 5.0, "Broken Bells": 1.0, "Deadmau5": 1.0, 
"Norah Jones": 3.0, "Phoenix": 5, "Slightly Stoopid": 1.0},
"Dan": {"Blues Traveler": 3.0, "Broken Bells": 4.0, "Deadmau5": 4.5, 
"Phoenix": 3.0, "Slightly Stoopid": 4.5, "The Strokes": 4.0, 
"Vampire Weekend": 2.0},
"Hailey": {"Broken Bells": 4.0, "Deadmau5": 1.0, "Norah Jones": 4.0, 
"The Strokes": 4.0, "Vampire Weekend": 1.0},
"Jordyn": {"Broken Bells": 4.5, "Deadmau5": 4.0, "Norah Jones": 5.0, 
"Phoenix": 5.0, "Slightly Stoopid": 4.5, "The Strokes": 4.0, 
"Vampire Weekend": 4.0},
"Sam": {"Blues Traveler": 5.0, "Broken Bells": 2.0, "Norah Jones": 3.0,
"Phoenix": 5.0, "Slightly Stoopid": 4.0, "The Strokes": 5.0},
"Veronica": {"Blues Traveler": 3.0, "Norah Jones": 5.0, "Phoenix": 4.0,
"Slightly Stoopid": 2.5, "The Strokes": 3.0}
        }

def manhattan(rating1, rating2):
    """Computes the Manhattan distance. Both rating1 and rating2 are dictionaries
       of the form {'The Strokes': 3.0, 'Slightly Stoopid': 2.5}"""
    distance = 0
    commonRatings = False 
    for key in rating1:
        if key in rating2:
            distance += abs(rating1[key] - rating2[key])
            commonRatings = True
    if commonRatings:
        return distance
    else:
        return -1 #Indicates no ratings in common

def computeNearestNeighbor(username, users):
    """creates a sorted list of users based on their distance to username"""
    distances = []
    for user in users:
        if user != username:
            distance = manhattan(users[user], users[username])
            distances.append((distance, user))
    # sort based on distance -- closest first
    distances.sort()
    return distances

def recommend(username, users):
    """Give list of recommendations"""
    # first find nearest neighbor
    nearest = computeNearestNeighbor(username, users)[0][1]
    print nearest
    recommendations = []
    # now find bands neighbor rated that user didn't
    neighborRatings = users[nearest]
    userRatings = users[username]
    for artist in neighborRatings:
        if not artist in userRatings:
            recommendations.append((artist, neighborRatings[artist]))
    # using the fn sorted for variety - sort is more efficient
    return sorted(recommendations, key=lambda artistTuple: artistTuple[1], reverse = True)
代码语言:javascript
复制
# -*- coding: utf-8 -*-
from math import sqrt

users = {"Angelica": {"Blues Traveler": 3.5, "Broken Bells": 2.0, "Norah Jones": 4.5, "Phoenix": 5.0, "Slightly Stoopid": 1.5, "The Strokes": 2.5, "Vampire Weekend": 2.0},
"Bill":{"Blues Traveler": 2.0, "Broken Bells": 3.5, "Deadmau5": 4.0, "Phoenix": 2.0, "Slightly Stoopid": 3.5, "Vampire Weekend": 3.0},
"Chan": {"Blues Traveler": 5.0, "Broken Bells": 1.0, "Deadmau5": 1.0, "Norah Jones": 3.0, "Phoenix": 5, "Slightly Stoopid": 1.0},
"Dan": {"Blues Traveler": 3.0, "Broken Bells": 4.0, "Deadmau5": 4.5, "Phoenix": 3.0, "Slightly Stoopid": 4.5, "The Strokes": 4.0, "Vampire Weekend": 2.0},
"Hailey": {"Broken Bells": 4.0, "Deadmau5": 1.0, "Norah Jones": 4.0, "The Strokes": 4.0, "Vampire Weekend": 1.0},
"Jordyn": {"Broken Bells": 4.5, "Deadmau5": 4.0, "Norah Jones": 5.0, "Phoenix": 5.0, "Slightly Stoopid": 4.5, "The Strokes": 4.0, "Vampire Weekend": 4.0},
"Sam": {"Blues Traveler": 5.0, "Broken Bells": 2.0, "Norah Jones": 3.0, "Phoenix": 5.0, "Slightly Stoopid": 4.0, "The Strokes": 5.0},
"Veronica": {"Blues Traveler": 3.0, "Norah Jones": 5.0, "Phoenix": 4.0, "Slightly Stoopid": 2.5, "The Strokes": 3.0}
}

#明氏距离
def minkowski(rating1,rating2,r):
  distance=0
  commonRatings=False
  for key in rating1:
    if key in rating2:
      distance += pow(abs(rating1[key]-rating2[key]),r)
      commonRatings=True
      distance = pow(distance,1.0/r)
    if commonRatings:
      return distance
    else:
      return -1 #Indicates no ratings in common

def computeNearestNeighbor(username, users):
  """creates a sorted list of users based on their distance to username"""
  distances = []
  for user in users:
    if user != username:
      distance = minkowski(users[user], users[username],3)
      distances.append((distance, user))
      # sort based on distance -- closest first
      distances.sort()
      return distances

def recommend(username, users):
  """Give list of recommendations"""
  # first find nearest neighbor
  nearest = computeNearestNeighbor(username, users)[0][1]
  print nearest
  recommendations = []
  # now find bands neighbor rated that user didn't
  neighborRatings = users[nearest]
  userRatings = users[username]
  for artist in neighborRatings:
    if not artist in userRatings:
      recommendations.append((artist, neighborRatings[artist]))
      # using the fn sorted for variety - sort is more efficient
  return sorted(recommendations, key=lambda artistTuple: artistTuple[1], reverse = True)

但是可能存在常数差别,但是两者爱好相同的问题。皮尔逊相关系数:

代码语言:javascript
复制
# Pearson.py
from math import sqrt

users = {"Angelica": {"Blues Traveler": 3.5, "Broken Bells": 2.0, "Norah Jones": 4.5, "Phoenix": 5.0, "Slightly Stoopid": 1.5, "The Strokes": 2.5, "Vampire Weekend": 2.0},
"Bill":{"Blues Traveler": 2.0, "Broken Bells": 3.5, "Deadmau5": 4.0, "Phoenix": 2.0, "Slightly Stoopid": 3.5, "Vampire Weekend": 3.0},
"Chan": {"Blues Traveler": 5.0, "Broken Bells": 1.0, "Deadmau5": 1.0, "Norah Jones": 3.0, "Phoenix": 5, "Slightly Stoopid": 1.0},
"Dan": {"Blues Traveler": 3.0, "Broken Bells": 4.0, "Deadmau5": 4.5, "Phoenix": 3.0, "Slightly Stoopid": 4.5, "The Strokes": 4.0, "Vampire Weekend": 2.0},
"Hailey": {"Broken Bells": 4.0, "Deadmau5": 1.0, "Norah Jones": 4.0, "The Strokes": 4.0, "Vampire Weekend": 1.0},
"Jordyn": {"Broken Bells": 4.5, "Deadmau5": 4.0, "Norah Jones": 5.0, "Phoenix": 5.0, "Slightly Stoopid": 4.5, "The Strokes": 4.0, "Vampire Weekend": 4.0},
"Sam": {"Blues Traveler": 5.0, "Broken Bells": 2.0, "Norah Jones": 3.0, "Phoenix": 5.0, "Slightly Stoopid": 4.0, "The Strokes": 5.0},
"Veronica": {"Blues Traveler": 3.0, "Norah Jones": 5.0, "Phoenix": 4.0, "Slightly Stoopid": 2.5, "The Strokes": 3.0}
}

# 这里为了简单使用近似代替
def pearson(rating1,rating2):
  sum_xy=0
  sum_x=0
  sum_y=0
  sum_x2=0
  sum_y2=0
  n=0
  for key in rating1:
    if key in rating2:
      n += 1
      x = rating1[key]
      y = rating2[key]
      sum_xy += x*y
      sum_x += x
      sum_y += y
      sum_x2 += x**2
      sum_y2 += y**2
  denominnator = sqrt(sum_x2-(sum_x**2)/n)*sqrt(sum_y2-(sum_y**2)/n)
  if denominnator == 0:
    return 0
  else:
    return (sum_xy-(sum_x*sum_y)/n)/denominnator

def cos_like(rating1,rating2):
  innerProd=0
  vector_x=0
  vectoy_y=0
  for key in rating1:
    if key in rating2:
      x=rating1[key]
      y=rating2[key]
      innerProd += x*y
      vector_x += x**2
      vectoy_y += y**2
  denominnator = sqrt(vector_x) * sqrt(vectoy_y)
  if denominnator == 0:
    return 0
  else:
    return innerProd / denominnator

余弦相似度:$$cos(x, y)=\frac{x·y}{||x||\times ||y||}$$ 总结:如果数据稠密使用欧氏距离;如果数据稀疏,使用余弦相似度;如果用户评级范围不同,使用皮尔逊相关系数。但是如果仅仅是基于一个用户进行推荐,个别用户的怪癖也会被推荐。

k近邻:利用k个最相似的用户确定推荐结果,K和应有有关。利用皮尔逊系数来确定每个人的影响因子。

代码语言:javascript
复制
# A dictionary of movie critics and their ratings of a small
# set of movies
critics={'Lisa Rose': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.5,
'Just My Luck': 3.0, 'Superman Returns': 3.5, 'You, Me and Dupree': 2.5, 
'The Night Listener': 3.0},
'Gene Seymour': {'Lady in the Water': 3.0, 'Snakes on a Plane': 3.5, 
'Just My Luck': 1.5, 'Superman Returns': 5.0, 'The Night Listener': 3.0, 
'You, Me and Dupree': 3.5}, 
'Michael Phillips': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.0,
'Superman Returns': 3.5, 'The Night Listener': 4.0},
'Claudia Puig': {'Snakes on a Plane': 3.5, 'Just My Luck': 3.0,
'The Night Listener': 4.5, 'Superman Returns': 4.0, 
'You, Me and Dupree': 2.5},
'Mick LaSalle': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0, 
'Just My Luck': 2.0, 'Superman Returns': 3.0, 'The Night Listener': 3.0,
'You, Me and Dupree': 2.0}, 
'Jack Matthews': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
'The Night Listener': 3.0, 'Superman Returns': 5.0, 'You, Me and Dupree': 3.5},
'Toby': {'Snakes on a Plane':4.5,'You, Me and Dupree':1.0,'Superman Returns':4.0}}


from math import sqrt

# Returns a distance-based similarity score for person1 and person2
def sim_distance(prefs,person1,person2):
  # Get the list of shared_items
  si={}
  for item in prefs[person1]: 
    if item in prefs[person2]: si[item]=1

  # if they have no ratings in common, return 0
  if len(si)==0: return 0

  # Add up the squares of all the differences
  sum_of_squares=sum([pow(prefs[person1][item]-prefs[person2][item],2) 
  for item in prefs[person1] if item in prefs[person2]])

  return 1/(1+sum_of_squares)

# Returns the Pearson correlation coefficient for p1 and p2
def sim_pearson(prefs,p1,p2):
  # Get the list of mutually rated items
  si={}
  for item in prefs[p1]: 
  if item in prefs[p2]: si[item]=1

  # if they are no ratings in common, return 0
  if len(si)==0: return 0

  # Sum calculations
  n=len(si)

  # Sums of all the preferences
  sum1=sum([prefs[p1][it] for it in si])
  sum2=sum([prefs[p2][it] for it in si])

  # Sums of the squares
  sum1Sq=sum([pow(prefs[p1][it],2) for it in si])
  sum2Sq=sum([pow(prefs[p2][it],2) for it in si]) 

  # Sum of the products
  pSum=sum([prefs[p1][it]*prefs[p2][it] for it in si])

  # Calculate r (Pearson score)
  num=pSum-(sum1*sum2/n)
  den=sqrt((sum1Sq-pow(sum1,2)/n)*(sum2Sq-pow(sum2,2)/n))
  if den==0: return 0

  r=num/den

  return r

# Returns the best matches for person from the prefs dictionary.
# Number of results and similarity function are optional params.
def topMatches(prefs,person,n=5,similarity=sim_pearson):
  scores=[(similarity(prefs,person,other),other) 
  for other in prefs if other!=person]
    scores.sort()
    scores.reverse()
  return scores[0:n]

# Gets recommendations for a person by using a weighted average
# of every other user's rankings
def getRecommendations(prefs,person,similarity=sim_pearson):
  totals={}
  simSums={}
  for other in prefs:
    # don't compare me to myself
    if other==person: continue
      sim=similarity(prefs,person,other)

    # ignore scores of zero or lower
    if sim<=0: continue
  for item in prefs[other]:

    # only score movies I haven't seen yet
    if item not in prefs[person] or prefs[person][item]==0:
    # Similarity * Score
      totals.setdefault(item,0)
      totals[item]+=prefs[other][item]*sim
    # Sum of similarities
      simSums.setdefault(item,0)
      simSums[item]+=sim

# Create the normalized list
  rankings=[(total/simSums[item],item) for item,total in totals.items()]

# Return the sorted list
  rankings.sort()
  rankings.reverse()
  return rankings

def transformPrefs(prefs):
  result={}
  for person in prefs:
  for item in prefs[person]:
    result.setdefault(item,{})

  # Flip item and person
  result[item][person]=prefs[person][item]
  return result


def calculateSimilarItems(prefs,n=10):
  # Create a dictionary of items showing which other items they
  # are most similar to.
  result={}
  # Invert the preference matrix to be item-centric
  itemPrefs=transformPrefs(prefs)
  c=0
  for item in itemPrefs:
  # Status updates for large datasets
  c+=1
  if c%100==0: print "%d / %d" % (c,len(itemPrefs))
  # Find the most similar items to this one
  scores=topMatches(itemPrefs,item,n=n,similarity=sim_distance)
  result[item]=scores
  return result

def getRecommendedItems(prefs,itemMatch,user):
  userRatings=prefs[user]
  scores={}
  totalSim={}
  # Loop over items rated by this user
  for (item,rating) in userRatings.items( ):

  # Loop over items similar to this one
  for (similarity,item2) in itemMatch[item]:

    # Ignore if this user has already rated this item
    if item2 in userRatings: continue
    # Weighted sum of rating times similarity
    scores.setdefault(item2,0)
    scores[item2]+=similarity*rating
    # Sum of all the similarities
    totalSim.setdefault(item2,0)
    totalSim[item2]+=similarity

  # Divide each total score by total weighting to get an average
  rankings=[(score/totalSim[item],item) for item,score in scores.items( )]

  # Return the rankings from highest to lowest
  rankings.sort( )
  rankings.reverse( )
  return rankings

def loadMovieLens(path='C:\Users\WangYixin\Desktop\PCI_Code\PCI_Code Folder\chapter2\data'):
  # Get movie titles
  movies={}
  for line in open(path+'/u.item'):
    (id,title)=line.split('|')[0:2]
    movies[id]=title

    # Load data
    prefs={}
  for line in open(path+'/u.data'):
    (user,movieid,rating,ts)=line.split('\t')
    prefs.setdefault(user,{})
    prefs[user][movies[movieid]]=float(rating)
  return prefs
代码语言:javascript
复制
# -*- coding: utf-8 -*-
# 推荐类
import codecs
from math import sqrt

users = {"Angelica": {"Blues Traveler": 3.5, "Broken Bells": 2.0,
"Norah Jones": 4.5, "Phoenix": 5.0,
"Slightly Stoopid": 1.5,
"The Strokes": 2.5, "Vampire Weekend": 2.0},

"Bill":{"Blues Traveler": 2.0, "Broken Bells": 3.5,
"Deadmau5": 4.0, "Phoenix": 2.0,
"Slightly Stoopid": 3.5, "Vampire Weekend": 3.0},

"Chan": {"Blues Traveler": 5.0, "Broken Bells": 1.0,
"Deadmau5": 1.0, "Norah Jones": 3.0, "Phoenix": 5,
"Slightly Stoopid": 1.0},

"Dan": {"Blues Traveler": 3.0, "Broken Bells": 4.0,
"Deadmau5": 4.5, "Phoenix": 3.0,
"Slightly Stoopid": 4.5, "The Strokes": 4.0,
"Vampire Weekend": 2.0},

"Hailey": {"Broken Bells": 4.0, "Deadmau5": 1.0,
"Norah Jones": 4.0, "The Strokes": 4.0,
"Vampire Weekend": 1.0},

"Jordyn": {"Broken Bells": 4.5, "Deadmau5": 4.0,
"Norah Jones": 5.0, "Phoenix": 5.0,
"Slightly Stoopid": 4.5, "The Strokes": 4.0,
"Vampire Weekend": 4.0},

"Sam": {"Blues Traveler": 5.0, "Broken Bells": 2.0,
"Norah Jones": 3.0, "Phoenix": 5.0,
"Slightly Stoopid": 4.0, "The Strokes": 5.0},

"Veronica": {"Blues Traveler": 3.0, "Norah Jones": 5.0,
"Phoenix": 4.0, "Slightly Stoopid": 2.5,
"The Strokes": 3.0}
}



class recommender:

  def __init__(self, data, k=1, metric='pearson', n=5):
    """ initialize recommender
    currently, if data is dictionary the recommender is initialized
    to it.
    For all other data types of data, no initialization occurs
    k is the k value for k nearest neighbor
    metric is which distance formula to use
    n is the maximum number of recommendations to make"""
    self.k = k
    self.n = n
    self.username2id = {}
    self.userid2name = {}
    self.productid2name = {}
    # for some reason I want to save the name of the metric
    self.metric = metric
    if self.metric == 'pearson':
      self.fn = self.pearson
    #
    # if data is dictionary set recommender data to it
    #
    if type(data).__name__ == 'dict':
      self.data = data

  def convertProductID2name(self, id):
    """Given product id number return product name"""
    if id in self.productid2name:
      return self.productid2name[id]
    else:
      return id


  def userRatings(self, id, n):
    """Return n top ratings for user with id"""
    print ("Ratings for " + self.userid2name[id])
    ratings = self.data[id]
    print(len(ratings))
    ratings = list(ratings.items())
    ratings = [(self.convertProductID2name(k), v)
    for (k, v) in ratings]
      # finally sort and return
      ratings.sort(key=lambda artistTuple: artistTuple[1],
      reverse = True)
      ratings = ratings[:n]
    for rating in ratings:
      print("%s\t%i" % (rating[0], rating[1]))




  def loadBookDB(self, path=''):
    """loads the BX book dataset. Path is where the BX files are
    located"""
    self.data = {}
    i = 0
    #
    # First load book ratings into self.data
    #
    f = codecs.open(path + "BX-Book-Ratings.csv", 'r', 'utf8')
    f.readline() #read the title
    for line in f:
      i += 1
      #separate line into fields
      fields = line.split(';') # still with ""
      user = fields[0].strip('"') #delete “ in the fields
      book = fields[1].strip('"')
      rating = int(fields[2].strip().strip('"'))
      if user in self.data:
        currentRatings = self.data[user]
      else:
        currentRatings = {}
        currentRatings[book] = rating
        self.data[user] = currentRatings
        #line = f.readline()
    f.close()
    #
    # Now load books into self.productid2name
    # Books contains isbn, title, and author among other fields
    #
    f = codecs.open(path + "BX-Books.csv", 'r', 'utf8')
    for line in f:
      i += 1
      #separate line into fields
      fields = line.split(';')
      isbn = fields[0].strip('"')
      title = fields[1].strip('"')
      author = fields[2].strip().strip('"')
      title = title + ' by ' + author
      self.productid2name[isbn] = title
    f.close()
    #
    # Now load user info into both self.userid2name and
    # self.username2id
    #
    f = codecs.open(path + "BX-Users.csv", 'r', 'utf8')
    for line in f:
      i += 1
      #print(line)
      #separate line into fields
      fields = line.split(';')
      userid = fields[0].strip('"')
      location = fields[1].strip('"')
      if len(fields) > 3:
        age = fields[2].strip().strip('"')
      else:
        age = 'NULL'
      if age != 'NULL':
        value = location + ' (age: ' + age + ')'
      else:
        value = location
        self.userid2name[userid] = value
        self.username2id[location] = userid
    f.close()
    print(i)


  def pearson(self, rating1, rating2):
    sum_xy = 0
    sum_x = 0
    sum_y = 0
    sum_x2 = 0
    sum_y2 = 0
    n = 0
    for key in rating1:
      if key in rating2:
        n += 1
        x = rating1[key]
        y = rating2[key]
        sum_xy += x * y
        sum_x += x
        sum_y += y
        sum_x2 += pow(x, 2)
        sum_y2 += pow(y, 2)
  if n == 0:
    return 0
  # now compute denominator
  denominator = (sqrt(sum_x2 - pow(sum_x, 2) / n)
  * sqrt(sum_y2 - pow(sum_y, 2) / n))
  if denominator == 0:
    return 0
  else:
    return (sum_xy - (sum_x * sum_y) / n) / denominator


  def computeNearestNeighbor(self, username):
    """creates a sorted list of users based on their distance to
    username"""
    distances = []
    for instance in self.data:
      if instance != username:
        distance = self.fn(self.data[username],
        self.data[instance])
        distances.append((instance, distance))
  # sort based on distance -- closest first
  distances.sort(key=lambda artistTuple: artistTuple[1],
  reverse=True)
  return distances

  def recommend(self, user):
    """Give list of recommendations"""
    recommendations = {}
    # first get list of users ordered by nearness
    nearest = self.computeNearestNeighbor(user)
    # now get the ratings for the user
    userRatings = self.data[user]
    # determine the total distance
    totalDistance = 0.0
    for i in range(self.k):
      totalDistance += nearest[i][1]
      # now iterate through the k nearest neighbors
      # accumulating their ratings
    for i in range(self.k):
      # compute slice of pie
      weight = nearest[i][1] / totalDistance
      # get the name of the person
      name = nearest[i][0]
      # get the ratings for this person
      neighborRatings = self.data[name]
      # get the name of the person
      # now find bands neighbor rated that user didn't
    for artist in neighborRatings:
      if not artist in userRatings:
        if artist not in recommendations:
          recommendations[artist] = (neighborRatings[artist] * weight)
        else:
          recommendations[artist] = (recommendations[artist] + neighborRatings[artist] * weight)
      # now make list from dictionary
    recommendations = list(recommendations.items())
    recommendations = [(self.convertProductID2name(k), v)
    for (k, v) in recommendations]
      # finally sort and return
      recommendations.sort(key=lambda artistTuple: artistTuple[1],
      reverse = True)
      # Return the first n items
  return recommendations[:self.n]

  ############test code############
  #r = recommender(users)
  #r.recommend('Jordyn')
  #r.recommend('Hailey')
  #r.loadBookDB('BX-CSV-Dump/')
  #r.recommend('171118')
  #r.userRatings('171118', 5)
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-10-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CryptoCode 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 写在之前
  • 协同过滤
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档