Matlab 日期頻次統計

dengxun7056發表於2015-10-07

一、孕婦建檔月份頻次統計

源資料樣本,為某醫院一段時間內的孕婦建檔時間

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,就沒什麼難度了。

轉載於:https://www.cnblogs.com/NaughtyBaby/p/4859511.html

相關文章