【问题标题】:Merge dataframe with another dataframe created from apply function?将数据框与从应用函数创建的另一个数据框合并?
【发布时间】:2021-06-29 02:32:58
【问题描述】:

我有一个工资数据的数据框df

State,Annual Salary
New York, 132826
New Hampshire,128704
California,127388
Vermont,121599
Idaho,120011

还有一个函数,get_taxes_from_api,它调用 API 并将输入的州和年薪的税号作为只有 1 行的数据框返回,如下所示:

State,annual.fica.amount,annual.federal.amount,annual.state.amount
North Carolina,8918,40334,6364

它的类型是:<class 'pandas.core.frame.DataFrame'> 不是系列。 我想在 df 的每一行上调用 API,然后合并每个生成的 1 行数据帧。比如:

State,Annual Salary,annual.fica.amount,annual.federal.amount,annual.state.amount
North Carolina, 116500,8918,40334,6364
New York, 132826, . . . 
New Hampshire,128704, . . . 
California,127388, . . . 
Vermont,121599, . . . 
Idaho,120011, . . . 

我该怎么做?我遇到了一个错误,我的 lambda 下面创建了一个系列而不是数据框,所以像这里 'https://stackoverflow.com/a/62849468/2415706' 这样使用 result_type=expand 进入了这个兔子洞,但它仍然坏了:

all_tax_df = df[['State','Annual Salary']].apply(lambda row: get_taxes_from_api(row['State'],row['Annual Salary']), axis=1, result_type='expand')


# merge all_tax_df with df on 'State'

【问题讨论】:

    标签: python pandas dataframe merge


    【解决方案1】:

    .apply() 中的应用函数返回熊猫系列时,您无需为.apply() 调用指定result_type。来自official document

    在函数内部返回一个Series类似于传递 结果类型='展开'。结果列名将是系列 索引。

    另外,对于默认的result_type=None

    默认行为(无)取决于 应用函数:....如果应用函数返回一个系列,这些是 扩展到列。

    由于您的 API(.apply() 调用中的应用函数)返回一个 1 行 DataFrame,您可以通过 .squeeze() 调用轻松地将其转换为系列,如下所示:

    df[['State','Annual Salary']].apply(
        lambda row: get_taxes_from_api(row['State'], row['Annual Salary']).squeeze(), axis=1)
    

    apply() 调用的结果仅包含API 调用返回的列,不包括原始DataFrame 中的Annual Salary 列。您可以调用.merge() 将原始数据帧与从apply() 返回的结果数据帧合并,以获得所需的布局。您可以在一行中完成 2 个步骤:

    all_tax_df = df.merge(df[['State','Annual Salary']].apply(
        lambda row: get_taxes_from_api(row['State'], row['Annual Salary']).squeeze(), axis=1))
    

    试运行

    col = ['State','Annual Salary']
    dat = [['New York', 132826], ['New Hampshire',128704], ['California',127388], ['Vermont',121599], ['Idaho',120011]]
    df = pd.DataFrame(dat, columns=col)
    
    def get_taxes_from_api(state, annual_salary):
        return pd.DataFrame({'State': [state], 
                             'annual.fica.amount': [int(annual_salary * 0.067)], 
                             'annual.federal.amount': [int(annual_salary * 0.3)], 
                             'annual.state.amount': [int(annual_salary * 0.048)]})
    
    
    all_tax_df = df.merge(df[['State','Annual Salary']].apply(
        lambda row: get_taxes_from_api(row['State'], row['Annual Salary']).squeeze(), axis=1))
    
    
    
    print(all_tax_df)
    
    
    
    
               State  Annual Salary  annual.fica.amount  annual.federal.amount  annual.state.amount
    0       New York         132826                8899                  39847                 6375
    1  New Hampshire         128704                8623                  38611                 6177
    2     California         127388                8534                  38216                 6114
    3        Vermont         121599                8147                  36479                 5836
    4          Idaho         120011                8040                  36003                 5760
    

    【讨论】:

    • 我尝试了您在此处修复该错字的方法,但仍然无法正常工作。 get_taxes_from_api 不返回 pd.Series,它返回一个数据框。这是我在编写测试打印其类型和返回内容时得到的结果:<class 'pandas.core.frame.DataFrame'> annual.fica.amount annual.federal.amount annual.state.amount State Initial State 0 7650 15103.5 0 TX Texas
    • @user2415706 我通过定义自定义函数进一步简化了代码,这样我们就不需要在lambda函数中调用两次api了。
    • @user2415706 使用.squeeze() 可以轻松地将 1 行数据帧转换为熊猫系列。请参阅上面的合并编辑。代码可以大大简化并用作最终版本。
    • 感谢您的更新,是的,它看起来更适合挤压()。
    【解决方案2】:

    如果您真的不希望将结果作为一个系列,您可以轻松地将其转换为 DataFrame。

    import pandas as pd    
    
    all_tax_df = pd.DataFrame(df[['State','Annual Salary']].apply(lambda row: get_taxes_from_api(row['State'],row['Annual Salary']), axis=1, result_type='expand'))
    

    【讨论】:

    • 试过这个,我得到:ValueError: If using all scalar values, you must pass an index,get_taxes_from_api 已经返回一个数据帧,我写了一个测试,这就是测试输出的类型和输出:<class 'pandas.core.frame.DataFrame'> annual.fica.amount annual.federal.amount annual.state.amount State Initial State 0 7650 15103.5 0 TX Texas
    【解决方案3】:

    您只需将应用结果直接分配给新列即可:

    df[["annual.fica.amount","annual.federal.amount","annual.state.amount"]]=( 
        df[['State','Annual Salary']].apply(lambda row: get_taxes_from_api(row['State'],row['Annual Salary']), axis=1)
    )
    

    如果您在一次调用 api 中获得整个数据帧(这可能更有效),那么合并将是一个好主意

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-30
      • 1970-01-01
      • 2019-07-21
      • 2016-08-20
      • 2018-08-26
      • 2016-01-20
      • 2019-03-19
      • 1970-01-01
      相关资源
      最近更新 更多