【问题标题】:Apply a function with two dataframe as argument应用具有两个数据框作为参数的函数
【发布时间】:2021-08-19 09:58:15
【问题描述】:

我正在寻找运行将两个数据帧作为参数 df1 和 df2 的函数的方法。

我想要的是根据 df2 中的信息在 df1 中创建一个新列,而不使用循环,因为我的整个 df1 是 3M 行,df2 是 700k 行。 为此,我比较 df1 的 X 的值是否包含在 from 和 df2 的 to

我尝试使用 pandas 库,但出现如下错误:

ValueError: 只能比较标签相同的 Series 对象

这是我的代码示例。

import pandas as pd
import numpy as np

df1 = pd.DataFrame({'X':[1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9,
                         2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9],
                    'Z':['F1','F2','F2','F1','F1','F2','F2','F1','F2','F2',
                         'F1','F1','F1','F1','F1','F1','F1','F1','F1','F1']})

df2 = pd.DataFrame({
           'from': [1.0, 1.5, 1.8, 2.2, 2.6],
           'to': [1.5, 1.8, 2.2, 2.6, 2.9],
           'Z': ['F1', 'F1', 'F2', 'F1', 'F2'],
           'Y': ['foo', 'bar', 'foobar', 'foo', 'zoo']
})
def asign(df1, df2):
    if df1['Z'] == df2['Z']:
        idx = np.where((df1[X] >= df2['from']) & (df1[X]<= df2['to']))[0]
        df1['Y'] = df2['Y'][idx]
        return df1

df1.groupby('Z').apply(asign, df2)

输出必须是这样的:

>>> df1
out[0] : 
    X    Z   Y
0   1.0  F1  foo
1   1.1  F2  bar
2   1.2  F2  foobar
3   1.3  F1  foo
4   1.4  F1  foobar
5   1.5  F2  bar
6   1.6  F1  foo
7   1.7  F2  bar

要在 df1 中创建的 Y 列的值取决于该行属于 F1 或 F2 组 Z 并且 X 的值大于或等于 from 且小于 to 请问你能帮我解决这个问题吗? 谢谢

【问题讨论】:

  • 您能否编辑您的问题并将预期的输出(+解释)放在那里?
  • 问题已更新

标签: python pandas dataframe


【解决方案1】:

使用pd.cut() 的更好解决方案

下面的旧解决方案运行良好,但它可能效率不高,因为它首先创建一个大型数据框,然后从中选择一个行子集。此解决方案改为使用 pd.cut 创建 bin,然后合并数据帧,直接创建所需的输出。

此外,这为如何进行合并提供了额外的灵活性。

df1 = pd.DataFrame({'X':[1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9,
                         2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9],
                    'Z':['F1','F2','F2','F1','F1','F2','F2','F1','F2','F2',
                         'F1','F1','F1','F1','F1','F1','F1','F1','F1','F1']})

df2 = pd.DataFrame({
           'bmin': [1.0,   1.5,   1.8,      2.2,   2.6],
           'bmax': [1.5,   1.8,   2.2,      2.6,   2.9],
           'Z':    ['F1',  'F1',  'F2',     'F1',  'F2'],
           'Y':    ['foo', 'bar', 'foobar', 'foo', 'zoo']
})


# Adding new column to the dataframes
bins = sorted(df2.bmin.unique()) + [df2.bmax.max()]

df1.loc[:, 'bin'] = pd.cut(
    df1.X,
    bins=bins,
    labels=False,        # Makes cut return int indices for the bins
    include_lowest=True, # Otherwise 1.0 would be NaN
)
df2.loc[:, 'bin'] = pd.cut(
    0.5 * (df2.bmin + df2.bmax),
    bins=bins,
    labels=False,
    include_lowest=True,
)

# Merge on all relevant columns. Change how to 'inner' for an inner join
merged = pd.merge(df1, df2, on=["Z", "bin"], how='outer')

输出样本

      X   Z  bin  bmin  bmax       Y
0   1.0  F1    0   1.0   1.5     foo
1   1.3  F1    0   1.0   1.5     foo
2   1.4  F1    0   1.0   1.5     foo
3   1.1  F2    0   NaN   NaN     NaN
4   1.2  F2    0   NaN   NaN     NaN

使用merge 后跟query 的旧解决方案

也许您会对DataFrame.query() 感兴趣?

在下面的代码中,我使用query 合并Z 上的数据帧。请注意,此代码的输出数据与您编写的不同,但我不明白如何

1   1.1  F2  bar

由于您希望 bin 和 Z 都匹配,因此可能来自您的输入数据?我可以看到,df2 中没有封装 1.1 的 bin 也有Z=F2。抱歉,如果我不理解您的问题。

请注意,我重命名了 df2 中的 bin 限制列,因为您不能在 numexpr 查询中使用 Python 关键字。

import pandas as pd
import numpy as np

df1 = pd.DataFrame({'X':[1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9,
                         2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9],
                    'Z':['F1','F2','F2','F1','F1','F2','F2','F1','F2','F2',
                         'F1','F1','F1','F1','F1','F1','F1','F1','F1','F1']})

df2 = pd.DataFrame({
           'bmin': [1.0,   1.5,   1.8,      2.2,   2.6],
           'bmax': [1.5,   1.8,   2.2,      2.6,   2.9],
           'Z':    ['F1',  'F1',  'F2',     'F1',  'F2'],
           'Y':    ['foo', 'bar', 'foobar', 'foo', 'zoo']
})

merged = pd.merge(
    df1, 
    df2,
    on='Z',
)
merged = merged.query('bmin <= X < bmax')
merged = merged.sort_values(by="X")[['X', 'Z', 'Y']]

给出输出

      X   Z       Y
0   1.0  F1     foo
3   1.3  F1     foo
6   1.4  F1     foo
10  1.7  F1     bar
50  1.8  F2  foobar
52  1.9  F2  foobar
20  2.2  F1     foo
23  2.3  F1     foo
26  2.4  F1     foo
29  2.5  F1     foo

【讨论】:

  • 这就是我正在寻找的内容,但是使用查询它只选择具有良好合并值的元素,而我希望整个数据集的值是 Y 所以所有元素都有一个Y 并且满足条件
  • 我放的输出不对,只是一个例子
  • 我添加了一个我认为更有效的新解决方案,至少在内存方面,使用 pd.bins。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多