【物流業は儲かるのか?】売上高と営業利益率を他業界と比較してみた
物流会社ランキングを見れば物流業界の中での売上高や営業利益のランキングはわかりますが、他の業界と比べて物流業界のレベルが低ければ井の中の蛙です。
そこで他業界と比べた物流業界のレベルを調べてみました。
データソースはInvesting.com
Investing.comでは全業界における上場企業の財務指標が見れますので、ここからデータを取りました。
業界分類ですが、Stock ScreenerでSelect Industryのプルダウンを見ると52業界に分類されていますので、これに従いました。
物流業界はFreight & Logistics Services(物流&運輸)です。
この画面で日本の会社を検索して見ると、全部で3,947社あることがわかります。
しかしながら、Webスクレイピングできたのは3,147社だけでしたので、その他の会社は無視しました。
財務指標を取得
Investpyというライブラリーを使えばPythonでInvesting.comからデータを自動取得できます。
またこのライブラリーの中のinvestpy.get_stock_financial_summaryを使えば、国名と会社コードを指定することによって財務情報のサマリーを取得することができます。
会社コードをcompany_listにリストとして入れておけば、次のようなコードで結果がデータフレームdata_listに書き込まれます。
columns1 = ['Code', 'Total Revenue1', 'Gross Profit1', 'Operating Income1', 'Net Income1', 'Total Revenue2', 'Gross Profit2', 'Operating Income2', 'Net Income2', 'Total Revenue3', 'Gross Profit3', 'Operating Income3', 'Net Income3', 'Total Revenue4', 'Gross Profit4', 'Operating Income4', 'Net Income4']
data_list = pd.DataFrame(columns=columns1)
for i in company_list:
try:
data = investpy.get_stock_financial_summary(stock = str(i) , country = 'japan')
list1=[[str(i), data.iloc[0, 0], data.iloc[0, 1], data.iloc[0, 2], data.iloc[0, 3], data.iloc[1, 0], data.iloc[1, 1], data.iloc[1, 2], data.iloc[1, 3], data.iloc[2, 0], data.iloc[2, 1], data.iloc[2, 2], data.iloc[2, 3], data.iloc[3, 0], data.iloc[3, 1], data.iloc[3, 2], data.iloc[3, 3]]]
columns1 =['Code', 'Total Revenue1', 'Gross Profit1', 'Operating Income1', 'Net Income1', 'Total Revenue2', 'Gross Profit2', 'Operating Income2', 'Net Income2', 'Total Revenue3', 'Gross Profit3', 'Operating Income3', 'Net Income3', 'Total Revenue4', 'Gross Profit4', 'Operating Income4', 'Net Income4']
data2 = pd.DataFrame(data=list1, columns=columns1)
data_list = pd.concat([data_list, data2], axis=0)
except:
print(i)
data_list
このように過去4年間分の売上高/粗利益/営業利益/当期利益が取得できます。
物流業界の売上高や営業利益率は多いのか少ないのか?
このデータフレームに会社名/業種(Industry)/営業利益率(OP Rate1)を追加して、直近年のデータだけを残すと次のようになります。
次に52ある各業界ごとに売上高の平均を求めてみます。
ついでに各業界における会社数も求めておきます。
これはgroupbyを使って次のようにコーディングできます。
データフレーム名はdfにしています。
df_industry = df.groupby('Industry').agg(avg_revenue = ('Total Revenue1', np.average), count = ('Code', np.count_nonzero)).reset_index()
df_industry
しかしこれではランキング順位がわからないので、ランキングを付けて降順にソートします。
df_industry['rank'] = df_industry['avg_revenue'].rank(ascending = False).astype(int)
df_industry.sort_values('avg_revenue', ascending=False).reset_index()
物流業界は52業界中18番目に平均売上高が高いことがわかりました。
同様に営業利益率についても調べてみると17位でした。
マルチレベルABC分類して物流会社の分布を分析
このように平均値で見ると物流業界は悪くない位置にいることがわかりますが、個々の会社についてはわかりません。
例えば物流業界の平均利益率は6.4%ですが10%超えの業界が10もあるため、利益率8%の物流会社があっても全業界で見ると普通の会社なのかもしれませんね。
そこで、全3,147社を売上高と営業利益率でそれぞれランキングし、それを3等分します。
つまり上位、中位、下位を1,049社ずつで区切り、それぞれをA、B、Cランクとします。
すると各社は売上高と営業利益率それぞれのランクによりA-A、A-B、A-C、B-A、B-B、B-C、C-A、C-B、C-Cの9つに分類できます。
そして物流業界にこの9分類がどのように分布しているかを調べます。
つまり、全3,147社をマルチレベルABC分類して、物流会社77社がどのような分布になっているかを見てみましょう。
全3,147社をマルチレベルABC分類する
まずは全3,147社を売上高と営業利益率でランキングします。
これはrankメソッドを使って下記のようにコーディングできます。
df['Rev_rank'] = df['Total Revenue1'].rank(ascending = False).astype(int)
df['OP_rank'] = df['OP Rate1'].rank(ascending = False).astype(int)
df
売上高の順位がRev_rank列に、営業利益率の順位がOP_rank列に書き込まれました。
これからやりたいのはAランク、Bランク、Cランクに均等に分割したいので、順位を0~1の相対値に変換します。
これは引数pctにTrueを指定することによってできます。
df['Rev_rank'] = df['Total Revenue1'].rank(ascending = False, pct = True)
df['OP_rank'] = df['OP Rate1'].rank(ascending = False, pct = True)
df
次にこの相対順位をもとに均等にABC分類します。
これはcutメソッドで実現できます。
bins = [0, 0.33, 0.67, 1]
names = ['A', 'B', 'C']
labels = pd.DataFrame(df['Industry'])
labels['rev_label'] = pd.cut(df['Rev_rank'], bins, labels = names)
labels['op_label'] = pd.cut(df['OP_rank'], bins, labels = names)
labels
これで全3,147社を売上高と営業利益率でマルチレベルABC分類できました。
物流業界内での分布を調べる
では次に物流業界内にそれぞれのランクの会社がどれくらいいるのかを調べてみましょう。
売上高についてはqueryメソッドを使って次のようにコーディングできます。
rev_high = labels.query("Industry == '物流&運輸' & rev_label=='A'").count()
rev_medium = labels.query("Industry == '物流&運輸' & rev_label=='B'").count()
rev_low = labels.query("Industry == '物流&運輸' & rev_label=='C'").count()
rev_high[0], rev_medium[0], rev_low[0]
--------------------
(35, 29, 13)
このようにAランクは35社、Bランクは29社、Cランクは13社であることがわかりました。
同様に営業利益率についても調べてみると次のようになります。
op_high = labels.query("Industry == '物流&運輸' & op_label=='A'").count()
op_medium = labels.query("Industry == '物流&運輸' & op_label=='B'").count()
op_low = labels.query("Industry == '物流&運輸' & op_label=='C'").count()
op_high[0], op_medium[0], op_low[0]
---------------------------
(20, 44, 13)
売上高ではAランクの会社が多いけれども、営業利益率ではBランクの会社が多いことがわかります。
それではこれらを組み合わせたマルチレベルABC分類ではどのような分布になるのでしょうか?
まずはマルチレベルABC分類の列を作っておきましょう。
labels['label'] = labels['rev_label'].astype('string') + '-' + labels['op_label'].astype('string')
labels
これを全業種3,147社分についてプロットすると次のようになります。
fig = sns.countplot(x = 'label', data = labels)
fig.set_xticklabels(fig.get_xticklabels(), rotation = 45)
多少の出っ込み引っ込みはあるものの、概ね均等に分布しています。
次に物流業界の77社についてプロットしてみましょう。
fig = sns.countplot(x = 'label', data = labels[labels['Industry']=='物流&運輸'])
fig.set_xticklabels(fig.get_xticklabels(), rotation = 45)
- 売上Aランクで利益率Bランクの会社が最多
- いずれの売上ランクでも利益率Bランクの会社が最多
という傾向がかなり顕著に現れています。
まとめ
以上から物流業界の特徴は次のようにまとめられるかと思います。
売上規模の大きな会社が多い
物流業界は規模の経済が大きく働く業界です。
欧米ではもっと上位会社による寡占化が進んでいるので、日本でも今後この傾向は顕著になっていくのでしょう。
利益率は普通の会社が多い
規模の経済が大きく働く業界なので、利益率の高い会社は売上の大きな会社に偏っています。
とはいっても売上の大きな会社でも利益率は普通の会社が最多です。
これは売上の大きな会社でも世界的に見るとまだまだ中途半端で、国際物流でコスト競争力を発揮するには更なる規模拡大が求められていることを意味しそうです。
ニッチで高収益は難しい
全業種で見ると、売上高Cランクで利益率Aランクの会社は約380社もあります。
ところが物流業界では僅か3社です。
そのうち1社は玉井商船で、コロナ前は赤字続きでしたがコロナ特需により棚ぼた的に利益が膨らんだ海運会社です。
残り2社は杉村倉庫と丸八倉庫で、物流よりも不動産事業で稼いでいる会社です。
サービス内容で圧倒的な差別化を図るのが難しく、規模の経済による仕入れコスト削減が事業拡大のカギとなる物流業界では、売上高が少ない会社が大きな利益を上げるのは難しいということが言えそうです。