1. 程式人生 > 實用技巧 >jdbc連結資料庫

jdbc連結資料庫

資料分析的目的:

以醫院銷售資料為例,目的是瞭解朝陽醫院在2018年裡的銷售情況,通過對朝陽區醫院的藥品銷售資料的分析,瞭解朝陽醫院的患者的月均消費次數,月均消費金額、客單價以及消費趨勢、需求量前幾位的藥品等。

資料分析基本過程包括:獲取資料、資料清洗、構建模型、資料視覺化以及消費趨勢分析。

資料準備

資料是存在Excel中的,可以使用pandas的Excel檔案讀取函式將資料讀取到記憶體中,這裡需要注意的是檔名和Excel中的sheet頁的名字。讀取完資料後可以對資料進行預覽和檢視一些基本資訊。

匯入原始資料

import numpy as np
from pandas import Series, DataFrame
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
from pylab import mpl
'''
=====================匯入資料==========================
'''
file_name = '(偽造)醫院資料集.xlsx'
xls = pd.ExcelFile(file_name)
#   使用parse()可以根據傳入的sheet名稱來提取對應的表格資訊
dataDF = xls.parse('Sheet1', dtype='object')
# #   列印輸出前五行資料
# print(dataDF.head())
#  使用sheet_names來檢視當前表格中包含的所有sheet名稱(按順序)
print(xls.sheet_names[0])

檢視資料基本資訊:

'''
=========================檢視資料基本資訊=========================
'''
# 檢視資料幾行幾列、索引、列表頭內容、資料統計數目
print(dataDF.shape)
print(dataDF.index)
print(dataDF.columns)
print(dataDF.count())

資料清洗

(1)選擇子集


在我們獲取到的資料中,可能資料量非常龐大,並不是每一列都有價值都需要分析,這時候就需要從整個資料中選取合適的子集進行分析,這樣能從資料中獲取最大價值。在本次案例中不需要選取子集,暫時可以忽略這一步。

(2)列重新命名

在資料分析過程中,有些列名和資料容易混淆或產生歧義,不利於資料分析,這時候需要把列名換成容易理解的名稱,可以採用rename函式實現:

'''
==========================================================
=====                                              =======
=====                     資料清洗                  =======
=====                                              =======
==========================================================
此處複習哈理論知識:資料清洗包括過程包括:選擇子集、列名重新命名、缺失資料處理、資料型別轉換、資料排序及異常值處理
'''
'''
---------1.選擇子集:---------
在我們獲取到的資料中,可能資料量非常龐大,並不是每一列都有價值都需要分析,
這時候就需要從整個資料中選取合適的子集進行分析,這樣能從資料中獲取最大價值。在本次案例中不需要選取子集,
暫時可以忽略這一步。(也是我現在分析不出來,學習的例項也沒教…………)
'''

'''
---------2.列重新命名---------
在資料分析過程中,有些列名和資料容易混淆或產生歧義,不利於資料分析,這時候需要把列名換成容易理解的名稱,
可以採用rename函式實現:
'''
dataDF.rename(columns={'購藥時間': '銷售時間'}, inplace=True)
# print(dataDF.head())

(3)缺失值處理

獲取的資料中很有可能存在缺失值,通過檢視基本資訊可以推測“購藥時間”和“社保卡號”這兩列存在缺失值,如果不處理這些缺失值會干擾後面的資料分析結果。

缺失資料常用的處理方式為刪除含有缺失資料的記錄或者利用演算法去補全缺失資料。

在本次案例中為求方便,直接使用dropna函式刪除缺失資料,具體如下:

#缺失值處理
print('刪除缺失值前:', dataDF.shape)

# 使用info檢視資料資訊,
print(dataDF.info())
#刪除缺失值
dataDF = dataDF.dropna(subset=['銷售時間','社保卡號'], how='any')
print('\n刪除缺失值後',dataDF.shape)
print(dataDF.info())

(4)資料型別轉換

在匯入資料時為了防止匯入不進來,會強制所有資料都是object型別,但實際資料分析過程中“銷售數量”,“應收金額”,“實收金額”,這些列需要浮點型(float)資料,“銷售時間”需要改成時間格式,因此需要對資料型別進行轉換。

可以使用astype()函式轉為浮點型資料:

