Type something to search...

利用 CrewAI 为自动化 EDA 构建人工智能代理协作框架

引言:数据探索的新纪元

在当今这个数据驱动的世界中,企业不断寻求从庞大的数据集中提取可操作的洞察。传统上,这项任务一直是熟练数据科学家的领域,他们花费大量时间探索和分析数据。但如果我们能够自动化这个过程呢?如果一个由人工智能驱动的系统能够对数据提出有见地的问题,彻底分析数据,并呈现详细报告——所有这些都只需最少的人为干预?这正是我们的项目旨在通过利用CrewAI代理框架来实现的目标。

项目背景

该项目围绕使用 AI 代理自动化探索性数据分析(EDA)过程。主要目标是创建一个系统,可以处理数据集及其元数据,生成有洞察力的问题,然后使用数据分析代理回答这些问题。最终产品是一个全面的 EDA 报告,采用 markdown 格式,准备与利益相关者共享或由数据专业人士进一步完善。

为什么要自动化EDA?

EDA是数据科学中的一个关键步骤,使分析师能够在应用更高级的技术之前理解数据集中的结构、模式和关系。然而,EDA可能会耗时且重复,特别是在处理大型数据集时。自动化这个过程不仅节省时间,还能确保一致性和全面性,使数据科学家能够专注于更复杂的任务。

项目概述

CrewAI框架

该项目建立在CrewAI框架之上,该框架允许创建协作AI代理。在这个上下文中,框架促进了两种关键类型代理的协调:

  1. 商业顾问代理:该代理负责生成关于数据集的深刻问题。它检查元数据并确定数据的哪些方面值得进一步探索。
  2. 数据科学家代理:一旦生成问题,数据科学家代理就会接管。该代理生成Python代码以回答每个问题,执行代码,解释结果,并以markdown格式总结发现。

工作原理

该过程可以分为以下步骤:

  1. 元数据分析和问题生成:业务顾问代理分析数据集的元数据,并生成一系列旨在深入探讨数据的问题。这些问题可能涉及调查特定变量的分布、检查变量之间的相关性或检验假设。
  2. 自动化代码生成和执行:对于每个问题,数据科学家代理生成执行所需分析的必要Python代码。这可能涉及创建可视化、进行统计测试或应用机器学习模型。然后执行代码,并捕获输出,例如图表和统计摘要。
  3. 结果总结:分析结果汇编成一个markdown报告。该报告包括原始问题、使用的Python代码、生成的输出以及发现的总结。

定义代理人

商业顾问代理

商业顾问代理的任务是生成与数据集相关的有意义和相关的问题。这些问题至关重要,因为它们指导后续的分析。代理在YAML配置文件中的定义如下。

business_consultant:
  role: >
    Business Consultant
  goal: >
    Generate insightful business questions based on the data and metadata. 
  backstory: >
    You are an experienced business consultant skilled at asking great questions based on the data and metadata..
  llm: llm_model    
generate_questions_task:
  description: >
    Below is the description of a dataset containng the context and the description of data elements.
    - Based on your understanding of the metadata, generate {how_many} questions which woul give deeper insights into the domain the data represents. 
    - Questions should be about specific variables and based on univariate or bivariate analysis.
    - The insights should be based on some of the basic statistical anlaysis like histogram, correlation analysis, hypothesis tests, bar plots, distribution or outlier analysis etc.

    <metadata>
      {metadata_info}
    </metadata>
  expected_output: >   
    A list of question as specified by schema.
  agent: business_consultant

该配置概述了代理的角色、目标以及用于生成问题的参数。代理利用语言模型(例如,GPT-4\)来解释元数据并制定可以通过统计分析或可视化进行探索的问题。

数据科学家代理

数据科学家代理的角色是回答业务顾问代理生成的问题。它通过编写和执行 Python 代码来实现。该代理也在 YAML 配置文件中定义:

data_scientist:
  role: >
    Data Scientist
  goal: >
    Generate code to answer the question,  execute the code, interpret and summarize the results.
  backstory: >
    You are a skilled data scientist proficient in exploratory data analysis, statistics, machine learning.
  llm: llm_model    
