【基于双重差分法在小红书的案例实践】使用JavaSE和MySQL知识实现

项目的大概流程

  1. 创建MySQL中的具体的数据库和表格,作为原始数据
  2. 在IDEA中建立MySQL JDBC的驱动
  3. 在具体的类中编写代码,完成具体的业务分析
  4. 实验组与对照组的区分
  5. 计算比较两组的差异
双重差分法的使用逻辑(DID):
1.分组:

将所有的数据分为实验组对照组:

  1. 实验组:指接收推荐标签的用户(受到干预)
  2. 对照组:指没有接收推荐标签的用户(未受到干预)
2.思路如下:

在遍历 SQL 查询结果时,判断每个用户是否受到了干预,

将实验组和对照组用户的干预前后数据分别累加,

并统计各组的样本数量

计算实验组和对照组在干预前后的均值

  1. 实验组:干预前均值 avgTreatedBefore

  2. 实验组: 干预后均值 avgTreatedAfter

  3. 对照组:未被干预前均值 avgControlBefore

  4. 对照组: 未被干预后均值 avgControlAfter

3.计算两组差异:

实验组差异值 = 实验组干预后的平均值 - 实验组干预前的平均值。

对照组差异值 = 对照组干预后的平均值 - 对照组干预前的平均值。

最后通过 实验组差异 - 对照组差异 计算推荐内容对用户行为的净影响.

  1. 方法调用:

    调用 calculate 方法,分别计算推荐内容对 用户留存率
    发布作品量 的影响。
    这两个影响值基于用户在干预前后的活跃天数和作品发布量进行分析。

5异常处理:

使用了 try-with-resources 自动管理数据库资源,确保在程序执行完后关闭数据库连接。
若发生异常,则会捕获并输出异常信息.

第一部分: 数据库连接和数据获取:

1.创建数据库:

create database xiaohongshu character set utf8mb4;

之所以设置字符集为utf8mb4,是因为这个字符集支持中文字符

2.创建表:

create table userbehavior (
user_id int primary key, --(用户ID)主键
favorite_tag varchar(50), --用户喜欢的标签
received_recommendation tinyint(1), --是否接受标签
active_days_before int, ---- 用户在干预前活跃天数
active_days_after int, ---- 用户在干预后活跃天数
posts_before int, ---- 干预前发布作品数量
posts_after int ----干预后发布作品数量
);

3.插入数据:

insert into userbehavior (user_id, favorite_tag, received_recommendation, active_days_before, active_days_after, posts_before, posts_after)
values
(1, ‘游戏’, 1, 10, 20, 2, 5),
(2, ‘动漫’, 0, 8, 10, 1, 2),
(3, ‘颜值’, 1, 15, 25, 3, 8),
(4, ‘赛车’, 0, 12, 14, 0, 1),
(5, ‘美食’, 1, 9, 16, 1, 4),
(6, ‘电影’, 0, 7, 9, 1, 2),
(7, ‘搞笑’, 1, 11, 22, 2, 6),
(8, ‘游戏’, 0, 13, 14, 3, 3);

4.查询数据:

select *
from userbehavior;

在这里插入图片描述

5.数据库创建完成之后回到IDEA中进行数据库的连接

首先通过 JDBC 连接 MySQL 数据库,获取表 UserBehavior 中与实验相关的列数据。列分别表示用户是否接收推荐内容、干预前行为、干预后行为(例如,活跃天数和发布作品量)。

第一步: 导入连接MySQL需要的各种类

import java.sql.* ;

第二步: 编写数据库的连接信息:
  1. 定义一个私有化的常量URL
private static final String URL = "jdbc:mysql://LAPTOP-PREV8ACU:3306/xiaohongshu?useSSL=false&serverTimezone=Asia/Shanghai";
  1. 基本格式:
    这段代码是用来指定 Java 程序中连接 MySQL 数据库的 JDBC 连接 URL。具体解释如下:

jdbc:mysql://主机名:端口号/数据库名称?参数名=参数值&参数名=参数值…

  1. 主机名和端口号每个电脑都不同
    应该使用如下命令查看

show variables like ‘hostname’;

在这里插入图片描述

这里的数据库地址 是指定了一个 JDBC 连接 URL,用于连接本地主机名 LAPTOP-PREV8ACU 上运行的 MySQL 数据库 xiaohongshu,使用默认端口 3306,禁用 SSL 安全连接,并将时区设置为 Asia/Shanghai(亚洲/上海)。

第三步:指定用户名和密码
private static final String USER = "root";
private static final String PASSWORD = "123456";
第四步:定义一个方法使用双重差分法
双重差分法的定义:

双重差分法(Difference -in- Difference Method 简称 DID)
是一种常用的计量经济学方法, 用于评估 政策或干预措施对某个变量的影响
研究者利 用该方法可设计两个不同组别(实验组和对照组) 和两个不同时间点(干预前和干预后)的数据
通过 比较不同组别和不同时间点的数据来评估干预的效果