#資料型別轉換
dataDF['銷售數量'] = dataDF['銷售數量'].astype('float')
dataDF['應收金額'] = dataDF['應收金額'].astype('float')
dataDF['實收金額'] = dataDF['實收金額'].astype('float')
print(dataDF.dtypes)

在“銷售時間”這一列資料中存在星期這樣的資料,但在資料分析過程中不需要用到,因此要把銷售時間列中日期和星期使用split函式進行分割,分割後的時間,返回的是Series資料型別:

'''
定義函式:分割銷售日期,提取銷售日期
輸入:timeColSer 銷售時間這一列,Series資料型別,例‘2018-01-01 星期五’
輸出:分割後的時間,返回Series資料型別,例‘2018-01-01’
'''
def splitSaletime(timeColSer):
    timeList=[]
    
    for value in timeColSer:
        dateStr=value.split(' ')[0] #用空格進行分割
        timeList.append(dateStr)
​
    timeSer=pd.Series(timeList)    #將列表轉行為一維資料Series型別
    return timeSer

#獲取“銷售時間”這一列
timeSer = dataDF.loc[:,'銷售時間']
​
#對字串進行分割,提取銷售日期
dateSer = splitSaletime(timeSer)
​
#修改銷售時間這一列的值
dataDF.loc[:,'銷售時間'] = dateSer
print(​dataDF.head())

'''
資料型別轉換:字串轉換為日期
​
把切割後的日期轉為時間格式,方便後面的資料統計:
'''
#errors='coerce' 如果原始資料不符合日期的格式,轉換後的值為空值NaT
dataDF.loc[:,'銷售時間']=pd.to_datetime(dataDF.loc[:,'銷售時間'],format='%Y-%m-%d', errors='coerce')
​
print(dataDF.dtypes)

'''
再來看看現在有哪些空值
'''
print(dataDF.isnull().sum())

'''
轉換日期過程中不符合日期格式的數值會被轉換為空值
刪除含有NaT的空行
'''
dataDF = dataDF.dropna(subset=['銷售時間', '社保卡號'], how='any')
datasDF = dataDF.reset_index(drop=True)
dataDF.info()

(5)資料排序

此時時間是沒有按順序排列的,所以還是需要排序一下,排序之後索引會被打亂,所以也需要重置一下索引。

其中by:表示按哪一列進行排序,ascending=True表示升序排列,ascending=False表示降序排列

'''
---------5.資料排序--------
此時時間是沒有按順序排列的,所以還是需要排序一下,排序之後索引會被打亂,所以也需要重置一下索引。預設為升序排序
'''
dataDF = dataDF.sort_values(by='銷售時間', ascending=True)
dataDF = dataDF.reset_index(drop=True)
print(dataDF.head())

(6)異常值處理

先檢視資料的描述統計資訊

'''
--------6異常值處理--------
'''
# 先檢視資料的描述統計資訊
print(dataDF.describe())

可以看到,“銷售數量”、“應收金額”、“實收金額”這三列資料的最小值出現了負數,
這明顯不符合常理,資料中存在異常值的干擾,因此要對資料進一步處理,以排除異常值的影響:

'''
可以看到,“銷售數量”、“應收金額”、“實收金額”這三列資料的最小值出現了負數,
這明顯不符合常理,資料中存在異常值的干擾,因此要對資料進一步處理,以排除異常值的影響:
'''
# 將'銷售數量'這一列小於0的資料排除掉
pop = dataDF.loc[:, '銷售數量'] > 0
dataDF = dataDF.loc[pop, :]
print(dataDF.describe())

資料視覺化

資料清洗完成後,需要利用資料構建模型(就是計算相應的業務指標),並用視覺化的方式呈現結果。

(1)業務指標1:月均消費次數

月均消費次數 = 總消費次數 / 月份數(同一天內,同一個人所有消費算作一次消費)

# 計算總消費次數
# 刪除重複資料
kpil_Df = dataDF.drop_duplicates(subset=['銷售時間', '社保卡號'])
totalI = kpil_Df.shape[0]
print('總消費次數=', totalI)

