Pandas使用两个数据帧进行布尔索引

时间:2015-01-28 15:46:32

标签: python python-3.x pandas

我有两个pandas数据帧:

df1
'A' 'B'
 0   0
 0   2
 1   1
 1   1
 1   3

df2
'ID' 'value'
 0   62
 1   70
 2   76
 3   4674
 4   3746

我想将df.value作为新列D分配给df1,但仅限于df.A == 0df1.Bdf2.ID应该是标识符。

示例输出:

df1
'A' 'B' 'D'
 0   0   62
 0   2   76
 1   1   NaN
 1   1   NaN
 1   3   NaN

我尝试了以下内容:

df1['D'][ df1.A == 0 ] = df2['value'][df2.ID == df1.B]

但是,由于df2和df1的长度不同,我得到了一个ValueError。

ValueError: Series lengths must match to compare

这肯定是由于最后一部分的布尔索引:[df2.ID == df1.B]

有谁知道如何在不需要迭代数据帧的情况下解决问题?

非常感谢!

==============

编辑回复@EdChum:它与示例数据完美配合,但我的实际数据存在问题。 df1是一个庞大的数据集。 df2看起来像这样:

df2
    ID  value
0   1   1.00000
1   2   1.00000
2   3   1.00000
3   4   1.00000
4   5   1.00000
5   6   1.00000
6   7   1.00000
7   8   1.00000
8   9   0.98148
9   10  0.23330
10  11  0.56918
11  12  0.53251
12  13  0.58107
13  14  0.92405
14  15  0.00025
15  16  0.14863
16  17  0.53629
17  18  0.67130
18  19  0.53249
19  20  0.75853
20  21  0.58647
21  22  0.00156
22  23  0.00000
23  24  0.00152
24  25  1.00000

在进行合并之后,输出如下:首先是133次0.98148,然后是47次0.00025然后它继续从df2获得更多的值序列,直到最后出现一系列NaN条目......

Out[91]: df1
    A   B   D
0   1   3   0.98148
1   0   9   0.98148
2   0   9   0.98148
3   0   7   0.98148
5   1   21  0.98148
7   1   12  0.98148
...     ...     ...     ...
2592    0   2   NaN
2593    1   17  NaN
2594    1   16  NaN
2596    0   17  NaN
2597    0   6   NaN

知道这里可能发生了什么吗?它们都是int64。

==============

以下是两个带有重现问题数据的csv。

DF1: https://owncloud.tu-berlin.de/public.php?service=files&t=2a7d244f55a5772f16aab364e78d3546

DF2: https://owncloud.tu-berlin.de/public.php?service=files&t=6fa8e0c2de465cb4f8a3f8890c325eac

重现:

import pandas as pd

df1 = pd.read_csv("../../df1.csv")
df2 = pd.read_csv("../../df2.csv")

df1['D'] = df1[df1.A == 0].merge(df2,left_on='B', right_on='ID', how='left')['value']

1 个答案:

答案 0 :(得分:3)

这个稍微有点棘手,这里有2个步骤,首先是只选择df中'A'为0的行,然后合并到另一个df,其中'B'和'ID'匹配,但执行''左'合并,然后从中选择'值'列并分配给df:

In [142]:

df['D'] = df[df.A == 0].merge(df1, left_on='B',right_on='ID', how='left')['value']
df
Out[142]:
   A  B   D
0  0  0  62
1  0  2  76
2  1  1 NaN
3  1  1 NaN
4  1  3 NaN

打破这一点将显示正在发生的事情:

In [143]:
# boolean mask on condition
df[df.A == 0]
Out[143]:
   A  B   D
0  0  0  62
1  0  2  76
In [144]:
# merge using 'B' and 'ID' columns
df[df.A == 0].merge(df1, left_on='B',right_on='ID', how='left')
Out[144]:
   A  B   D  ID  value
0  0  0  62   0     62
1  0  2  76   2     76

完成上述所有操作后,您可以直接分配:

df['D'] = df[df.A == 0].merge(df1, left_on='B',right_on='ID', how='left')['value']

这样可以与左侧的idnex对齐,因此会自动分配任何缺失的值NaN

修改

另一种似乎适用于您的真实数据的方法是使用map为您执行查找,map接受一个字典或系列作为参数并查找相应的值,在这种情况下,您需要将索引设置为“ID”列,这会将您的df降低为只有“值”列的一个:

df['D'] = df[df.A==0]['B'].map(df1.set_index('ID')['value'])

所以上面像以前一样执行布尔索引,然后在'B'列上调用map,并在我们在'ID'上设置索引后查找其他df中相应的'Value'。

<强>更新

我查看了你的数据和我的第一个方法,我可以看到为什么会失败,左侧df的对齐失败,所以你在连续的行中得到1192个值,然后其余的行是{{1}直到第2500行。

如果你像这样在左侧应用相同的面具,那么工作是什么:

NaN

因此,这会正确遮盖左侧的行并分配合并的结果