Pandas 基于外部条件向数据帧添加列

Pandas 基于外部条件向数据帧添加列,pandas,dataframe,merge,Pandas,Dataframe,Merge,给定三个数据帧,一个包含用户数据,第二个包含数据装箱,第三个是类别名称,如中所示: klasses_df = pd.DataFrame([[1, 'Sad'], [7, 'Regular'], [13, 'Happy'], [42, 'Magical']], columns=['kl

给定三个数据帧,一个包含用户数据,第二个包含数据装箱,第三个是类别名称,如中所示:

klasses_df = pd.DataFrame([[1, 'Sad'],
                           [7, 'Regular'],
                           [13, 'Happy'],
                           [42, 'Magical']],
                           columns=['klass', 'mood'])
                           
bins_df = pd.DataFrame([[0.0, 3.0, 1],
                        [3.0, 6.0, 7],
                        [6.0, 8.0, 13]],
                       columns=['lower', 'upper', 'klass'])


person_df = pd.DataFrame([['John', 1.5],
                          ['Mary', 3.6],
                          ['Paul', 7.2],
                          ['Josh', 5.7],
                          ['Phil', 9.9]],
                         columns=['name', 'feeling'])
我想扩展
person\u df
(或者创建一个新的数据框),在这里可以找到正确的
klass\u id
情绪。例如,在
person\u df
的第一行中,John的感觉位于
1.5
,在
bins\u df
中,我们可以看到它位于范围第一范围
[0,3]
,因此位于
klass
1
。查看
klass\u df
我们发现
klass\u id
1
Sad
。这将使最后一行/新行与John相关,如
John,1.5,1,“Sad”

为此,我创建了两个辅助函数:

def find_klass_from_feeling(feeling, bin_data):
    values = bin_data.values
    klass = values[(values[:,0] <= feeling) & (feeling < values[:,1])][:,2]
    if len(klass) == 0:
        return 0
    else:
        return int(klass.flatten()[0])

def find_mood_from_class(klass, klasses_data):
    if klass == 0:
        return None
    retval = klasses_df[klasses_df['klass'] == klass]['mood'].iloc[0]
    return retval
这是可行的,但似乎完全错了,因为我相信,熊猫有一些更合适的方法来处理它。我尝试使用
apply
applymap
,但没有成功


欢迎提供任何提示。

首先,这个问题有几个问题:

  • 范围包括右值还是左值?现在,我假设没有,值3将进入bin 1
  • 超过8的值会发生什么变化?现在,我为超过8的所有值创建新类别“99”
要解决您的问题,可以使用pandas pd.cut()

您需要将您的垃圾箱和标签列在列表中:

您可以手动声明它:

bins = [0.0, 3.0, 6.0, 8.0, float("inf")]
labels = [1, 7, 13, 99]
或者,如果您的数据来自外部,您可以将其转换为:

bins = [0.0]+bins_df['upper'].to_list()+[float("inf")]
label = bins_df['klass'].to_list() + [99]
(我使用99作为伪值,以表示超过8的值缺少类)

现在使用
pd.cut()

person_df['klass']=pd.cut(person_df['feeling'], bins = bins, labels=labels)
然后将其链接到心情以获取值:

result = pd.merge(person_df, klasses_df, on='klass', how='left')
print(result)
输出:

   name  feeling  klass     mood
0  John      1.5      1      Sad
1  Mary      3.6      7  Regular
2  Paul      7.2     13    Happy
3  Josh      5.7      7  Regular
4  Phil      9.9     99      NaN

(Phil不在指定范围内,因此没有心情)

查看“非相等联接”,如此处所述:您可以将装箱重写为不同的格式,还是必须是此数据帧(即,如果箱子可以在列表中,这更易于管理)?另外,菲尔的分数超出了bin的范围,你的bin在开始和结束时都有相同的值。例如,如果一个人降落在3号货位上,他们应该属于1号货位还是7号货位?
lower
   name  feeling  klass     mood
0  John      1.5      1      Sad
1  Mary      3.6      7  Regular
2  Paul      7.2     13    Happy
3  Josh      5.7      7  Regular
4  Phil      9.9     99      NaN