zoukankan      html  css  js  c++  java
  • Matlab 日期频次统计

    一、孕妇建档月份频次统计

    源数据样本,为某医院一段时间内的孕妇建档时间

    2015-04-22 10:12:52
    2014-11-21 17:16:47
    2013-12-16 17:35:44
    2013-12-26 16:58:46
    2013-12-27 16:44:33
    2013-12-27 16:45:32
    2013-12-30 8:26:20
    2013-12-30 9:47:27
    2013-12-30 8:46:42
    2013-12-30 11:00:06
    2013-12-30 11:08:42

    分析目的:统计每个月的孕妇建档频次,这就要提取源数据的第一列,同截取年月数据,然后做频次直方图,看孕妇建档频次有没有随月份变化的规律。

    Matlab 代码:

    %孕妇建档日期统计
    [datestr,timestr]=textread('PregnantWomanFileTime.txt','%s%s');
    f=cell2mat(datestr);
    f=f(:,1:7);
    f=tabulate(f);
    f=sortrows(f,1);
    bar(cell2mat(f(:,2)),1);
    set(gca,'XTickLabel',f(:,1),'XTick',[1:length(f(:,1))]);
    title( '孕妇建档时间统计' );%下面的代码是为了旋转横坐标轴标签
    xtb = get(gca,'XTickLabel');% 获取横坐标轴标签句柄
    xt = get(gca,'XTick');% 获取横坐标轴刻度句柄
    yt = get(gca,'YTick'); % 获取纵坐标轴刻度句柄
    xtextp=xt;%每个标签放置位置的横坐标
    ytextp=yt(1)*ones(1,length(xt));
    text(xtextp,ytextp,xtb,'HorizontalAlignment','right','VerticalAlignment','top','rotation',45,'fontsize',10); 
    set(gca,'xticklabel','');% 将原有的标签隐去

    最终生成效果图:

    下面将对上面的 Matlab 代码进行分析。

    1、读取 txt 中的日期时间数据

    如果 txt 中是两列数值,譬如「1981 1986」,那只需要用 M = load('shuzhi.txt') 就可读取进 M 矩阵中,如下图所示。

    >> M = load('CoupleBirth.txt');
    >> M(1:4,:)
    
    ans =
    
            1981        1986
            1988        1993
            1985        1989
            1984        1984

    然后就可以用 M(:,1) 和 M(:,2) 访问这两列数据。

    但本例中我们要读取的不是数值数据,而是包含日期的字符串,我们就不能再用 load 函数读取了,要用 textread 函数。因为是两列数据,就不能用 M=textread('PregnantWomanFileTime.txt','%s'); 来读取了,如果硬要这样读,那日期和时间就会在返回的元胞数组 M 中混到一块,如下所示:

    >> M=textread('PregnantWomanFileTime.txt','%s');
    >> M(1:4)
    
    ans = 
    
        '2015-04-22'
        '10:12:52'
        '2014-11-21'
        '17:16:47'

    为了把两列数据分别读进两个元胞数组,要使用:

    >> [datestr,timestr]=textread('PregnantWomanFileTime.txt','%s%s');
    >> datestr(1:4)
    
    ans = 
    
        '2015-04-22'
        '2014-11-21'
        '2013-12-16'
        '2013-12-26'

    textread 函数返回的是装满数据的元胞数组,datestr 和 timestr 都是元胞数组。

    元胞数组是MATLAB的一种特殊数据类型,可以将元胞数组看做一种无所不包的通用矩阵。通过小括号()里面加下标,访问cell数组中的数据,返回的是对应的cell。通过大括号{}里面加下标,访问cell数组中的数据,返回的是对应cell的内容。

    >> [datestr,timestr]=textread('PregnantWomanFileTime.txt','%s%s');
    >> datestr(1)
    
    ans = 
    
        '2015-04-22'
    
    >> class(datestr(1))
    
    ans =
    
    cell
    
    >> datestr{1}
    
    ans =
    
    2015-04-22
    
    >> class(datestr{1})
    
    ans =
    
    char

    2、从 2015-04-22 中提取出 2015-04 来

    可以用正则表达式,但我们这里使用矩阵的方法,正则表达式的方法我们后面介绍。目前 datestr 还是 cell 元胞数组,我们先把元胞数组转成 char 矩阵,使用 cell2mat 函数。

    >> [datestr,timestr]=textread('PregnantWomanFileTime.txt','%s%s');
    >> class(datestr)
    
    ans =
    
    cell
    
    >> f=cell2mat(datestr);
    >> class(f)
    
    ans =
    
    char
    
    >> f(1:4,:)
    
    ans =
    
    2015-04-22
    2014-11-21
    2013-12-16
    2013-12-26

    然后对 char 矩阵提取所需字符即可。

    >> f=f(:,1:7);
    >> f(1:4,:)
    
    ans =
    
    2015-04
    2014-11
    2013-12
    2013-12

    3、统计月份的频次

    如果 f 是一维数值矩阵,那只需要使用 hist 函数就可以了,但因为这里要统计的是日期字符的频次,hist 就不能用了。

    >> hist(f)
    ??? Error using ==> hist
    Input arguments must be numeric.

    还好 Matlab 提供了另一个类似的频数统计函数 tabulate。

    >> f=tabulate(f);
    >> f
    
    f = 
    
        '2015-04'    [1386]    [6.4706]
        '2014-11'    [ 582]    [2.7171]
        '2013-12'    [  84]    [0.3922]
        '2014-01'    [ 766]    [3.5761]
        '2014-09'    [ 587]    [2.7404]
        '2014-02'    [ 616]    [2.8758]
    ……

    使用 sortrows 函数对根据第一列元素对 f 排序。

    >> f=sortrows(f,1);
    >> f
    
    f = 
    
        '2013-12'    [  84]    [0.3922]
        '2014-01'    [ 766]    [3.5761]
        '2014-02'    [ 616]    [2.8758]
        '2014-03'    [1000]    [4.6685]
        '2014-04'    [ 977]    [4.5612]
        '2014-05'    [ 948]    [4.4258]
        '2014-06'    [ 961]    [4.4865]

    4、绘直方图

    绘图就很简单了,bar 函数就可以。首先我们要 f 转成一维矩阵,因为上面 tabulate 返回的是元胞数组。转成行矩阵、列矩阵均可。然后再调用 bar 绘制 f 第二列的数据图,并使用 f 的第一列设置 x 轴标签,再加上 Title。

    >> bar(cell2mat(f(:,2)),1);
    >> set(gca,'XTickLabel',f(:,1),'XTick',[1:length(f(:,1))]);
    >> title( '孕妇建档时间统计' );%下面的代码是为了旋转横坐标轴标签

    本来到这里绘图可以算完成了,但是,看看 x 轴标签拥挤得,完全没法看,所以需要对 x 轴标签的显示进行下调整。需要旋转 x 轴标签了,才发现强大的 Matlab 实现这个功能竟然这么麻烦,需要通过下一小节来说明。

    5、旋转 x 轴标签

     下面是旋转 x 轴标签的代码,当时找这段代码比较烦恼,因为实在不能相信 Matlab 旋转个标签都这么麻烦。其实这段代码也很简单,就是获取 x 轴标签句柄,并设置到相应的位置,然后将原有标签隐去。xt 和 yt 不重要,只是用了下 xt 的长度和 yt(1) 的 0 值。xtb 是标签内容,xtextp 和 ytextp 是标签位置坐标。text 函数可查阅相关手册了解。

    xtb = get(gca,'XTickLabel');% 获取横坐标轴标签句柄
    xt = get(gca,'XTick');% 获取横坐标轴刻度句柄
    yt = get(gca,'YTick'); % 获取纵坐标轴刻度句柄
    xtextp=xt;%每个标签放置位置的横坐标
    ytextp=yt(1)*ones(1,length(xt));
    text(xtextp,ytextp,xtb,'HorizontalAlignment','right','VerticalAlignment','top','rotation',45,'fontsize',10); 
    set(gca,'xticklabel','');% 将原有的标签隐去

    最终图形显示如第一张图所示。

    二、孕妇建档某一月频次统计

    上面的例子选取的第一列的所有数据,只是提取了每个数据的年月。现在要统计某一个月份的数据,就要对数据进行过滤。这里我们使用正则表达式进行过滤,代码如下。绘图代码跟上面一样。

    %孕妇建档时间一个月内
    [datestr,timestr]=textread('PregnantWomanFileTime.txt','%s%s');
    k=regexp(datestr,'^2015-07.*$', 'match');
    ix=~cellfun('isempty',k);
    index=find(ix~=0);
    f=datestr(index);
    f=tabulate(f);
    f=sortrows(f,1);
    bar(cell2mat(f(:,2)),1);
    set(gca,'XTickLabel',f(:,1),'XTick',[1:length(f(:,1))]);
    title( '孕妇建档时间一个月内' );%下面的代码是为了旋转横坐标轴标签
    xtb = get(gca,'XTickLabel');% 获取横坐标轴标签句柄
    xt = get(gca,'XTick');% 获取横坐标轴刻度句柄
    yt = get(gca,'YTick'); % 获取纵坐标轴刻度句柄
    xtextp=xt;%每个标签放置位置的横坐标
    ytextp=yt(1)*ones(1,length(xt));
    text(xtextp,ytextp,xtb,'HorizontalAlignment','right','VerticalAlignment','top','rotation',45,'fontsize',10); 
    set(gca,'xticklabel','');% 将原有的标签隐去

    生成的图形如下:

    下面对上面使用正则表达式的代码进行解析。

    k=regexp(datestr,'^2015-07.*$', 'match');

    regexp 查找每个元素中匹配字符的位置并返回,k 的值截取如下:

        {1x1 cell}
        {1x1 cell}
        {1x1 cell}
        {1x1 cell}
        {1x1 cell}
                {}
                {}
                {}
                {}

    代码 ix=~cellfun('isempty',k)  是判断元胞数组中的元素是否为空,ix 的值截取如下:

         1
         1
         1
         0
         0
         0

    index=find(ix~=0) 是找到上面元胞数组中不为空的元素坐标,这是根据正则表达式提取数据很重要的一步,很有技巧。index 的值截取如下:

    >> index=find(ix~=0);
    >> index
    
    index =
    
           11269
           11287
           11597
           11672
           11695

    下面就需要根据上面的 index 提取相应的数据了。会者不难,难者不会。

    >> f=datestr(index);
    >> f
    
    f = 
    
        '2015-07-07'
        '2015-07-09'
        '2015-07-15'
        '2015-07-06'

    绘图功能跟上面一样。

    三、孕妇建档时间一天内统计

    对一天内的孕妇建档频次进行统计。

    [datestr,timestr]=textread('PregnantWomanFileTime.txt','%s%s');
    f=regexprep(timestr,':d+:d+$','');
    f=str2num(char(f));%这个代码可是几经坎坷
    hist(f);
    title( '孕妇建档时间一天内频次统计' );

    生成图形如下:

    代码解析如下:

    f=regexprep(timestr,':d+:d+$','') 是把时间列的分和秒都去掉,返回的就是小时。原理是用 regexprep 把时间的分秒都替换成空,剩下的就是小时。

    >> f=regexprep(timestr,':d+:d+$','');
    >> f(1:4)
    
    ans = 
    
        '10'
        '17'
        '17'
        '16'

    下面就是要想办法把 f 中表示小时的字符转换成数值类型,因为如果跟上面一样用 tabulate 进行统计,并使用 sortrows 排序时,出发生把 8 排在 12 后面的情况,而这里正好又都是数值类型,我们何不直接转换成数值,然后用 hist 呢?

    >> [datestr,timestr]=textread('PregnantWomanFileTime.txt','%s%s');
    f=regexprep(timestr,':d+:d+$','');
    >> f(1:4)
    
    ans = 
    
        '10'
        '17'
        '17'
        '16'
    
    >> f=str2num(char(f));%这个代码可是几经坎坷
    >> f(1:4)
    
    ans =
    
        10
        17
        17
        16

    其中 f=str2num(char(f)) 这个代码找得我好苦。因为起初我想到用 cell2mat 把元胞数组内的字符转换成数值,结果是这样的。

    >> [datestr,timestr]=textread('PregnantWomanFileTime.txt','%s%s');
    f=regexprep(timestr,':d+:d+$','');
    >> f(1:4)
    
    ans = 
    
        '10'
        '17'
        '17'
        '16'
    
    >> abc=cell2mat(f)
    ??? Error using ==> cat
    CAT arguments dimensions are not consistent.
    
    Error in ==> cell2mat at 95
        m = cat(1,m{:});
    
    >> abc=cell2mat(f')
    
    abc =
    
    10171716161689811……

    无力吐槽……

    后来终于找到正确的转换方式:f=str2num(char(f))

    后面的绘图,直接用 hist,就没什么难度了。

  • 相关阅读:
    P3302 [SDOI2013]森林
    P2542 [AHOI2005] 航线规划
    P5795 [THUSC2015]异或运算
    P3320 [SDOI2015]寻宝游戏
    P1963 [NOI2009] 变换序列
    一月练习日志
    计算几何全家桶
    bzoj1076: [SCOI2008]奖励关(期望dp+状压dp)
    bzoj3450 Easy(概率期望dp)
    Eclipse配置 自动补全功能 快捷键 alt+/
  • 原文地址:https://www.cnblogs.com/NaughtyBaby/p/4859511.html
Copyright © 2011-2022 走看看