Technically Impossible

Lets look at the weak link in your statement. Anything "Technically Impossible" basically means we haven't figured out how yet.

プログラミング言語人気ランキング2020の主成分分析とクラスタリング

日経XTECH、2019年12月号にて「プログラミング言語人気ランキング」という記事が掲載された。技術者440人に対して、主に次の観点でアンケートし、まとめたものだ。

  1. どのプログラミング言語を学びたいか、学びたくないか
  2. 業務現場では、どの言語をどのような用途で使用しているか

xtech.nikkei.com

ここから収集できるデータを用いて、主成分分析とクラスタリングをしてみた。機械学習で言えば、どちらも「教師なし学習」と呼ばれる機械的な判別、分類方法だ。
特に上記1の観点からの分類では、かなり良好な傾向を見出すことができた。同時に上記2の観点からは、言語の判別、分類よりも使用用途に関する相関が垣間見え、そこから実際の利用用途を察することができる結果が示された。

統計処理にはRを用いた。コードの全文は、投稿末尾に掲載すると同時に、GitHubにもアップロードしている。用いたデータも同様にアップロードしている。

データ収集、整理

日経XTECHのサイトに掲載されているグラフに基づいて、数値情報をExcelにまとめた。結果として出来上がったのが、data.xlsxだ。
投稿末尾にまとめたGitHubへのリンクからダウンロードできる。

スキル磨きと、利用頻度の関係

日経XTECHでは、次の観点から調査していた。

  • スキルを磨きたい、磨かなくてもよいと思う言語
  • 最も使っている、よく使っている言語

まずこれらの観点を主成分分析する。「最も使用している」、「よく使用している」に相関が見いだせるのは当然だろう。とはいえ「最も使用している」と「スキルを磨きたい」のベクトルは直角に近く、相関は少ない。「スキルを磨きたい」のは「よく使用している」言語だ。

ここに言語をマップすると、興味深い傾向が分かる。各象限を大別すると次のようになる。

第1象限 右上 よく使う領域
第2象限 右下 スキルを磨きたい領域
第3象限 左下 使用頻度が低い領域
右寄りなほどスキルを磨きたい
左寄りなほどスキルを磨かなくてよい
第4象限 左上 スキルを磨かなくてもよいと思う領域

これだけでも何かが十分に伝わる読者は多いと思う。次にこれらの言語をクラスタ分析する。2→4→9とクラスタ数を増やしていく毎に、グループごとの特徴が際立ってくるのだ。
次に紹介する各図と見比べると、朧げなストーリーが浮かんできそうな気がする。例えばこんな具合だ。

  • JavaPHPC#などの基幹開発から、モダンなweb開発へ転身したい
  • VB系、COBOL等のレガシーから逃げられない
  • 目新しい言語は、それほど使われていないし、それほど学びたいとも思わない、しかしPythonは例外
  • Pythonを使っている人の利用頻度は高く、それに対する向上心も旺盛
2グループ

スキルを磨かなくてもよい
スキルを磨きたい
4グループ

スキルを磨かなくてもよい
あまり使わない
よく使う
使わざるを得ない
スキルを磨きたい
9グループ

唯我独尊 アセンブラ
C/C++
Python
いわゆる勝ち組
レガシー COBOL
FORTLAN
レガシーから離れたい=学びたくない
基幹開発 C#
Java
VBA
学習意欲に関わらず、使わざるを得ない
足抜け PHP
VB.NET
現在稼働中のシステム
ここから脱却したい
衰退
高ハードル
Lua
Objective-C
Perl
PL/I
Scala
Visual Basic
より今時な言語へ移行したい
新興
ジャンル限定
Go
Kotlin
R
Ruby
Swift
TypeScript
使用頻度は低いが将来に見込みがある
特定用途で利用する
web開発 HTML/CSS
JavaScript
SQL
まさにズバリ
何も言うことなしの組み合わせ

使用用途

日経XTECHは、各言語の使用用途も調査していた。用途は次の9領域だ。

  1. 新規開発
  2. 更改
  3. 運用
  4. 基幹系
  5. 分析
  6. AI
  7. web
  8. 組み込み
  9. モバイル
  10. その他

これらの観点からの主成分分析は、相互に相関の強い結果が示された。これはおそらく複数回答可であることの帰結だと推察している。

ここに回答のある言語だけを対象にマップすると、また興味深い傾向が現れる。同時に朧げなストーリーも浮かんでくる。

  • Javaは基幹系、web系の業務で用いられており、その更改ではC#が用いられていそうだ。
  • 新規開発、組み込み系の相関が強く、そこではC/C++が用いられている。
  • 分析用途にVBAが用いられている。おそらくExcelの影響だろう。

参照

xtech.nikkei.com
github.com

コード全文

🔎R code

library(readxl)
library(NbClust)
library(factoextra)
library(Rmisc)
library(FactoMineR)
library(factoextra)
library(corrplot)

#PCA
myPCA = function(d){
  mypca = PCA(d, scale.unit = TRUE, graph = FALSE)
  print(mypca$eig)
  
  fig20 = fviz_pca_var(mypca, col.var = "cos2", gradient.cols = c("blue", "red"), repel = TRUE)
  fig21 = fviz_pca_var(mypca, col.var = "contrib", gradient.cols = c("blue", "red"), repel = TRUE)
  multiplot(fig20, fig21, cols = 2)
  
  corrplot(t(mypca$var$cos2), addCoef.col = "gray")
  corrplot(t(mypca$var$contrib), is.corr = FALSE, addCoef.col = "gray")
  
  fig22 = fviz_pca_biplot(
    mypca,
    col.var = "darkgreen",
    col.ind = "cos2",
    gradient.cols = c("blue", "red"),
    repel = TRUE)
  
  fig23 = fviz_pca_biplot(
    mypca,
    col.var = "darkgreen",
    col.ind = "cos2",
    gradient.cols = c("blue", "red"),
    repel = TRUE, select.ind = list(cos2 = 0.6))
  
  multiplot(fig22)
  multiplot(fig23)
}

#number of cluster
mynb = function(d){
  myAHCnum = NbClust(d, method = "ward.D", index = "all")
  myNHCnum = NbClust(scale(d), method = "kmeans", index = "alllong")
  
  fig1 = fviz_nbclust(myAHCnum, method = "silhouette")
  fig2 = fviz_nbclust(myNHCnum, method = "gap_stat", nboot = 100)
  multiplot(fig1, fig2)
}

#clustering
mycl = function(c, d){
  myAHC = hcut(d, k = c, stand = TRUE, graph = FALSE)
  myNHC = kmeans(scale(d), c, iter.max = 100, nstart = nrow(d))

  fig10 = fviz_silhouette(myAHC, label = TRUE, rotate = TRUE, print.summary = FALSE)
  multiplot(fig10)
  
  fig11 = fviz_cluster(myNHC, data = d)
  multiplot(fig11)
}

data = read_excel("C:/user/document/Temple University/DTA101/week08/assignment/data.xlsx")

# PCA with skill
pca_data1 = as.matrix(data[,c(2:5)])
rownames(pca_data1) = data$language
myPCA(pca_data1)

# PCA with usage
pca_data2 = as.matrix(data[,c(6:15)])
rownames(pca_data2) = data$language
pca_data2 = pca_data2[c(2:5, 8:10, 12, 14, 16, 18:21, 23:24),]
myPCA(pca_data2)

# clustering
d1 = as.matrix(data[, c(2:5)])
d1 = scale(d1)
rownames(d1) = data$language
mynb(d1)

for (i in c(2, 4, 9)){
  mycl(i, d1)
}