美國嬰兒名字分析-不要再用英語教材裡面的英文名了!!!

美國嬰兒名字分析-不要再用英語教材裡面的英文名了!!!

來自專欄 MATLAB

這篇文章主要是介紹live script和table相關函數的使用, 還不涉及到機器學習.

記者: live script+table給你什麼樣的感覺? 相比比較流行的python數據工具鏈呢?

菡姐: live script + table給我的感覺呢?

感覺比jupyter notebook + pandas好多了!

MATLAB有workspace, jupyter notebook沒有, 就好比汽車沒有碼速表一樣!

spyder也有workspace, 但是它不能顯示所有的數據類型, 而且數據量一大, 容易卡死.

哎呦, 我超喜歡玩MATLAB的!

我之前寫過:

菡姐:MATLAB的數據分析工具鏈?

zhuanlan.zhihu.com圖標菡姐:使用MATLAB數據分析工具鏈進行實戰: 看電影真的是男女有別?

zhuanlan.zhihu.com圖標

現在就用上面提到的數據分析工具鏈進行實戰.

使用的例子是《利用Python進行數據分析》 麥金尼 (Wes McKinney), 唐學韜, 等【摘要 書評 試讀】圖書 裡面第二章的第三個例子.

(沒看過這本書的讀者不需要買這本書, 除非你想用python進行數據分析)

之所以使用這個例子, 是因為:

1 我對這個例子比較熟悉, 之前學pandas時, 好好研究過這個例子.

2 網上能夠下載到數據.

3 可以做對照, 確保我用MATLAB做出的結果與用pandas做出的結果是一致的, 防止出錯.

這個例子所需要的數據可以在這下載:

wesm/pydata-book?

github.com圖標

OK, 正式開始了.

文章比較長, 我先說一下大概的內容吧:

1 分析了一下英文教材裡面的常見名的歷史流行度, 發現這些名字以前很流行, 現在已經冷門了.

2 名字多樣性逐漸提高了, 而且女孩的多樣性明顯高於男孩的.

3 名字的尾字母的流行度也在發生變化.

4 發現了一組"變性"的名字!!!

先給live script的截圖, 方便讀者直接看到運行結果

再給轉化為普通script的程序, 方便讀者在自己電腦上運行.

數據下載完後, 可以直接運行了, 使用R2018a以上的版本(groupsummary是R2018a的新函數, 如果改成findgroup+splitapply的話, 更老一些的版本應該也能運行).