datascience_task:
  description: >
    You are tasked with generating the Python code, executing and summarizing to answer the question given a dataset. 
    You are given the following information:

    - Dataset description: <dataset_description> {metadata_info} </dataset_description>
    - Question: <question> {question_str} </question>

    Steps to Follow:

    1. Must follow the guidelines below strictly to generate the code.
      - The code should use pandas, numpy, matplotlib, seaborn, statsmodel and scikit-learn libraries.
      - Include the above libraries and any other library that may be required.
      - Load the dataset from the dataset_location given below: 
        <dataset_location>
          {datapath_info} 
        </dataset_location>  
      - Assuming the data is already clean (skip data preparation)
      - Use statistical tests and plots to answer the questions.
      - Do not do summary statistics on all the variables.
      - Focus only on the question in hand and use variables that are necessary for the analysis.
      - Must print all intermediate results and final results on the console.
      - The plot must be saved in png format at the below directory. Add plt.savefig() with the location below after the plots is created.  
        <imagepath> 
          {imagepath_dir} 
        </imagepath>
      - Ensure the code is clear, efficient, and well-commented.

    2. The generated code satisfies the following conditions. If answer to any of the following is no, then the code generated in invalid.
      - Is dataset loaded from the <dataset_location> specified above ?
      - Is the code only use relevant variables in the dataframe for analysis that are necessary to answer the question?
      - Is atleast one plot generated?
      - Is the code saving the plot only in the <imagepath> directory mentioned above?
      - Are the results or outputs of printed to the console?

    3. Execute the code using the appropriate tool
    3. Collect all output 
    4. Interpret and summarize the results from statistical tests and plots in outputs       
      
  agent: data_scientist
  expected_output: >
    Summary or conclusion from the results or plots. 
    The output should be in MARKDOWN format and must contain the following sections. It should start with question header as below. 
    ### Question
       - question
    ### Code
      - The code provided in the context as it is, without any changes. Embed the code in fenced code blocks?
    ### Code Output
      Outputs from code execution
    ### Analysis
      Inference and summarization of the code outputs

该代理使用众所周知的 Python 库,如 Pandas、NumPy、Matplotlib 和 Seaborn 来进行分析。该代理生成的代码不仅功能齐全,而且设计清晰、高效,并且有良好的文档,确保分析易于理解和复制。

实现团队

为了使这些代理生动起来,我们实现了两个关键组件:QuestCrewEDACrew

QuestCrew

QuestCrew 负责协调业务顾问代理。它初始化代理,提供必要的元数据,并捕获生成的问题。以下是其工作原理的简要概述:

class QuestionList(BaseModel):
    questions: List[str]


pyrepltool = PythonREPL()

@CrewBase
class QuestCrew():
 """Quest crew"""
 agents_config = 'config/quest/agents.yaml'
 tasks_config = 'config/quest/tasks.yaml'

 @llm
 def llm_model(self):
  return ChatOpenAI(temperature=0.0,  # Set to 0 for deterministic output
                    model="gpt-4o-2024-08-06",  # Using the GPT-4 Turbo model
                    max_tokens=8000) 
 
 @agent
 def business_consultant(self) -> Agent:
  return Agent(
   config=self.agents_config['business_consultant'],
   max_rpm=None,
   verbose=True
  )

 @task
 def generate_questions_task(self) -> Task:
  return Task(
   config=self.tasks_config['generate_questions_task'],
   output_pydantic = QuestionList
  )

 @crew
 def crew(self) -> Crew:
  """创建 Llmeda 队伍"""
  question_crew = Crew(
   agents=self.agents,
   tasks=self.tasks, # Automatically created by the @task decorator
   process=Process.sequential,
   verbose=True,
   output_log_file = "qgen.log"
   # process=Process.hierarchical, # In case you wanna use that instead https://docs.crewai.com/how-to/Hierarchical/
  )
  
  return question_crew

EDACrew

