本篇实现一个 pandas 综合数据处理的案例。假设的场景就是计算某期间的物料进出存,涉及 pandas 多个 data frame 的关联、日期类型数据信息的提取、数据分组汇总等,掌握后应该能应付日常很多数据处理场景。这个案例之前我利用 MS Access 和 Power Query 都进行过加工操作,并发过了博文讲解数据处理过程,有兴趣的朋友可以在我之前的博客中查看。本次来看看 利用 pandas 如何进行数据处理。数据存放在 SQL Server Express 数据库中,主要表的结构和表之间的关系如下:
示例数据在 github 上有 Access 版本的数据可供下载,在文章的最后给出连接地址。
对数据库的连接和读取,利用 sqlalchemy + pyodbc。在 Windows 上,使用 odbcad32 命令创建 odbc 连接的数据源:
首先选择驱动程序:
选择默认连接的数据库:
进行了 odbc 配置之后,在 python 中使用 sqlalchemy + pyodbc 通过下面的方法建立与 sql server 数据库的连接 (建立 engine ):
from sqlalchemy import create_engine
engine = create_engine('mssql+pyodbc://username:pwd!@mssql')
这里的 mssql 就是上面 odbc 数据源配置的 DSN (data source name)。username 和 password 按数据库登录密码。
然后使用 sql 语句建立 3 个 data frame:
df_details = pd.read_sql(
'select DocNo, MaterialNo, Qty from dbo.stock_movement_details', engine)
df_headers = pd.read_sql(
'select DocNo, DocDate, MovementType from dbo.stock_movement_headers', engine)
df_mvt_type = pd.read_sql(
'select MovementTypeID, InoutSign from dbo.movement_types', engine)
通过两次 merge 将三个 data frame 组合在一起:
df_merged_headers = df_details.merge(df_headers, on='DocNo')
df = df_merged_headers.merge(
df_mvt_type, left_on='MovementType', right_on='MovementTypeID')
然后添加字段,使用的就是条件列方法。条件列在表达或者条件的时候,需要用 np.where() 的嵌套方式来实现:
df['TxYear'] = df.DocDate.dt.year
df['TxMonth'] = df.DocDate.dt.month
df['ActualQty'] = np.where(
df.InoutSign == "+",
df.Qty,
-1 * df.Qty
)
df['BeginQty'] = np.where(
df.TxYear < year,
df.ActualQty,
(np.where(
(df.TxYear == year) & (df.TxMonth < month),
df.ActualQty,
0
))
)
df['StockIn'] = np.where(
(df.TxYear == year) & (df.TxMonth == month) & (df.InoutSign == "+"),
df.ActualQty,
0
)
df['StockOut'] = np.where(
(df.TxYear == year) & (df.TxMonth == month) & (df.InoutSign == "-"),
df.ActualQty,
0
)
df['EndQty'] = df.BeginQty + df.StockIn + df.StockOut
最后使用分组汇总得到结果:
df_grouped = df[['MaterialNo', 'BeginQty', 'StockIn',
'StockOut', 'EndQty']].groupby('MaterialNo').sum()
xlwings 的基本使用方法,请参考我下面的这篇文章
xlwings : 从此可以 VBA 调用 Python 代码啦
本次使用 Excel 作界面,将查询条件在 Excel 单元格中输入,然后将参数传递给 python,调用 python 代码获取计算结果 (结果的数据类型为 pandas dataframe), 然后用 xlwings 库将数据写入 Excel 工作表。
Excel 筛选条件的界面如下:
点击 Refresh 按钮,调用下面的 VBA 代码:
Public Sub GetStockBalances()
Dim mymodule As String
mymodule = "stockbalances"
Dim txYear As String
Dim txMonth As String
txYear = Sheet3.Range("B1").Value
txMonth = Sheet3.Range("B2").Value
' clear Sheet1 content
Sheet1.Cells.ClearContents
Dim parms As String
parms = "('" & txYear & "','" & txMonth & "')"
RunPython ("import " & mymodule & ";" & mymodule & ".get_stock_balances" & parms)
End Sub
参数 从 VBA 传递给 python,使用 String 类型,所以在每个参数的两边加上单引号 (’)
github : pandas-xlwings-stock-balances