引用的参考文献:
中国知网:
基于双重差分法的家校社协同育人效应评估

双重差分法的核心思想
双重差分法的核心思想是通过比较干预实施前后,处理组与对照组之间的差异变化从而得出结论.

6.解析代码:

try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD))
使用 Connection中的DriverManager 类连接数据库,传入数据库地址,用户名,地址

String query = "select " +treatmentColumn + “, " +
beforeColumn + " , " + afterColumn + " from userbehavior”;

作用类似于下面这个在Mysql中写的命令:

select treatmentColumn, beforeColumn, afterColumn from userbehavoir;

如图:
在这里插入图片描述

PreparedStatement statement = conn.prepareStatement(query);
这行代码用于执行上一行那条SQL查询语句

ResultSet resultSet = statement.executeQuery();
将执行的结果保存到resultSet中

while (resultSet.next())
//使用while循环去遍历结果当中的每一条

完整代码如下:


//传入参数,是否被干预, 干预前,干预后
public static double calculate(String treatmentColumn, String beforeColumn, String afterColumn) {  
//初始化各个参数的值
     //干预之前的                //干预了之后的
    double treatedBefore = 0.0, treatedAfter = 0.0;  


   //没有干预之前的              //没有干预之后的
    double controlBefore = 0.0, controlAfter = 0.0;  
 
  //计数器,计算两组的数量,为了方便计算平均值
    int treatedCount = 0, controlCount = 0;  
  
  
   //使用Connection中的DriverManger类进行连接,传入URL,用户名,密码
    try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD)) {  

//是特定的查询语句,查询指定的三列从UserBehavior表中
    String query = "SELECT " + treatmentColumn + ", " +beforeColumn + ", " + afterColumn + " FROM UserBehavior";  

//执行查询语句
    PreparedStatement statement = conn.prepareStatement(query);  

//保存查询结果,结果存到resultSet
    ResultSet resultSet = statement.executeQuery();  
  
    //遍历每一条查询到的结果  
    while (resultSet.next()) {  

		//对每一条结果进行判断,是否受到干预
            boolean receivedTreatment = resultSet.getBoolean(treatmentColumn);
            //将干预前,干预后的结果存到before和after中
            int before = resultSet.getInt(beforeColumn);  
            int after = resultSet.getInt(afterColumn);  

			//如果是受到干预的,将干预后结果和干预前的结果分别存入
            if (receivedTreatment) {  
                treatedBefore += before;  
                treatedAfter += after;  
                treatedCount++; 
			
            }
            //没有受到干预的也一样
			else {  
                controlBefore += before;  
                controlAfter += after;  
                controlCount++;  
            }  
        }  
  
        // 计算平均值  
        //计算实验组和对照组在干预前后的平均值。  
        //使用差异中差异法 (DID) 公式:(实验组的差异 - 对照组的差异),  
       
        double avgTreatedBefore = treatedBefore / treatedCount;  
        double avgTreatedAfter = treatedAfter / treatedCount;  
        double avgControlBefore = controlBefore / controlCount;  
        double avgControlAfter = controlAfter / controlCount;  

         //计算实验组差异
        double treatedDifference = avgTreatedAfter - avgTreatedBefore;  

         //计算对照组差异
        double controlDifference = avgControlAfter - avgControlBefore;  
  

        //返回 (实验组差异 - 对照组差异)
        return treatedDifference - controlDifference;  
  
    } catch (Exception e) {   
        e.printStackTrace();  
    }  
    return 0.0;     
}
第五步:使用main方法调用
  
public static void main(String[] args) {  

//传入参数(是否被干预, 干预之前的天数, 干预之后的天数)
    double recommend01 = calculate("received_recommendation", "active_days_before", "active_days_after");  
    System.out.println("推荐特定标签内容对用户留存率的影响: " + recommend01);  

//传入参数(是否被干预, 干预之前的发布量,干预之后的发布量)
    double recommend02 = calculate("received_recommendation", "posts_before", "posts_after");  
    System.out.println("推荐特定标签内容对用户发布作品量的影响: " + recommend02);  
    
} 
出现过的报错:

java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘SELECTreceived_recommendation, active_days_before, active_days_afterFROM UserBeh’ at line 1

这段话说明:在java当中写的select语句有错误,编译器无法识别这个select语句,于是就报错了,可能是如下错误:

SQL语法的问题、字段名与SQL的关键字冲突

参考博客:
博客原文

我自己发现在代码中的这一行代码报错:

//是特定的查询语句,查询指定的三列从UserBehavior表中
String query = “SELECT” + treatmentColumn + ", " +beforeColumn + “, " + afterColumn + " FROM UserBehavior”;

解决办法如图所示:
在这里插入图片描述

SELECT的后面不加空格就会报错:
在这里插入图片描述

SELECT的后面加了空格就可以正常运行了:
在这里插入图片描述