EDACrew 处理数据科学家代理,它执行实际的数据分析。在接收到来自 QuestCrew 的问题后,它生成并执行 Python 代码来回答每个问题,然后将结果编译成 markdown 报告。

@CrewBase
class EDACrew():
 """EDA crew"""
 agents_config = 'config/eda/agents.yaml'
 tasks_config = 'config/eda/tasks.yaml'

 @llm
 def llm_model(self):
  return ChatOpenAI(temperature=0.0,  # Set to 0 for deterministic output
                    model="gpt-4o-2024-08-06",  # Using the GPT-4 Turbo model
                    max_tokens=8000) 
 
  #return ChatAnthropic(temperature=0.2, model='claude-3-5-sonnet-20240620')

  # return ChatGoogleGenerativeAI(
  #   model="gemini-1.5-flash",
  #   temperature=0,
  #   max_tokens=4096,
  #   max_retries=2)
 
  return ChatGroq(
   model="llama3.1-70b-versatile",
   temperature=0.0,
   max_retries=2,
  ) 

 @agent
 def data_scientist(self) -> Agent:
  return Agent(
   config=self.agents_config['data_scientist'],
   verbose=True
  )
 
 @task
 def datascience_task(self) -> Task:
  return Task(
   config=self.tasks_config['datascience_task'],
   tools=[pyrepl_tool]
  )
 
 @crew
 def crew(self) -> Crew:
  """Creates the Llmeda crew"""
  eda_crew = Crew(
   agents=self.agents,
   tasks=self.tasks, # Automatically created by the @task decorator
   process=Process.sequential,
   verbose=True,
   output_log_file = "eda.log"
   # process=Process.hierarchical, # In case you wanna use that instead https://docs.crewai.com/how-to/Hierarchical/
  )
  
  return eda_crew

主要执行流程

主脚本协调整个过程。它首先读取数据集元数据并初始化代理操作。首先运行 QuestCrew 以生成问题,然后运行 EDACrew 进行分析。最后,结果被汇总到一个 markdown 报告中。

def read_file(file_path):
    with open(file_path, 'r') as file:
        content = file.read()
    return content

def generate_markdown_for_images(directory):
    # Get list of PNG files in the directory
    images = [img for img in os.listdir(directory) if img.endswith('.png')]

    # Start the markdown section
    markdown_content = "### Plots \n\n"

    # Loop through each image and generate markdown
    for img in images:
        image_path = os.path.join(directory, img)
        markdown_content += f"![{img}]({image_path})\n\n"

    return markdown_content

def run():
    """
    Run the crew.
    """

    print(f"当前工作目录: {os.getcwd()}")

    # Initilize the agentops for tracing of communication with LLMs
    agentops.init(auto_start_session=False)

    # Read the YAML config file
    with open('config.yaml', 'r') as f:
        config = yaml.safe_load(f)    # Read the config file

    # Reading configuarations
    metadata_txt = read_file(config['app']['Metadata'])
    datapath = config['app']['DataPath']
    imagepath = config['app']['ImagePath']
    num_questions = config['app']['NumOfQuestions']

    print(f"元数据文件位置: {metadata_txt}")
    print(f"数据路径位置: {datapath}")
    print(f"图像位置: {imagepath}")   

    # To store analysis for each questions.
    md_content = []
    
    agentops.start_session( tags = ['question', 'hypothesis'] )

    # Creating hypothesis or generating questions using QuestCrew
    q_inputs = {
        'how_many': int(num_questions),
        'metadata_info': metadata_txt,
    }

    # Run the agent
    qresult = QuestCrew().crew().kickoff(inputs=q_inputs)

    agentops.end_session("成功")

    if qresult is not None:        
        print(f"来自 crew.kickoff 的原始结果: {qresult.raw}")
    
    qlist = qresult.pydantic
    for q in qlist.questions:
        print(f"问题: {q}")            

    # Create the directories for storing the created plots
    for i in range(len(qlist.questions)):
        os.makedirs(f"{imagepath}/q_{i}", exist_ok=True)   

    # Creating the EDACrews for generate code and answer those questions
    # Also to summarize the questions
    
    eda_inputs_list = [{
        'question_str': q,
        'metadata_info': metadata_txt,
        'datapath_info': datapath,
        'imagepath_dir': f"{imagepath}/q_{i}"} for i, q in enumerate(qlist.questions)]

    agentops.start_session(tags = ['answer', 'analysis'])

    # Run the agent
    final_results = EDACrew().crew().kickoff_for_each(inputs = eda_inputs_list)

    agentops.end_session("成功")

    # Consolidating the writing to a file. 
    try:
        with open("final_analysis.md", 'w') as file:
            file.write("# 探索性数据分析" + '\n\n')
            file.write("## 数据集描述" + '\n\n')
            file.write(metadata_txt + '\n\n')
            for i, mdc in enumerate(final_results):
                file.write(f"## EDA 分析 - {i+1}" + '\n\n')
                print(mdc.raw)
                file.write(mdc.raw + '\n\n')
                file.write(generate_markdown_for_images(f"{imagepath}/q_{i}") +"\n\n")
        print(f"成功写入 final_analysis.md")
    except IOError as e:
        print(f"写入文件时发生错误: {e}")

    agentops.end_session("成功")

