Pandas 两个数据帧的布尔索引
Pandas Boolean indexing with two dataframes
我有两个 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 == 0
时。
df1.B
和 df2.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']
这个有点棘手,这里有 2 个步骤,首先是 select 只有 df 中 'A' 为 0 的行,然后合并到另一个 df 'B' 和 'ID' 匹配,但执行 'left' 合并,然后 select 来自此的 'value' 列并分配给 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 减少到只有 'Value' 列的一个:
df['D'] = df[df.A==0]['B'].map(df1.set_index('ID')['value'])
所以上面像以前一样执行布尔索引,然后在 'B' 列上调用 map
并在 [=] 上设置索引后在另一个 df 中查找相应的 'Value' 48=].
更新
我查看了你的数据和我的第一个方法,我明白了为什么会失败,左侧 df 的对齐失败,所以你在连续的行中得到 1192 个值,然后其余的行是 NaN
到第 2500 行。
如果您像这样在左侧应用相同的蒙版,则有效:
df1.loc[df1.A==0, 'D'] = df1[df1.A == 0].merge(df2,left_on='B', right_on='ID', how='left')['value']
所以这正确地屏蔽了左侧的行并分配了合并的结果
我有两个 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 == 0
时。
df1.B
和 df2.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']
这个有点棘手,这里有 2 个步骤,首先是 select 只有 df 中 'A' 为 0 的行,然后合并到另一个 df 'B' 和 'ID' 匹配,但执行 'left' 合并,然后 select 来自此的 'value' 列并分配给 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 减少到只有 'Value' 列的一个:
df['D'] = df[df.A==0]['B'].map(df1.set_index('ID')['value'])
所以上面像以前一样执行布尔索引,然后在 'B' 列上调用 map
并在 [=] 上设置索引后在另一个 df 中查找相应的 'Value' 48=].
更新
我查看了你的数据和我的第一个方法,我明白了为什么会失败,左侧 df 的对齐失败,所以你在连续的行中得到 1192 个值,然后其余的行是 NaN
到第 2500 行。
如果您像这样在左侧应用相同的蒙版,则有效:
df1.loc[df1.A==0, 'D'] = df1[df1.A == 0].merge(df2,left_on='B', right_on='ID', how='left')['value']
所以这正确地屏蔽了左侧的行并分配了合并的结果