mysql求分位数_给Mysql加自定义函数计算百分位数(percentile)。
百分位数(percentile)的详细定义见百度百科。
在这里我用一个通俗的例子来补充解释, 例如今年有900万人参加了高考,自然有900万个成绩,某个学校计划择优招生分数最高的前900个,那么分数线应该是多少呢,这就涉及到百分位的计算,这个学校录取的百分比就是万分之一,分数线的位置在万分之九千九百九十九,化成百分比就是99.99%,那对应这个百分比位置的具体数值是多少呢,这个说的就是百分位(percentile)。
Mysql中要实现根据若干条记录的某个字段获取指定百分位的值,用常规的自定义函数似乎行不通。我们用C/C++语言写一个mysql插件。
udf_percentile.cc, 这是插件的源代码。
/*
returns the percentile of the values in a distribution
input parameters:
data (real or int)
desired percentile of result, 0-1 (double)
decimals of output (optional, int)
output:
percentile value of the distribution (real)
compiling
gcc -fPIC -Wall -I /usr/include/mysql51/mysql/ -shared -o udf_percentile.so udf_percentile.cc
udf_percentile.so /usr/lib64/mysql/plugin/
registering the function:
CREATE AGGREGATE FUNCTION percentile RETURNS REAL SONAME 'udf_percentile.so';
getting rid of the function:
DROP FUNCTION percentile;
hat tip to Jan Steemann's udf_median function http://mysql-udf.sourceforge.net/
*/
#ifdef STANDARD
#include
#include
#include
#ifdef __WIN__
typedef unsigned __int64 ulonglong;
typedef __int64 longlong;
#else
typedef unsigned long long ulonglong;
typedef long long longlong;
#endif /*__WIN__*/
#else
#include
#include
#endif
#include
#include
#include
#ifdef HAVE_DLOPEN
#define BUFFERSIZE 1024
extern "C" {
my_bool percentile_init( UDF_INIT* initid, UDF_ARGS* args, char* message );
void percentile_deinit( UDF_INIT* initid );
void percentile_reset( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
void percentile_clear(UDF_INIT* initid, char *is_null, char *error);
void percentile_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
double percentile( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
}
struct percentile_data
{
unsigned long count;
unsigned long abscount;
unsigned long pages;
double *values;
};
my_bool percentile_init( UDF_INIT* initid, UDF_ARGS* args, char* message )
{
if ( args->arg_count < 2 || args->arg_count>3)
{
strcpy(message,"wrong number of arguments: percentile() requires two - three arguments");
return 1;
}
if (args->arg_type[0]!=REAL_RESULT && args->arg_type[0]!=INT_RESULT)
{
strcpy(message,"percentile() requires a real or int as parameter 1");
return 1;
}
if (args->arg_type[1]!=REAL_RESULT && args->arg_type[1]!=INT_RESULT && args->arg_type[1]!=DECIMAL_RESULT)
{
asprintf(&message,"percentile() requires a real/int as parameter 2, instead %d",args->arg_type[1]);
return 1;
}
if (args->arg_count>2 && args->arg_type[2]!=INT_RESULT)
{
strcpy(message,"percentile() requires an int as parameter 3");
return 1;
}
initid->decimals=2;
if (args->arg_count==3 && (*((ulong*)args->args[2])<=16))
{
initid->decimals=*((ulong*)args->args[2]);
}
percentile_data *buffer = new percentile_data;
buffer->count = 0;
buffer->abscount=0;
buffer->pages = 1;
buffer->values = NULL;
initid->maybe_null = 1;
initid->max_length = 32;
initid->ptr = (char*)buffer;
return 0;
}
void percentile_deinit( UDF_INIT* initid )
{
percentile_data *buffer = (percentile_data*)initid->ptr;
if (buffer->values != NULL)
{
free(buffer->values);
buffer->values=NULL;
}
delete initid->ptr;
}
void percentile_clear(UDF_INIT* initid, char *is_null, char *error){
percentile_data *buffer = (percentile_data*)initid->ptr;
buffer->count = 0;
buffer->abscount=0;
buffer->pages = 1;
*is_null = 0;
*error = 0;
if (buffer->values != NULL)
{
free(buffer->values);
buffer->values=NULL;
}
buffer->values=(double *) malloc(BUFFERSIZE*sizeof(double));
}
void percentile_reset( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* is_error )
{
percentile_clear(initid, is_null, is_error);
percentile_add( initid, args, is_null, is_error );
}
void percentile_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* is_error )
{
if (args->args[0]!=NULL)
{
percentile_data *buffer = (percentile_data*)initid->ptr;
if (buffer->count>=BUFFERSIZE)
{
buffer->pages++;
buffer->count=0;
buffer->values=(double *) realloc(buffer->values,BUFFERSIZE*buffer->pages*sizeof(double));
}
if(args->arg_type[0]==INT_RESULT){
buffer->values[buffer->abscount++] = (double) *((longlong*)args->args[0]);
}
else{
buffer->values[buffer->abscount++] = *((double*)args->args[0]);
}
buffer->count++;
}
}
int compare_doubles (const void *a, const void *b)
{
const double *da = (const double *) a;
const double *db = (const double *) b;
return (*da > *db) - (*da < *db);
}
double percentile( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* is_error )
{
percentile_data* buffer = (percentile_data*)initid->ptr;
double pctile;
if (buffer->abscount==0 || *is_error!=0)
{
*is_null = 1;
return 0.0;
}
*is_null=0;
if (buffer->abscount==1)
{
return buffer->values[0];
}
qsort(buffer->values,buffer->abscount,sizeof(double),compare_doubles);
if(args->arg_type[1]==INT_RESULT){
pctile = (double) *((longlong*)args->args[1]);
}
else if(args->arg_type[1]==DECIMAL_RESULT){
pctile = atof(args->args[1]);
}
else{
pctile = *((double*)args->args[1]);
}
int n = buffer->abscount - 1;
if(pctile <=0){
return buffer->values[0];
}
if(pctile>=1){
return buffer->values[n];
}
double i = n * pctile;
int ix = (int) i;
if (i == ix)
{
return buffer->values[ix];
} else
{
int j = ix + 1 >= n ? n : ix + 1;
return(buffer->values[ix]*(j - i) + buffer->values[j]*(i - ix));
}
}
#endif
将以上源代码编译成.so文件
gcc -fPIC -Wall -I /usr/include/mysql/ -shared -o udf_percentile.so udf_percentile.cc
在ubuntu下,如果没有/usr/include/mysql, 需要先安装libmysqlclient-dev:sudo apt-get install libmysqlclient-dev。如果是mysql5.x,你可以下载我编译好的so文件。
将so文件拷贝到mysql的插件目录下:
sudo cp udf_percentile.so /usr/lib/mysql/plugin/
以管理员身份进入mysql,注册自定义函数:
CREATE AGGREGATE FUNCTION percentile RETURNS REAL SONAME 'udf_percentile.so';
使用方法:
SELECT percentile(score, 0.9991,5) FROM candidates;
0.9991就是百分位(99.91%),5是指结果的精度(小数位数)。
没有mysql服务的管理权限的,只能通过程序实现了,最后附上percentile的JAVA和JS实现。
JAVA:
public static double percentile(double[] data,double p){
int n = data.length;
Arrays.sort(data);
double px = p*(n-1);
int i = (int)java.lang.Math.floor(px);
double g = px - i;
if(g==0){
return data[i];
}else{
return (1-g)*data[i]+g*data[i+1];
}
}
JS:
const percentile = (data, p) =>{
let n = data.length;
data.sort((a, b) => a - b);
let px = p*(n-1);
let i = Math.floor(px);
let g = px - i;
if(g==0){
return data[i];
}else{
return (1-g)*data[i]+g*data[i+1];
}
}
mysql求分位数_给Mysql加自定义函数计算百分位数(percentile)。相关推荐
- mysql求分位数_分位函数(四分位数)概念与pandas中的quantile函数
函数原型 DataFrame.quantile(q=0.5, axis=0, numeric_only=True, interpolation='linear') 参数 - q : float or ...
- MySQL学习笔记_关于MySQL的字符类型VARCHAR长度知识总结
MySQL学习笔记_关于MySQL的字符类型VARCHAR长度知识总结 一.VARCHAR存储和行长度限制 1.VARCHAR(N)中,N指的是字符的长度,VARCHAR类型最大支持65535,指的是 ...
- pandas编写自定义函数计算多个数据列的加和(sum)、使用groupby函数和apply函数聚合计算分组内多个数据列的加和
pandas编写自定义函数计算多个数据列的加和(sum).使用groupby函数和apply函数聚合计算分组内多个数据列的加和 目录
- R语言编写自定义函数计算R方、使用自助法Bootstrapping估计多元回归模型的R方的置信区间、可视化获得的boot对象、估计单个统计量的置信区间、分别使用分位数法和BCa法
R语言编写自定义函数计算R方.使用自助法Bootstrapping估计多元回归模型的R方的置信区间.可视化获得的boot对象.估计单个统计量的置信区间.分别使用分位数法和BCa法(Bootstrapp ...
- Python Turtle 绘图[难度2星]:一朵雪花(基础代码 、 加变量/加自定义函数优化)
2022年北京冬奥会开幕式上"一朵雪花"贯穿始终,给大家印象深刻.今天我们也让海龟来绘制一朵雪花.先绘制一朵普通雪花,在下一期分享中再让海龟来绘制一朵"中国结雪花&quo ...
- python函数求n年后本息_Python自定义函数计算给定日期是该年第几天的方法示例...
本文实例讲述了Python自定义函数计算给定日期是该年第几天的方法.分享给大家供大家参考,具体如下: 写一个函数,计算给定日期是该年的第几天. 满足闰年的条件: 闰年是公历中的名词,能被4整除但不能被 ...
- Python使用numpy包编写自定义函数计算平均绝对误差(MAE、Mean Absolute Error)、评估回归模型和时间序列模型、解读MAE
Python使用numpy包编写自定义函数计算平均绝对误差(MAE.Mean Absolute Error).评估回归模型和时间序列模型.解读MAE 目录
- python编写自定义函数计算一维numpy数组中与指定目标数值最接近(距离最近)的数值(find closest value in numpy array to a certain value)
python编写自定义函数计算一维numpy数组中与指定目标数值最接近(距离最近)的数值(find closest value in numpy array to a certain value) 目 ...
- Python使用numpy包编写自定义函数计算均方误差(MSE、mean squared error)、评估回归模型和时间序列模型、解读MSE评估指标
Python使用numpy包编写自定义函数计算均方误差(MSE.mean squared error).评估回归模型和时间序列模型.解读MSE评估指标 目录
最新文章
- 'or'='or'经典漏洞原理分析
- 友盟分享和cocos2dx符合重复duplicate symbol 解决方案
- python mysqldb cursor_python中MySQLdb模块用法实例
- linux go redis,go-redis 连接池
- QT4 自定义槽和信号
- 看阿里云如何用云上技术创新,帮助哈啰单车实现智能数据收治
- java如何实例化集合_如何在java中实例化一个Queue对象?
- 弗吉尼亚州为数据中心建设的电力线路产生争议
- TensorFlow神经网络(九)VGG net论文阅读笔记
- 运用提示原则证明线性无关
- Python网页爬虫之中文乱码
- 【 javascript 】.innerHTML属性定义
- 【回归预测】基于matlab灰狼算法优化ELMAN神经网络回归预测【含Matlab源码 1782期】
- 侠客X部分截图 官方论坛开发注册 邀您一起公测。
- Servlet各种接口和类
- 最新超完整的易支付PHP源码+代码全开源
- Pytorch优化器全总结(二)Adadelta、RMSprop、Adam、Adamax、AdamW、NAdam、SparseAdam(重置版)
- 简单的外网映射工具natapp操作
- grep exclude
- 简普科技Q3财报解读:业绩超过预期之后的更多确定性