%% 美國嬰兒名字分析-不要再用英語教材裡面的英文名了!!!%% 合併數據(1880年至2010年)% 一個文件只存一年的嬰兒名字的統計數據.% % 如圖所示:% % % % 每個文件裡面的格式是這樣的:% % % % 第一列是嬰兒的名字, 第二列是嬰兒的性別, 第三列是那一年該性別, 起該名字的嬰兒的數量. %%years_set = 1880:2010;filename = sprintf(ch02\names\yob%d.txt, years_set(1));NamesData = readtable(filename);NamesData.Properties.VariableNames = {name, sex, births};NamesData.year = years_set(1)*ones(height(NamesData), 1);for ii = 2:length(years_set) filename = sprintf(ch02\names\yob%d.txt, years_set(ii)); piece = readtable(filename); piece.Properties.VariableNames = {name, sex, births}; piece.year = years_set(ii)*ones(height(piece), 1); NamesData = [NamesData;piece];endNamesData.sex = categorical(NamesData.sex);summary(NamesData);%% % 發現了一些有趣的點: % % 女性的名字多樣性高於男性(100萬:69萬), 注意這裡面名字沒有根據年份去重, 但不影響結論.head(NamesData)tail(NamesData)%% % 查看了一下合併數據的頭部與尾部, 大致確認全部都合併了進去.%% 各個年份的出生人數(按照性別分組)%%total_births = groupsummary(NamesData, {year, sex}, sum, births)girl_births = total_births.sum_births(total_births.sex == F);boy_births = total_births.sum_births(total_births.sex == M);figure;plot(years_set, girl_births);hold on;plot(years_set, boy_births);legend(女孩, 男孩, Location, best)xlabel(年份);ylabel(人數);%% % 可以看出, 總體趨勢上, 美國出生人數是逐年增加的.% % 題外話, 可以看出, 男女比例也在發生巨大的變化, 但這不是本文的研究對象.%% 計算佔比% 上一節分析出, 總體趨勢上, 美國出生人數是逐年增加的, 因此, 簡單的根據人數來判斷是否熱門是不合理的, 佔比這個指標更合理一些.%%G = findgroups(NamesData.year, NamesData.sex);prop_cell = splitapply(@(x) {x./sum(x)}, NamesData.births, G);prop = zeros(0, 1);for ii = 1:length(prop_cell) prop = [prop;prop_cell{ii}];endNamesData.prop = prop;head(NamesData)%% % 添加了佔比這個變數, 表示: 該性別該年份該名字的人數/(該性別該年份的總人數)%% 過濾掉冷門名字%%length(unique(NamesData.name))%% % 1880年到2010年, 總共出現過88496個名字!% % 實在是太多了.% % 為了方便計算, 過濾掉冷門名字, 保留熱門名字.% % 熱門名字的具體定義為: 該年份, 該性別人數排名前1000名的名字.% % (如果該年份該性別的名字種類小於1000個, 那麼全體都是熱門名字)idx_hot = zeros(0, 1);for ii = 1:length(unique(G)) idx = find(G == ii); births = NamesData.births(idx); [~, I] = sort(births, descend); idx_hot = [idx_hot;idx(I(1:min(1000, length(I))))];endHotNamesData = NamesData(idx_hot, :);height(HotNamesData)length(unique(G))*1000%% % 最後行數略小於理論上限, 說明確實存在特殊情況(如果該年份該性別的名字種類小於1000個, 那麼全體都是熱門名字)head(HotNamesData)tail(HotNamesData)%% 來看看那些過時的名字(比如經常出現在英語教材裡面的名字, 男生: Bill, Bob, John, Tom, 女生: Ann, Mary, Jane, Rose)%%births_year_name = groupsummary(HotNamesData, {year, name}, sum, births);births_year_name.GroupCount = []; % 必須加上這句, 之前debug了不少時間:(births_year_name = unstack(births_year_name, sum_births, name);figure;plot(births_year_name.year, births_year_name.Bill);figure;plot(births_year_name.year, births_year_name.Bob);figure;plot(births_year_name.year, births_year_name.John);figure;plot(births_year_name.year, births_year_name.Tom);figure;plot(births_year_name.year, births_year_name.Ann);figure;plot(births_year_name.year, births_year_name.Mary);figure;plot(births_year_name.year, births_year_name.Jane);figure;plot(births_year_name.year, births_year_name.Rose);%% % 可以看出, 很多經常出現在我們英語教材裡面的英文名已經過時了% % 所以, 給自己起英文名的時候, 盡量規避這些名字, 要不然美國人想: 這年輕人怎麼起了個爺爺奶奶級的名字?%% 名字多樣性分析%%total_prop = groupsummary(HotNamesData, {year, sex}, sum, prop);total_prop_girl = total_prop(total_prop.sex == F, {year, sum_prop});total_prop_boy = total_prop(total_prop.sex == M, {year, sum_prop});figure;plot(total_prop_girl.year, total_prop_girl.sum_prop);hold on;plot(total_prop_boy.year, total_prop_boy.sum_prop);legend(女孩, 男孩, Location, best);xlabel(年份);title(前1000名佔比總和)%% % 可以看到1880年時, 前1000名已經能全覆蓋了, 而到了2010年, 前1000名只能覆蓋73%(女生), 84%(男生).% % 說明名字的多樣性在增加, 女生比男生更多樣.G = findgroups(HotNamesData.year, HotNamesData.sex);diversity = splitapply(@(x) find(cumsum(sort(x, descend)) > 0.5, 1), HotNamesData.prop, G);diversity_girl = diversity(1:2:end);diversity_boy = diversity(2:2:end);figure;plot(unique(HotNamesData.year), diversity_girl);hold on;plot(unique(HotNamesData.year), diversity_boy);legend(女孩, 男孩, Location, best);xlabel(年份);title(前多少個名字佔比50%?)%% % 這張圖可以得到相同的結論: 名字的多樣性在增加, 女生比男生更多樣.%% 尾字母的演化%%NamesData.lastletter = cellfun(@(x) x(end), NamesData.name);births_stats = groupsummary(NamesData, {lastletter, sex, year}, sum, births);births_stats = births_stats(ismember(births_stats.year, [1910, 1960, 2010]), :);births_stats = removevars(births_stats, GroupCount);births_stats = unstack(births_stats, sum_births, sex);births_stats_girl = births_stats(:, [1, 2, 3]);births_stats_boy = births_stats(:, [1, 2, 4]);births_stats_girl = unstack(births_stats_girl, F, year);births_stats_boy = unstack(births_stats_boy, M, year);letters = births_stats_girl.lastletter;letters = categorical(cellstr(letters));births_stats_girl = births_stats_girl{:, 2:end};births_stats_boy = births_stats_boy{:, 2:end};births_stats_girl(isnan(births_stats_girl)) = 0;births_stats_boy(isnan(births_stats_boy)) = 0;size(births_stats_girl)size(births_stats_boy)%% % 26行3列, 說明整理對了, 26個字母, 3個年份的數據figure;bar(letters, bsxfun(@rdivide, births_stats_girl, sum(births_stats_girl)));legend(1910, 1960, 2010, Location, best);xlabel(名字的最後一個字母);ylabel(佔比);title(女孩);figure;bar(letters, bsxfun(@rdivide, births_stats_boy, sum(births_stats_boy)));legend(1910, 1960, 2010, Location, best);xlabel(名字的最後一個字母);ylabel(佔比);title(男孩);%% % 可以發現:% % 女孩名字的最後一個字母, a越來越多了, e越來越少了.% % 男孩名字的最後一個字母, n越來越多了.%% "變性"的名字(L|esl開頭的名字)|% L|esl開頭的名字有: Leslie, Lesley, Leslee, Lesli, Lesly|)....% % 這些名字逐漸女性化了.%%names = string(HotNamesData.name);idx_Lesl = startsWith(names, Lesl);HotNamesData_Lesl = HotNamesData(idx_Lesl, :);groupsummary(HotNamesData_Lesl, name, sum, births)%% % 其中叫"Leslie"的人最多.Lesl_year_sex = groupsummary(HotNamesData_Lesl, {year, sex}, sum, births);Lesl_year_sex = removevars(Lesl_year_sex, GroupCount);Lesl_year_sex = unstack(Lesl_year_sex, sum_births, sex);Lesl_year_sex.total = Lesl_year_sex.F + Lesl_year_sex.M;Lesl_year_sex.F_ratio = Lesl_year_sex.F./Lesl_year_sex.total;Lesl_year_sex.M_ratio = Lesl_year_sex.M./Lesl_year_sex.total;figure;plot(Lesl_year_sex.year, Lesl_year_sex.F_ratio);hold on;plot(Lesl_year_sex.year, Lesl_year_sex.M_ratio);legend(女孩, 男孩, Location, best);xlabel(年份);title(Lesl開頭名字的性別佔比)%% % 可以看到, 之前是男性化的名字, 逐漸變成女性化的名字!!!% %

