Python数据框检查列数据帧中的值是否在另一个数据帧中报告的值范围内

时间:2016-07-12 16:52:31

标签: python function dataframe multiple-columns matching

道歉,如果问题是微不足道的,但作为一个python newby,我无法找到正确的解决方案。

我有两个数据帧,我需要在第一个数据帧中添加一个列,如果第一个数据帧的某个值在第二个数据帧的两个值之间,则为true,否则为false。

例如:

first_df = pd.DataFrame({'code1':[1,1,2,2,3,1,1],'code2':[10,22,15,15,7,130,2]})
second_df = pd.DataFrame({'code1':[1,1,2,2,3,1,1],'code2_start':[5,20,11,11,5,110,220],'code2_end':[15,25,20,20,10,120,230]})

first_df

  code1 code2
0   1   10
1   1   22
2   2   15
3   2   15
4   3   7
5   1   130
6   1   2

second_df

  code1 code2_end   code2_start
0   1   15          5
1   1   25          20
2   2   20          11
3   2   20          11
4   3   10          5
5   1   120         110
6   1   230         220

对于第一个数据帧中的每一行,我应该检查code2 columne中报告的值是否在第二个数据帧second_df的行所标识的可能范围之一之间,例如:

first_df code1=1code2=22

的第1行

检查second_df我有4行code1=1rows 0,1,56,值code2=22位于code2_start=20标识的区间内和code2_end=25所以函数应该返回True

考虑一个函数应该返回False的例子,

first_df code1=1code2=130

的第5行

但是没有包含130 code1=1

的间隔

我试过使用这个功能

def check(first_df,second_df):
    for i in range(len(first_df):
        return ((second_df.code2_start <= first_df.code2[i]) & (second_df.code2_end <= first_df.code2[i]) & (second_df.code1 == first_df.code1[i])).any()

并将其矢量化

first_df['output'] = np.vectorize(check)(first_df, second_df)

但显然没有成功。

我很乐意为您提供任何意见。

THX。

一个。

作为一个实际例子:

first_df.code1[0] = 1

因此我需要在second_df上搜索所有的istances

second_df.code1 == first_df.code1[0]
0     True
1     True
2    False
3    False
4    False
5     True
6     True

对于实例0,1,5,6,其中状态为True我需要检查值

first_df.code2[0]
10

介于

标识的范围之一
second_df[second_df.code1 == first_df.code1[0]][['code2_start','code2_end']]
    code2_start code2_end
0   5           15
1   20          25
5   110         120
6   220         230

因为first_df.code2 [0]的值是10,所以它在5到15之间,所以由行0标识的范围因此我的函数应该返回True。在first_df.code1 [6]的情况下,值仍然是1,因此范围表仍然是相同的,但在这种情况下first_df.code2 [6]是2并且没有包含2的间隔因此resut应该是False

1 个答案:

答案 0 :(得分:1)

first_df['output'] = (second_df.code2_start <= first_df.code2) & (second_df.code2_end <= first_df.code2)

这是有效的,因为当您执行以下操作时:second_df.code2_start <= first_df.code2

你得到一个布尔系列。如果您在其中两个布尔系列上执行逻辑AND,则会得到一个值为True的Series,其中Series TrueFalse

以下是一个例子:

>>> import pandas as pd
>>> a = pd.DataFrame([{1:2,2:4,3:6},{1:3,2:6,3:9},{1:4,2:8,3:10}])
>>> a['output'] = (a[2] <= a[3]) & (a[2] >= a[1])
>>> a
   1  2   3 output
0  2  4   6   True
1  3  6   9   True
2  4  8  10   True

编辑:

因此,基于您更新的问题和我对您的问题的新解释,我会做这样的事情:

import pandas as pd

# Define some data to work with
df_1 = pd.DataFrame([{'c1':1,'c2':5},{'c1':1,'c2':10},{'c1':1,'c2':20},{'c1':2,'c2':8}])
df_2 = pd.DataFrame([{'c1':1,'start':3,'end':6},{'c1':1,'start':7,'end':15},{'c1':2,'start':5,'end':15}])

# Function checks if c2 value is within any range matching c1 value
def checkRange(x, code_range):
    idx = code_range.c1 == x.c1
    code_range = code_range.loc[idx]
    check = (code_range.start <= x.c2) & (code_range.end >= x.c2)
    return check.any()

# Apply the checkRange function to each row of the DataFrame
df_1['output'] = df_1.apply(lambda x: checkRange(x, df_2), axis=1)

我在这里做的是定义一个名为checkRange的函数,它作为输入x,一行df_1code_range,整个df_2数据帧。它首先查找code_range的行,这些行与给定行c1具有相同的x.c1值。然后丢弃不匹配的行。这是在前两行中完成的:

idx = code_range.c1 == x.c1
code_range = code_range.loc[idx]

接下来,我们得到一个布尔系列,告诉我们x.c2是否属于简化code_range数据框中给出的任何范围:

check = (code_range.start <= x.c2) & (code_range.end >= x.c2)

最后,由于我们只关心x.c2属于其中一个范围,因此我们返回check.any()的值。当我们在布尔系列上调用any()时,如果系列中的任何值为True,它将返回True

要在checkRange的每一行调用df_1函数,我们可以使用apply()。我定义了lambda expression,以便将checkRange函数发送到行以及df_2axis=1表示将在DataFrame的每一行(而不是每一列)上调用该函数。