生成Markdown报告

最后一步是将所有分析整合到一个markdown文件中。该报告包括数据集描述、商务顾问代理提出的每个问题、用于回答问题的代码以及结果分析。

以下是生成的EDA报告示例。

## Exploratory Data Analysis

### Dataset Description

南非西开普省一个心脏病高风险地区的男性回顾性样本。每个冠心病案例大约有两个对照组。许多冠心病阳性男性在冠心病事件后接受了降血压治疗和其他减少风险因素的项目。在某些情况下,测量是在这些治疗之后进行的。这些数据来自一个更大的数据集,详见Rousseauw等人,1983年,南非医学杂志。

列名及其描述:

sbp - 收缩压
tobacco - 累积烟草(千克)
ldl - 低密度脂蛋白胆固醇
adiposity - https://en.m.wikipedia.org/wiki/Body_adiposity_index
famhist - 家族心脏病史(存在,缺失)
typea - A型行为
obesity - https://en.wikipedia.org/wiki/Obesity
alcohol - 当前酒精消费
age - 发病年龄
chd - 响应,冠心病


### EDA Analysis - 1

#### Question
收缩压(sbp)在有冠心病(chd)和没有冠心病的个体之间的分布有什么不同,这对该人群的血压与心脏病风险之间的关系有什么启示?

