代码优化
This commit is contained in:
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
@@ -1,8 +1,7 @@
|
||||
package com.tarzan.recommend;
|
||||
|
||||
import com.tarzan.recommend.Service.Recommend;
|
||||
import com.tarzan.recommend.service.Recommend;
|
||||
import com.tarzan.recommend.dto.ItemDTO;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -12,49 +12,57 @@ import java.util.stream.IntStream;
|
||||
*
|
||||
* @author tarzan
|
||||
* @version 1.0
|
||||
* @company 洛阳图联科技有限公司
|
||||
* @copyright (c) 2019 LuoYang TuLian Co'Ltd Inc. All rights reserved.
|
||||
* @date 2020/7/31$ 15:21$
|
||||
* @since JDK1.8
|
||||
*/
|
||||
public class CoreMath {
|
||||
|
||||
/**
|
||||
* 方法描述: 推荐电影id列表
|
||||
*
|
||||
* @param userId 当前用户
|
||||
* @param list 用户电影评分数据
|
||||
* @return {@link List<Integer>}
|
||||
* @date 2023年02月02日 14:51:42
|
||||
*/
|
||||
public List<Integer> recommend(Integer userId, List<RelateDTO> list) {
|
||||
//找到最近邻用户id
|
||||
Map<Double, Integer> distances = computeNearestNeighbor(userId, list);
|
||||
Integer nearest = distances.values().iterator().next();
|
||||
|
||||
//按用户分组
|
||||
Map<Integer, List<RelateDTO>> userMap=list.stream().collect(Collectors.groupingBy(RelateDTO::getUseId));
|
||||
|
||||
//获取其他用户与当前用户的关系值
|
||||
Map<Double, Integer> distances = computeNeighbor(userId, userMap);
|
||||
//取关系最近的用户
|
||||
Integer nearestUserId = distances.values().iterator().next();
|
||||
//最近邻用户看过电影列表
|
||||
List<Integer> neighborItemList = userMap.get(nearest).stream().map(e->e.getModuleId()).collect(Collectors.toList());
|
||||
List<Integer> neighborItems = userMap.get(nearestUserId).stream().map(RelateDTO::getModuleId).collect(Collectors.toList());
|
||||
//指定用户看过电影列表
|
||||
List<Integer> userItemList = userMap.get(userId).stream().map(e->e.getModuleId()).collect(Collectors.toList());;
|
||||
List<Integer> userItems = userMap.get(userId).stream().map(RelateDTO::getModuleId).collect(Collectors.toList());
|
||||
|
||||
//找到最近邻看过,但是该用户没看过的电影,计算推荐,放入推荐列表
|
||||
List<Integer> recommendList = new ArrayList<>();
|
||||
for (Integer item : neighborItemList) {
|
||||
if (!userItemList.contains(item)) {
|
||||
for (Integer item : neighborItems) {
|
||||
if (!userItems.contains(item)) {
|
||||
recommendList.add(item);
|
||||
}
|
||||
}
|
||||
Collections.sort(recommendList);
|
||||
// Collections.sort(recommendList);
|
||||
return recommendList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 在给定userId的情况下,计算其他用户和它的相关系数并排序
|
||||
* @param userId
|
||||
* @param list
|
||||
* @return
|
||||
* @param userId 用户id
|
||||
* @param userMap 用户电影评分关系mqp
|
||||
* @return Map<Double, Integer>
|
||||
*/
|
||||
private Map<Double, Integer> computeNearestNeighbor(Integer userId, List<RelateDTO> list) {
|
||||
Map<Integer, List<RelateDTO>> userMap=list.stream().collect(Collectors.groupingBy(RelateDTO::getUseId));
|
||||
private Map<Double, Integer> computeNeighbor(Integer userId, Map<Integer,List<RelateDTO>> userMap) {
|
||||
Map<Double, Integer> distances = new TreeMap<>();
|
||||
List<RelateDTO> userItems=userMap.get(userId);
|
||||
userMap.forEach((k,v)->{
|
||||
if(k!=userId){
|
||||
double distance = pearson_dis(v,userMap.get(userId));
|
||||
//排除此用户
|
||||
if(!k.equals(userId)){
|
||||
//关系距离
|
||||
double distance = pearsonDis(v,userItems);
|
||||
distances.put(distance, k);
|
||||
}
|
||||
});
|
||||
@@ -65,16 +73,16 @@ public class CoreMath {
|
||||
/**
|
||||
* 计算两个序列间的相关系数
|
||||
*
|
||||
* @param xList
|
||||
* @param yList
|
||||
* @return
|
||||
* @param xList 用户1喜欢的电影
|
||||
* @param yList 用户2喜欢的电影
|
||||
* @return double
|
||||
*/
|
||||
private double pearson_dis(List<RelateDTO> xList, List<RelateDTO> yList) {
|
||||
private double pearsonDis(List<RelateDTO> xList, List<RelateDTO> yList) {
|
||||
List<Integer> xs= Lists.newArrayList();
|
||||
List<Integer> ys= Lists.newArrayList();
|
||||
xList.forEach(x->{
|
||||
yList.forEach(y->{
|
||||
if(x.getModuleId()==y.getModuleId()){
|
||||
if(x.getModuleId().equals(y.getModuleId())){
|
||||
xs.add(x.getIndex());
|
||||
ys.add(y.getIndex());
|
||||
}
|
||||
@@ -86,14 +94,13 @@ public class CoreMath {
|
||||
/**
|
||||
* 方法描述: 皮尔森(pearson)相关系数计算
|
||||
*
|
||||
* @param xs
|
||||
* @param ys
|
||||
* @Return {@link Double}
|
||||
* @throws
|
||||
* @param xs x集合
|
||||
* @param ys y集合
|
||||
* @Return {@link double}
|
||||
* @author tarzan
|
||||
* @date 2020年07月31日 17:03:20
|
||||
*/
|
||||
public static Double getRelate(List<Integer> xs, List<Integer> ys){
|
||||
public static double getRelate(List<Integer> xs, List<Integer> ys){
|
||||
int n=xs.size();
|
||||
double Ex= xs.stream().mapToDouble(x->x).sum();
|
||||
double Ey=ys.stream().mapToDouble(y->y).sum();
|
||||
@@ -102,7 +109,9 @@ public class CoreMath {
|
||||
double Exy= IntStream.range(0,n).mapToDouble(i->xs.get(i)*ys.get(i)).sum();
|
||||
double numerator=Exy-Ex*Ey/n;
|
||||
double denominator=Math.sqrt((Ex2-Math.pow(Ex,2)/n)*(Ey2-Math.pow(Ey,2)/n));
|
||||
if (denominator==0) return 0.0;
|
||||
if (denominator==0) {
|
||||
return 0D;
|
||||
}
|
||||
return numerator/denominator;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,10 +7,8 @@ import lombok.NoArgsConstructor;
|
||||
/**
|
||||
* 业务项
|
||||
*
|
||||
* @author liu yapeng
|
||||
* @author TARZAN
|
||||
* @version 1.0
|
||||
* @company 洛阳图联科技有限公司
|
||||
* @copyright (c) 2019 LuoYang TuLian Co'Ltd Inc. All rights reserved.
|
||||
* @date 2020/7/31$ 15:02$
|
||||
* @since JDK1.8
|
||||
*/
|
||||
@@ -18,9 +16,13 @@ import lombok.NoArgsConstructor;
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ItemDTO {
|
||||
/** 主键 */
|
||||
private Integer id;
|
||||
/** 名称 */
|
||||
private String name;
|
||||
/** 日期 */
|
||||
private String date;
|
||||
/** 链接 */
|
||||
private String link;
|
||||
|
||||
}
|
||||
|
||||
@@ -7,10 +7,8 @@ import lombok.NoArgsConstructor;
|
||||
/**
|
||||
* 关系数据
|
||||
*
|
||||
* @author liu yapeng
|
||||
* @author tarzan
|
||||
* @version 1.0
|
||||
* @company 洛阳图联科技有限公司
|
||||
* @copyright (c) 2019 LuoYang TuLian Co'Ltd Inc. All rights reserved.
|
||||
* @date 2020/7/31$ 14:51$
|
||||
* @since JDK1.8
|
||||
*/
|
||||
@@ -18,11 +16,11 @@ import lombok.NoArgsConstructor;
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class RelateDTO {
|
||||
//用户id
|
||||
/** 用户id */
|
||||
private Integer useId;
|
||||
//业务id
|
||||
/** 业务id */
|
||||
private Integer moduleId;
|
||||
//指数
|
||||
/** 指数 */
|
||||
private Integer index;
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import lombok.NoArgsConstructor;
|
||||
/**
|
||||
* 用户对象
|
||||
*
|
||||
* @author liu yapeng
|
||||
* @author TARZAN
|
||||
* @version 1.0
|
||||
* @company 洛阳图联科技有限公司
|
||||
* @copyright (c) 2019 LuoYang TuLian Co'Ltd Inc. All rights reserved.
|
||||
@@ -18,15 +18,15 @@ import lombok.NoArgsConstructor;
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class UserDTO {
|
||||
//主键
|
||||
/** 主键 */
|
||||
private Integer id;
|
||||
//年纪
|
||||
/** 年纪 */
|
||||
private Integer age;
|
||||
//性别
|
||||
/** 性别 */
|
||||
private String sex;
|
||||
//职业
|
||||
/** 职业 */
|
||||
private String profession;
|
||||
//邮编
|
||||
/** 邮编 */
|
||||
private String postcode;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.tarzan.recommend.Service;
|
||||
package com.tarzan.recommend.service;
|
||||
|
||||
import com.tarzan.recommend.dto.ItemDTO;
|
||||
import com.tarzan.recommend.dto.RelateDTO;
|
||||
@@ -10,7 +10,11 @@ import org.assertj.core.util.Lists;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author tarzan
|
||||
*/
|
||||
@Data
|
||||
@Slf4j
|
||||
public class FileDataSource {
|
||||
@@ -22,20 +26,18 @@ public class FileDataSource {
|
||||
/**
|
||||
* 方法描述: 读取基础数据
|
||||
*
|
||||
* @param
|
||||
* @Return {@link List<RelateDTO>}
|
||||
* @throws
|
||||
* @author tarzan
|
||||
* @date 2020年07月31日 16:53:40
|
||||
*/
|
||||
public static List<RelateDTO> getData() {
|
||||
folderPath=new FileDataSource().getClass().getResource("/ml-100k").getPath();
|
||||
folderPath= Objects.requireNonNull(FileDataSource.class.getResource("/ml-100k")).getPath();
|
||||
List<RelateDTO> relateList = Lists.newArrayList();
|
||||
try {
|
||||
FileInputStream out = new FileInputStream(folderPath+"\\u.data");
|
||||
InputStreamReader reader = new InputStreamReader(out, StandardCharsets.UTF_8);
|
||||
BufferedReader in = new BufferedReader(reader);
|
||||
String line = null;
|
||||
String line;
|
||||
while ((line = in.readLine()) != null) {
|
||||
String newline = line.replaceAll("[\t]", " ");
|
||||
String[] ht = newline.split(" ");
|
||||
@@ -54,20 +56,18 @@ public class FileDataSource {
|
||||
/**
|
||||
* 方法描述: 读取用户数据
|
||||
*
|
||||
* @param
|
||||
* @Return {@link List<UserDTO>}
|
||||
* @throws
|
||||
* @author tarzan
|
||||
* @date 2020年07月31日 16:54:51
|
||||
*/
|
||||
public static List<UserDTO> getUserData() {
|
||||
folderPath=new FileDataSource().getClass().getResource("/ml-100k").getPath();
|
||||
folderPath= Objects.requireNonNull(FileDataSource.class.getResource("/ml-100k")).getPath();
|
||||
List<UserDTO> userList = Lists.newArrayList();
|
||||
try {
|
||||
FileInputStream out = new FileInputStream(folderPath+"\\u.user");
|
||||
InputStreamReader reader = new InputStreamReader(out, StandardCharsets.UTF_8);
|
||||
BufferedReader in = new BufferedReader(reader);
|
||||
String line = null;
|
||||
String line;
|
||||
while ((line = in.readLine()) != null) {
|
||||
String newline = line.replaceAll("[\t]", " ");
|
||||
String[] ht = newline.split("\\|");
|
||||
@@ -89,20 +89,18 @@ public class FileDataSource {
|
||||
/**
|
||||
* 方法描述: 读取电影数据
|
||||
*
|
||||
* @param
|
||||
* @Return {@link List<ItemDTO>}
|
||||
* @throws
|
||||
* @author tarzan
|
||||
* @date 2020年07月31日 16:54:22
|
||||
*/
|
||||
public static List<ItemDTO> getItemData() {
|
||||
folderPath=new FileDataSource().getClass().getResource("/ml-100k").getPath();
|
||||
folderPath= Objects.requireNonNull(FileDataSource.class.getResource("/ml-100k")).getPath();
|
||||
List<ItemDTO> itemList = Lists.newArrayList();
|
||||
try {
|
||||
FileInputStream out = new FileInputStream(folderPath+"\\u.item");
|
||||
InputStreamReader reader = new InputStreamReader(out, StandardCharsets.UTF_8);
|
||||
BufferedReader in = new BufferedReader(reader);
|
||||
String line = null;
|
||||
String line;
|
||||
while ((line = in.readLine()) != null) {
|
||||
String newline = line.replaceAll("[\t]", " ");
|
||||
String[] ht = newline.split("\\|");
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.tarzan.recommend.Service;
|
||||
package com.tarzan.recommend.service;
|
||||
|
||||
import com.tarzan.recommend.core.CoreMath;
|
||||
import com.tarzan.recommend.dto.ItemDTO;
|
||||
@@ -10,9 +10,8 @@ import java.util.stream.Collectors;
|
||||
/**
|
||||
* 推荐服务
|
||||
*
|
||||
* @author liu yapeng
|
||||
* @author TARZAN
|
||||
* @version 1.0
|
||||
* @copyright (c) 2019 LuoYang TuLian Co'Ltd Inc. All rights reserved.
|
||||
* @date 2020/7/31$ 16:18$
|
||||
* @since JDK1.8
|
||||
*/
|
||||
@@ -21,9 +20,8 @@ public class Recommend{
|
||||
/**
|
||||
* 方法描述: 猜你喜欢
|
||||
*
|
||||
* @param
|
||||
* @param userId 用户id
|
||||
* @Return {@link List<ItemDTO>}
|
||||
* @throws
|
||||
* @author tarzan
|
||||
* @date 2020年07月31日 17:28:06
|
||||
*/
|
||||
@@ -31,8 +29,7 @@ public class Recommend{
|
||||
CoreMath coreMath = new CoreMath();
|
||||
List<RelateDTO> data= FileDataSource.getData();
|
||||
List<Integer> recommendations = coreMath.recommend(userId, data);
|
||||
List<ItemDTO> itemList= FileDataSource.getItemData().stream().filter(e->recommendations.contains(e.getId())).collect(Collectors.toList());
|
||||
return itemList;
|
||||
return FileDataSource.getItemData().stream().filter(e->recommendations.contains(e.getId())).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user