如果有幫助的話, 讚賞一下吧. 花了一個下午做出來的.

----更新分割線--------------------------------------------------------------------------

有人對top100的名字有興趣, 我將2010年的流行名字進行了提取,並且畫成了詞雲.

女孩名字top100:

男孩名字top100:

代碼如下, 在上面代碼的下面補充上即可:

%% 女孩名字top100, 男孩名字top100HotNamesData_2010 = HotNamesData(HotNamesData.year == 2010, :);HotNamesData_2010_girl = HotNamesData_2010(HotNamesData_2010.sex == F, :);HotNamesData_2010_boy = HotNamesData_2010(HotNamesData_2010.sex == M, :);[~, idx_girl] = sort(HotNamesData_2010_girl.births, descend);top100_2010_girl = HotNamesData_2010_girl(idx_girl(1:100), :);[~, idx_boy] = sort(HotNamesData_2010_boy.births, descend);top100_2010_boy = HotNamesData_2010_boy(idx_boy(1:100), :);figure;wordcloud(top100_2010_girl.name, top100_2010_girl.births);figure;wordcloud(top100_2010_boy.name, top100_2010_boy.births);

推薦閱讀:

【IoT:從零開始的MATLAB學習】 2 偏好設置&幫助文檔
MATLAB Graph Object(3): 展示關係網
圖像處理與特徵提取 —— 從 MATLAB 到 Python(一)圖像、矩陣與數據的讀寫
如何算是精通MATLAB?
%(default) colormap(parula)

TAG:MATLAB | 數據分析 |