#### Code
```python
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.stats import ttest_ind

## 加载数据集
dataset_url = 'https://raw.githubusercontent.com/manaranjanp/MLIntroV1/main/Classification/SAheart.data'
data = pd.read_csv(dataset_url)

## 绘制有冠心病(CHD)和无冠心病(No CHD)个体的收缩压分布
plt.figure(figsize=(10, 6))
sns.histplot(data[data['chd'] == 1]['sbp'], color='red', label='CHD', kde=True, stat='density', bins=30)
sns.histplot(data[data['chd'] == 0]['sbp'], color='blue', label='No CHD', kde=True, stat='density', bins=30)
plt.title('按冠心病状态的收缩压分布')
plt.xlabel('收缩压')
plt.ylabel('密度')
plt.legend()
plt.savefig('/Users/manaranjanp/Documents/Work/MyLearnings/fastHTML/llmeda/q_0/sbp_distribution.png')
plt.show()

## 执行 t 检验以比较两个组的均值
chd_sbp = data[data['chd'] == 1]['sbp']
no_chd_sbp = data[data['chd'] == 0]['sbp']
t_stat, p_value = ttest_ind(chd_sbp, no_chd_sbp)

## 打印 t 检验的结果
print(f'T-test statistic: {t_stat}')
print(f'P-value: {p_value}')

代码输出

T-test statistic: 4.204044124452311
P-value: 3.1515993239517745e-05

分析

分析显示,患有冠心病(CHD)和未患有冠心病的个体之间收缩压(sbp)的分布存在显著差异。t 检验统计量为 4.204,p 值约为 3.15e-05,远低于传统的显著性水平 0.05。这表明两组之间的收缩压差异在统计上是显著的。直方图进一步说明,患有冠心病的个体相比于未患有冠心病的个体,往往具有更高的收缩压。这表明在该人群中,较高的收缩压与增加的冠心病风险相关。

图表

sbp_distribution.png

EDA 分析 - 2

问题

累积烟草消费(tobacco)与低密度脂蛋白胆固醇(ldl)水平之间是否存在显著相关性,这种关系可能如何影响在该高风险地区发展冠心病的风险?

代码

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.stats import pearsonr
import statsmodels.api as sm

## 加载数据集
dataset_url = 'https://raw.githubusercontent.com/manaranjanp/MLIntroV1/main/Classification/SAheart.data'
data = pd.read_csv(dataset_url)

## 显示数据集的前几行
data.head()

## 检查烟草与 LDL 之间的相关性
correlation, p_value = pearsonr(data['tobacco'], data['ldl'])
print(f'烟草与 LDL 之间的相关性: {correlation}, p 值为 {p_value}')

## 绘制烟草与 LDL 之间的关系
plt.figure(figsize=(10, 6))
sns.scatterplot(x='tobacco', y='ldl', data=data)
plt.title('烟草与 LDL 的散点图')
plt.xlabel('累计烟草 (kg)')
plt.ylabel('LDL 胆固醇')
plt.savefig('/Users/manaranjanp/Documents/Work/MyLearnings/fastHTML/llmeda/q_1/tobacco_ldl_correlation.png')
plt.show()

## 逻辑回归分析对冠心病的影响
X = data[['tobacco', 'ldl']]
y = data['chd']
X = sm.add_constant(X)  # 添加常数项

model = sm.Logit(y, X)
result = model.fit()
print(result.summary())

代码输出

吸烟与低密度脂蛋白胆固醇之间的相关性: 0.15890545800595818, p值为 0.000607828617738955

优化成功终止。
         当前函数值: 0.575236
         迭代次数 5
                           逻辑回归结果                           
==============================================================================
因变量:                    chd   观察数量:                  462
模型:                          Logit   自由度残差:                      459
方法:                           MLE   自由度模型:                            2
日期:                2024年9月5日   伪 R-squ.:                  0.1084
时间:                        17:55:51   对数似然:                -265.76
收敛:                       True   LL-Null:                       -298.05
协方差类型:            非稳健   LLR p值:                 9.427e-15
==============================================================================
                 coef    std err          z      P>|z|      [0.025      0.975]
------------------------------------------------------------------------------
const         -2.3305      0.293     -7.951      0.000      -2.905      -1.756
tobacco        0.1297      0.025      5.290      0.000       0.082       0.178
ldl            0.2447      0.053      4.607      0.000       0.141       0.349
==============================================================================

分析

累积烟草消费与低密度脂蛋白胆固醇水平之间的相关性分析显示出大约 0.159 的正相关,且 p 值为 0.0006,具有统计显著性。这表明吸烟与 LDL 水平之间存在弱但显著的正相关关系。

逻辑回归结果表明,烟草消费和 LDL 水平在该数据集中都是冠心病 (CHD) 的显著预测因子。烟草和 LDL 的系数均为正值,表明这些变量的水平越高,冠心病的风险越大。具体来说,逻辑回归模型显示,烟草消费每增加一个单位,患冠心病的对数几率大约增加 0.13,而每增加一个单位的 LDL,对数几率大约增加 0.24。

总体而言,尽管烟草与 LDL 之间的相关性较弱,但这两个因素在这个高风险区域中对冠心病的发展风险有独立的贡献。

图表

tobacco_ldl_correlation.png

这里是视频链接,详细讲解了这个 AI 代理的实现过程。

## 摘要:用AI革新数据分析

该项目代表了自动化EDA过程的一次重大进步。通过利用AI代理的力量,我们可以生成深刻的问题,进行全面的分析,并生成详尽的报告——这一切所需时间仅为人类所需时间的一小部分。这个框架不仅高效,而且高度适应性强,适合于各个领域的广泛数据分析任务。

随着企业继续应对不断增长的数据集,像这样的解决方案将变得越来越有价值。通过自动化常规分析任务,数据科学家可以专注于更具战略性的挑战,从而推动其组织的创新和增长。数据分析的未来已到来,而它是由AI驱动的。

Related Posts

使用 ChatGPT 搜索网络功能的 10 种创意方法

使用 ChatGPT 搜索网络功能的 10 种创意方法

例如,提示和输出 你知道可以使用 ChatGPT 的“搜索网络”功能来完成许多任务,而不仅仅是基本的网络搜索吗? 对于那些不知道的人,ChatGPT 新的“搜索网络”功能提供实时信息。 截至撰写此帖时,该功能仅对使用 ChatGPT 4o 和 4o-mini 的付费会员开放。 ![](https://images.weserv.nl/?url=https://cdn-im

阅读更多
在人工智能和技术领域保持领先地位的 10 项必学技能 📚

在人工智能和技术领域保持领先地位的 10 项必学技能 📚

在人工智能和科技这样一个动态的行业中,保持领先意味着不断提升你的技能。无论你是希望深入了解人工智能模型性能、掌握数据分析,还是希望通过人工智能转变传统领域如法律,这些课程都是你成功的捷径。以下是一个精心策划的高价值课程列表,可以助力你的职业发展,并让你始终处于创新的前沿。 1. 生成性人工智能简介课程: [生成性人工智能简介](https://genai.works

阅读更多
10 个强大的 Perplexity AI 提示,让您的营销任务自动化

10 个强大的 Perplexity AI 提示,让您的营销任务自动化

在当今快速变化的数字世界中,营销人员总是在寻找更智能的方法来简化他们的工作。想象一下,有一个个人助理可以为您创建受众档案,建议营销策略,甚至为您撰写广告文案。这听起来像是一个梦想? 多亏了像 Perplexity 这样的 AI 工具,这个梦想现在成为现实。通过正确的提示,您可以将 AI 转变为您的 个人营销助理。在本文中,我将分享 10 个强大的提示,帮助您自动

阅读更多
10+ 面向 UI/UX 设计师的顶级 ChatGPT 提示

10+ 面向 UI/UX 设计师的顶级 ChatGPT 提示

人工智能技术,如机器学习、自然语言处理和数据分析,正在重新定义传统设计方法。从自动化重复任务到实现个性化用户体验,人工智能使设计师能够更加专注于战略思维和创造力。随着这一趋势的不断增长,UI/UX 设计师越来越多地采用 AI 驱动的工具来促进他们的工作。利用人工智能不仅能提供基于数据的洞察,还为满足多样化用户需求的创新设计解决方案开辟了机会。 1. 用户角色开发 目的

阅读更多
在几分钟内完成数月工作的 100 种人工智能工具

在几分钟内完成数月工作的 100 种人工智能工具

人工智能(AI)的快速发展改变了企业的运作方式,使人们能够在短短几分钟内完成曾经需要几周或几个月的任务。从内容创作到网站设计,AI工具帮助专业人士节省时间,提高生产力,专注于创造力。以下是按功能分类的100个AI工具的全面列表,以及它们在现实世界中的使用实例。 1. 研究工具 研究可能耗时,但人工智能工具使查找、分析和组织数据变得更加容易。**ChatGPT, Cop

阅读更多
你从未知道的 17 个令人惊叹的 GitHub 仓库

你从未知道的 17 个令人惊叹的 GitHub 仓库

Github 隐藏的宝石!! 立即收藏的代码库 学习编程相对简单,但掌握编写更好代码的艺术要困难得多。GitHub 是开发者的宝藏,那里“金子”是其他人分享的精心编写的代码。通过探索 GitHub,您可以发现如何编写更清晰的代码,理解高质量代码的样子,并学习成为更熟练开发者的基本步骤。 1. notwaldorf/emoji-translate *谁需

阅读更多