我祖父对生成AI的一瞥
在我眼中,我的外祖父Skip一直都是一位农民。可悲的是,我母亲在1988年我出生后的一个月就因白血病去世了。作为家庭中的第一个孙子,Skip和我关系非常亲近。在我还是孩子的时候,我整天都会坐在拖拉机和联合收割机的扶手上,参加每年的小麦收获季节,当我成为十几岁的少年时,我自己也在农场工作了一个暑假。
然而,Skip早年的生活与我所知的农业世界完全不同。在我出现之前,他深入学术界,于1972年在得克萨斯农工大学完成了统计学博士学位的课程。不久后,他在马里兰大学担任教授职位,并于1974年完成了他的论文。他的开创性研究旨在预测和确定工业环境中的安全和材料风险。这项艰巨的任务需要多年的努力。他不得不手动收集各种公司十年的事故报告,手动处理统计数据,然后将这些见解转化为大学计算机系统的打孔卡指令。获得计算机使用时间并不容易,需要提前几周甚至几个月进行预约。一个编码错误可能意味着重新开始,可能会延迟他的研究数月之久。
他在1980年代离开了那种生活,接手了位于得克萨斯州东部的家族农场,并进军创业。但他作为农民时始终将统计推理的应用融入到自己的一切工作中,只是我作为一个孩子并没有意识到。在我孩子的心目中,Skip正在做着他所说的“办公室工作” —— 但实际上,他正在运用信息技术来预测和安排融资以满足运营费用,通过优化肥料中的化学成分来提高产量,制定减少现金流不确定性的策略通过在芝加哥大宗商品交易所上交易期货,所有这些都是通过连接到点阵打印机的购买于Radio Shack的16 KB RAM的TRS 80来实现的。农业可能是一个利润微薄的行业,而Skip的赌注是他可以使用统计学来稍微平衡一下这个领域。
多年来,这个农场没有经受住时间的考验。事实证明,当被迫跳过一代人时,代际农业并不好过,而如今的投入成本比以往更加不可饶恕 —— 规模经济成为唯一能够有利可图竞争的方式 —— 因此,Skip这一代的大多数中小型农民都被收购和整合了 —— 但这是逐渐发生的 —— 一点一点地(至少对我们来说是这样)。
当然,我后来开始欣赏统计学与农业之间的紧密联系。我仍然记得每年来自美国农业部的细致采样作物产量(包括我们的农场)作为他们的国家农业统计服务的一部分。在我看来,这是历史上一个伟大的、未被赞扬的而仍在进行的数据项目 —— 帮助几代农民做出“数据驱动”的决策 —— 在那还不是一个热门词汇之前。但随着我踏入自己的分析和数据科学职业之后的几十年,我对Skip几十年前所做的一切有了更多的欣赏 —— 这是我在二十多岁到三十多岁期间作为美国军官为人类服务和环球旅行之后的第二个行动。我经常通过电话与他重新联系,询问他当时是如何运行回归或模拟以及他是如何控制随机抽样“旧的那些日子”。然后偶尔告诉他他们现在如何进行并描述给他听概念,例如机器学习、深度学习、强化学习 —— 这对他来说有些科幻,但他喜欢听 —— 即使对他来说,在晚年这个时候现实还有些遥不可及。

进入实验。
我在周末决定行动而不是只说。我希望Skip亲自体验这项新技术,而不仅仅听我讲述它。如果我们能够制定一个在不到40分钟内启动一个假设的新农场的商业计划,那该多好啊?我可以使用启用了高级数据分析的ChatGPT 4在他的iPhone上共享屏幕,我们将一起合作建立它。
我们简要讨论了我们的假设:
- 我们有1000英亩的土地在德克萨斯州东部耕种。
- 我们有100万美元的初始资金用于购买设备。
- 我们需要在第一年运营费用上从银行获得信用额度来开始。
- 我们有兴趣种植小麦和大豆(Skip在过去实际种植的作物)。
我们的开始很简单:
Prompt 1:“为在德克萨斯州创建一个新农场种植小麦和大豆写一个商业计划大纲。”
Skip立即对长篇回答印象深刻。但是等等,我们才刚刚开始…
Prompt 2:“给我一个开始所需的设备清单”Prompt 3:“将其放入表格中,并根据紧急程度从最紧急到最不紧急进行数字优先排序”Prompt 4:“现在创建一个用于预算分配的新列,假设我将使用租赁和购买的组合,创建一个额外的列来推荐租赁与购买,假设我有100万美元的初始资金。”
(经过4分钟)
结果:

Prompt 5:“为变动成本(种子、肥料、劳动力等)保留多少金额,假设有1000英亩。创建一个新表格。”
结果:

到此为止,我感觉Skip好像又目睹了阿波罗11号的壮丽场景。他几乎不能掩饰他的兴奋。但我们还没有结束…
Prompt 6:“给我写个蒙特卡洛模拟,我可以调整输入假设并测试对预算的影响。”
结果:
import numpy as npimport matplotlib.pyplot as plt# 定义模拟次数n_simulations = 10000# 假设的 [平均值,标准差]wheat_seed_cost = [20, 2] # 单位面积成本soybean_seed_cost = [50, 5]fertilizer_wheat_cost = [50, 5]fertilizer_soybean_cost = [40, 4]labor_cost = [25, 3]pesticide_cost = [30, 3]fuel_maintenance_cost = [15, 2]miscellaneous_cost = [10, 1]def simulate_farm_costs(): wheat_seed = np.random.normal(wheat_seed_cost[0], wheat_seed_cost[1]) soybean_seed = np.random.normal(soybean_seed_cost[0], soybean_seed_cost[1]) fertilizer_wheat = np.random.normal(fertilizer_wheat_cost[0], fertilizer_wheat_cost[1]) fertilizer_soybean = np.random.normal(fertilizer_soybean_cost[0], fertilizer_soybean_cost[1]) labor = np.random.normal(labor_cost[0], labor_cost[1]) pesticide = np.random.normal(pesticide_cost[0], pesticide_cost[1]) fuel_maintenance = np.random.normal(fuel_maintenance_cost[0], fuel_maintenance_cost[1]) miscellaneous = np.random.normal(miscellaneous_cost[0], miscellaneous_cost[1]) total_cost = (wheat_seed + soybean_seed + fertilizer_wheat + fertilizer_soybean + labor + pesticide + fuel_maintenance + miscellaneous) * 1000 # 单位面积为1000英亩 return total_costresults = [simulate_farm_costs() for _ in range(n_simulations)]# 可视化plt.hist(results, bins=50, edgecolor='black', alpha=0.7)plt.title('总农场成本分布')plt.xlabel('总成本')plt.ylabel('频率')plt.grid(True, alpha=0.2)plt.show()
现在是真相时刻——代码能否运行?我们跳到Jupyter笔记本来运行代码。第一次尝试就成功了:

到这个时候,我们只用了10到15分钟。还有些时间可用…我们能让它变得交互吗?
我们需要创建一个参数列表,使用户能够通过滑块动态调整假设。再次向ChatGPT寻求一些建议,了解这些参数基于我们之前构建的蒙特卡洛模拟:

