我正在尝试将一个DataFrame(df2
)中的标签应用到另一个(df1
)条件中,并依赖于一个DataFrame列中的另一个值,以便在由一对列定义的区间内着陆在另一个Datarame中。
这是代码,
import pandas
import numpy
df1 = pandas.DataFrame( { 'a' : [1,2,3,4,5,6], 'b' : True } )
df2 = pandas.DataFrame( { 'c1':[ 2.0,3.1,5.2] , 'c2': [2.5,4.6,7.1] , 'l': ['x1','x2','x3'] } )
df1['l'] = numpy.NaN
for i in range( len( df1 ) ) :
aVal = df1.loc[ df1.index[i] , 'a' ]
is_in_c1c2 = ( df2['c1'] <= aVal ) & ( aVal < df2['c2'] )
if is_in_c1c2.any() :
df1.loc[ df1.index[i], 'l' ] = numpy.squeeze( df2.loc[ is_in_c1c2 , 'l' ].values )
# df1.loc[ df1.index[i], 'l' ] = df2.loc[ is_in_c1c2 , 'l' ] # ValueError, Incompatible indexer with Series
print( df1 )
print( df1['l'].map(type) )
>>>
a b l
0 1 True NaN
1 2 True x1
2 3 True NaN
3 4 True x2
4 5 True NaN
5 6 True x3
0 <type 'float'>
1 <type 'numpy.ndarray'>
2 <type 'float'>
3 <type 'numpy.ndarray'>
4 <type 'float'>
5 <type 'numpy.ndarray'>
Name: l, dtype: object
我第一次尝试ValueError, Incompatible indexer with Series
时发现异常,我感到很惊讶。为什么不支持,这是因为DataFrames的索引不匹配还是究竟是什么?
是否有更清洁/矢量化的方式来进行此类操作? .values
赋值很接近,但是我输入了错误的元素类型,所以我不得不挤压它们。很高兴在这里获得原始类型。我也为一个专栏制作了示例,但实际上我正在复制我的源代码中两列的标签。
答案 0 :(得分:1)
一种方法是使用Pandas'IntervalIndex
。
idx = pd.IntervalIndex.from_arrays(df2['c1'], df2['c2'], closed='both')
df1['l'] = df2.loc[idx.get_indexer(df1['a']), 'l'].values
df1
>>>
a b l
0 1 True NaN
1 2 True x1
2 3 True NaN
3 4 True x2
4 5 True NaN
5 6 True x3
不确定这有多快。如果df1['a']
实际上只包含整数,那么有一种更快的方法。
我认为原来的ValueError
是因为df2.loc[ is_in_c1c2 , 'l' ]
会返回Series
。尝试在数据框中将Series
指定为值时发生错误。并df2.loc[ is_in_c1c2 , 'l' ].values
返回ndarray
。该数组只包含一个值,因为只有一个匹配,但理论上,可能有多个匹配。