# 計算月份數
# 按銷售時間升序排序
kpil_Df = kpil_Df.sort_values(by='銷售時間', ascending=True)
# 重新命名行名
kpil_Df = kpil_Df.reset_index(drop=True)
# 獲取時間範圍
startTime = kpil_Df.loc[0, '銷售時間']
endTime = kpil_Df.loc[totalI - 1, '銷售時間']
# 計算月份
# 天數
daysI = (endTime - startTime).days
mounthI = daysI // 30
print('月份數=', mounthI)
# 月平均消費次數
kpil_I = totalI // mounthI
print('業務指標1:月均消費次數=', kpil_I)

(2)業務指標2:月均消費金額

月均消費金額 = 總消費金額 / 月份數

totalMoneyF = dataDF.loc[:, '實收金額'].sum()
mounthMoney = totalMoneyF // mounthI
print('業務指標2:月均消費金額=', mounthMoney)

(3)業務指標3:客單價

客單價 = 總消費金額 / 總消費次數

#客單價
pct = totalMoneyF / totalI
print('業務指標3:客單價=', pct)

(4)消費趨勢

畫圖視覺化分析

1、 分析每天的消費金額

'''
-------------------------------
        畫圖分析:消費趨勢
-------------------------------
'''
mpl.rcParams['font.sans-serif'] = ['SimHei']  # SimHei是黑體的意思
# 在操作之前先複製一份
# mpl.rcParams['font.sans-serif'] = ['Songti'] # SimHei是黑體的意思
# font = FontProperties(fname='/Library/Fonts/Songti.ttc') #設定字型
# 在操作之前先複製一份資料,防止影響清洗後的資料
groupDF = dataDF
# 將'銷售時間'設定為index
groupDF.index = groupDF['銷售時間']
print(groupDF.head())
gb = groupDF.groupby(groupDF.index)
print(gb)
dayDF = gb.sum()
print(dayDF)
# 畫圖
plt.plot(dayDF['實收金額'])
plt.title('按天消費金額')
plt.xlabel('時間')
plt.ylabel('實收金額')
plt.show()

結論:從結果可以看出,每天消費總額差異較大,除了個別天出現比較大筆的消費,大部分人消費情況維持在1000-2000元以內。

2.分析每月的消費金額

接下來,我銷售時間先聚合再按月分組進行分析:

#將銷售時間聚合按月分組
gb = groupDF.groupby(groupDF.index.month)
print(gb)
monthDF = gb.sum()
print(monthDF)
​
plt.plot(monthDF['實收金額'])
plt.title('按月消費金額')
plt.xlabel('時間')
plt.ylabel('實收金額')
plt.show()

結果顯示,7月消費金額最少,這是因為7月份的資料不完整,所以不具參考價值。
1月、4月、5月和6月的月消費金額差異不大.
2月和3月的消費金額迅速降低。

3.分析藥品銷售情況

對“商品名稱”和“銷售數量”這兩列資料進行聚合為Series形式,方便後面統計,並按降序排序:

#聚合統計各種藥品數量
medicine = groupDF[['商品名稱','銷售數量']]
bk = medicine.groupby('商品名稱')[['銷售數量']]
re_medicine = bk.sum()
​
#對銷售藥品數量按將序排序
re_medicine = re_medicine.sort_values(by='銷售數量', ascending=False)
re_medicine.head()

top_medicine = re_medicine.iloc[:10,:]
top_medicine

# 資料視覺化,用條形圖展示前十的藥品
top_medicine.plot(kind = 'bar')
plt.title('銷售前十的藥品')
plt.xlabel('藥品')
plt.ylabel('數量')
plt.show()

結論:對於銷售量排在前幾位的藥品,醫院應該時刻關注,保證藥品不會短缺而影響患者。得到銷售數量最多的前十種藥品的資訊,這些資訊也會有助於加強醫院對藥房的管理。

4.每天的消費金額分佈情況
每天的消費金額分佈情況:一橫軸為時間,縱軸為實收金額畫散點圖。

'''
每天的消費金額分佈情況
每天的消費金額分佈情況:一橫軸為時間,縱軸為實收金額畫散點圖。
'''
plt.scatter(dataDF['銷售時間'], dataDF['實收金額'])
plt.title('每天銷售金額')
plt.xlabel('時間')
plt.ylabel('實收金額')
plt.show()

結論:從散點圖可以看出,每天消費金額在500以下的佔絕大多數