上面是不加空格会报错,下面是在传参的过程中加了空格会报错,不加空格反而是对的:
在main中调用方法传参时,是不可以加空格的,不然就会报错:
如图:
在这里插入图片描述

解决办法就是把空格去掉:
在这里插入图片描述

所有
SQL完整代码如下:


--创建名为xiaohongshu 的数据库
create database xiaohongshu character set utf8mb4;


--创建表userbehavior
create table  userbehavior ( 
		user_id int primary key, --(用户ID)主键
		favorite_tag varchar(50), --用户喜欢的标签
		received_recommendation tinyint(1),  --是否接受标签
		active_days_before int,   ---- 用户在干预前活跃天数
		active_days_after int,    ---- 用户在干预后活跃天数
		posts_before int,         ---- 干预前发布作品数量
		posts_after int           ----干预后发布作品数量
> 	  );



--插入数据
insert into  insert into  userbehavior (user_id, favorite_tag, received_recommendation, active_days_before, active_days_after, posts_before, posts_after) 
values
(1, '游戏', 1, 10, 20, 2, 5), 
(2, '动漫', 0, 8, 10, 1, 2), 
(3, '颜值', 1, 15, 25, 3, 8),
(4, '赛车', 0, 12, 14, 0, 1), 
(5, '美食', 1, 9, 16, 1, 4), 
(6, '电影', 0, 7, 9, 1, 2), 
(7, '搞笑', 1, 11, 22, 2, 6), 
(8, '游戏', 0, 13, 14, 3, 3);

--查询是否插入成功:
select *
from userbehavior;

Java完整代码如下:

import java.sql.*;


public class Xiaohongshu {

	private static final String URL = "jdbc:mysql://LAPTOP-PREV8ACU:3306/xiaohongshu?useSSL=false&serverTimezone=Asia/Shanghai";  

private static  final String USER = "root";  

private static final String PASSWORD = "123456";

```java

//传入参数,是否被干预, 干预前,干预后
public static double calculate(String treatmentColumn, String beforeColumn, String afterColumn) {  
//初始化各个参数的值
     //干预之前的                //干预了之后的
    double treatedBefore = 0.0, treatedAfter = 0.0;  


   //没有干预之前的              //没有干预之后的
    double controlBefore = 0.0, controlAfter = 0.0;  
  //计数器,计算两组的数量,为了方便计算平均值

    int treatedCount = 0, controlCount = 0;  
  
  
   //使用Connection 进行连接,传入URL,用户名,密码
    try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD)) {  

//是特定的查询语句,查询指定的三列从UserBehavior表中
    String query = "SELECT " + treatmentColumn + ", " +beforeColumn + ", " + afterColumn + " FROM UserBehavior";  

//拼接具体的查询语句
    PreparedStatement statement = conn.prepareStatement(query);  

//执行查询语句,结果存到resultSet
    ResultSet resultSet = statement.executeQuery();  
  
    //遍历每一条查询到的结果  
    while (resultSet.next()) {  

		//对每一条结果进行判断,是否受到干预
            boolean receivedTreatment = resultSet.getBoolean(treatmentColumn);
            //将干预前,干预后的结果存到before和after中
            int before = resultSet.getInt(beforeColumn);  
            int after = resultSet.getInt(afterColumn);  

			//如果是受到干预的,将干预后结果和干预前的结果分别存入
            if (receivedTreatment) {  
                treatedBefore += before;  
                treatedAfter += after;  
                treatedCount++; 
			
            }
            //没有受到干预的也一样
			else {  
                controlBefore += before;  
                controlAfter += after;  
                controlCount++;  
            }  
        }  
  
        // 计算平均值  
        //计算实验组和对照组在干预前后的平均值。  
        //使用差异中差异法 (DID) 公式:(实验组的差异 - 对照组的差异),  
       
        double avgTreatedBefore = treatedBefore / treatedCount;  
        double avgTreatedAfter = treatedAfter / treatedCount;  
        double avgControlBefore = controlBefore / controlCount;  
        double avgControlAfter = controlAfter / controlCount;  

         //计算实验组差异
        double treatedDifference = avgTreatedAfter - avgTreatedBefore;  

         //计算对照组差异
        double controlDifference = avgControlAfter - avgControlBefore;  
  

        //返回 (实验组差异 - 对照组差异)
        return treatedDifference - controlDifference;  
  
    } catch (Exception e) {   
        e.printStackTrace();  
    }  
    return 0.0;     
}



public static void main(String[] args) {  

//传入参数(是否被干预, 干预之前的天数, 干预之后的天数)
    double recommend01 = calculate("received_recommendation", "active_days_before", "active_days_after");  
    System.out.println("推荐特定标签内容对用户留存率的影响: " + recommend01);  

//传入参数(是否被干预, 干预之前的量,干预之后的量)
    double recommend02 = calculate("received_recommendation", "posts_before", "posts_after");  
    System.out.println("推荐特定标签内容对用户发布作品量的影响: " + recommend02);  
    
} 

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值