一旦我们构建好参数列表,我们就可以在Power BI中创建一个与16个切片器可视化关联的“测量”表,允许用户手动选择输入并动态更新蒙特卡洛模拟。为此,我们在Power BI中创建一个“Python可视化”,将所有的测量值拖入其中,然后按照以下方式更新代码:
# 用于创建数据帧和删除重复行的以下代码总是被执行,作为脚本的前言:# dataset = pandas.DataFrame(fertilizer_soybean_cost_avg Value, fertilizer_soybean_cost_std Value, fertilizer_wheat_cost_avg Value, fertilizer_wheat_cost_std Value, fuel_maintenance_cost_avg Value, fuel_maintenance_cost_std Value, labor_cost_avg Value, labor_cost_std Value, miscellaneous_cost_avg Value, miscellaneous_cost_std Value, pesticide_cost_avg Value, pesticide_cost_std Value, soybean_seed_cost_avg Value, wheat_seed_cost_avg Value, wheat_seed_cost_std Value)# dataset = dataset.drop_duplicates()# 在下面粘贴或输入你的脚本代码:import numpy as npimport pandas as pdimport matplotlib.pyplot as plt# 假设数据从Power BI传递为'dataset'df = dataset# 从数据集中提取数值wheat_seed_cost_avg = df['wheat_seed_cost_avg Value'].iloc[0]wheat_seed_cost_std = df['wheat_seed_cost_std Value'].iloc[0]soybean_seed_cost_avg = df['soybean_seed_cost_avg Value'].iloc[0]soybean_seed_cost_std = df['soybean_seed_cost_std Value'].iloc[0]fertilizer_wheat_cost_avg = df['fertilizer_wheat_cost_avg Value'].iloc[0]fertilizer_wheat_cost_std = df['fertilizer_wheat_cost_std Value'].iloc[0]fertilizer_soybean_cost_avg = df['fertilizer_soybean_cost_avg Value'].iloc[0]fertilizer_soybean_cost_std = df['fertilizer_soybean_cost_std Value'].iloc[0]labor_cost_avg = df['labor_cost_avg Value'].iloc[0]labor_cost_std = df['labor_cost_std Value'].iloc[0]pesticide_cost_avg = df['pesticide_cost_avg Value'].iloc[0]pesticide_cost_std = df['pesticide_cost_std Value'].iloc[0]fuel_maintenance_cost_avg = df['fuel_maintenance_cost_avg Value'].iloc[0]fuel_maintenance_cost_std = df['fuel_maintenance_cost_std Value'].iloc[0]miscellaneous_cost_avg = df['miscellaneous_cost_avg Value'].iloc[0]miscellaneous_cost_std = df['miscellaneous_cost_std Value'].iloc[0]# 定义模拟次数n_simulations = 10000# 假设的平均值和标准差wheat_seed_cost = [wheat_seed_cost_avg, wheat_seed_cost_std]soybean_seed_cost = [soybean_seed_cost_avg, soybean_seed_cost_std]fertilizer_wheat_cost = [fertilizer_wheat_cost_avg, fertilizer_wheat_cost_std]fertilizer_soybean_cost = [fertilizer_soybean_cost_avg, fertilizer_soybean_cost_std]labor_cost = [labor_cost_avg, labor_cost_std]pesticide_cost = [pesticide_cost_avg, pesticide_cost_std]fuel_maintenance_cost = [fuel_maintenance_cost_avg, fuel_maintenance_cost_std]miscellaneous_cost = [miscellaneous_cost_avg, miscellaneous_cost_std]def simulate_farm_costs(): wheat_seed = np.random.normal(wheat_seed_cost[0], wheat_seed_cost[1]) soybean_seed = np.random.normal(soybean_seed_cost[0], soybean_seed_cost[1]) fertilizer_wheat = np.random.normal(fertilizer_wheat_cost[0], fertilizer_wheat_cost[1]) fertilizer_soybean = np.random.normal(fertilizer_soybean_cost[0], fertilizer_soybean_cost[1]) labor = np.random.normal(labor_cost[0], labor_cost[1]) pesticide = np.random.normal(pesticide_cost[0], pesticide_cost[1]) fuel_maintenance = np.random.normal(fuel_maintenance_cost[0], fuel_maintenance_cost[1]) miscellaneous = np.random.normal(miscellaneous_cost[0], miscellaneous_cost[1]) total_cost = (wheat_seed + soybean_seed + fertilizer_wheat + fertilizer_soybean + labor + pesticide + fuel_maintenance + miscellaneous) * 1000 # for 1000 acres return total_costresults = [simulate_farm_costs() for _ in range(n_simulations)]# 将结果转换为数据帧df_simulated_results = pd.DataFrame(results, columns=['Total Cost'])# 计算四分位数(IQR)Q1 = df_simulated_results['Total Cost'].quantile(0.25)Q3 = df_simulated_results['Total Cost'].quantile(0.75)# 绘制直方图plt.figure(figsize=(10, 6))n, bins, patches = plt.hist(df_simulated_results['Total Cost'], bins=50, color='blue', edgecolor='black', alpha=0.7)plt.title('模拟中第一年的可变农场成本分布')plt.xlabel('第一年的可变成本')plt.ylabel('频率')plt.grid(True, which='both', linestyle='--', linewidth=0.5)# 阴影部分表示IQRfor i in range(len(bins)): if bins[i] > Q1 and bins[i] < Q3: patches[i].set_facecolor('green')plt.axvline(Q1, color='red', linestyle='dashed', linewidth=1)plt.axvline(Q3, color='red', linestyle='dashed', linewidth=1)plt.tight_layout()plt.savefig('simulated_costs_histogram.png') # 保存图像文件plt.show()
只是为了好玩,我们要求ChatGPT定义四分位数范围(IQR)并用不同的颜色标记它,我们还手动更新了图表标签和x轴。其余的工作只是在Power BI中稍微清理了一下视觉效果,使其更加用户友好。最终结果:

现在我们有一个动态的蒙特卡洛模拟,可以尝试不同的输入成本假设,并预测我们需要投入多少变动运营费用来使我们的农业运作起来。借助ChatGPT 4,我们几乎不需要编写代码,只是稍作调整,在iPhone上通过屏幕共享完成大部分工作,最后在PBI桌面应用上构建最后一部分并通过PBI iPhone应用进行屏幕共享。所有这些工作只花了大约30-40分钟。
我祖父的评价是:“我们用了40分钟完成了在‘当年’他自己需要2年才能完成的工作。”是的,我承认我们还可以做更多——这个“模拟”远非完美。(例如,我们没有区分用于大豆和小麦的作物百分比。)但是,在40分钟内?连我自己都很惊讶。这就是通用人工智能的承诺——使数据科学民主化,鼓励实验,加快开发能力,所有这些都可以在你手掌之间完成。让祖父和孙子有机会通过一些统计数据和利用技术的新颖方式重新联系起来。