Pandas - 根据其他列的值从特定列中选择行值

时间:2021-01-04 18:35:53

标签: python pandas dataframe

这有点令人费解,但我只会显示我的数据

我构建了以下数据框:

      Mid_XYZ  Mid_YYY  Mid_ZZZ Select1 Select2
867    1019.11   1027.64  1022.68   XYZ   YYY
873    1018.04   1027.58  1022.81   XYZ   ZZZ

我想通过匹配列名的一部分,从基于 Select1Select2 字符串的列中选择值。在第一行,这将是

1019.111027.64(列 Mid_XYZMid_YYY) - 因为 Select1 有字符串 XYZSelect2 有字符串YYY

其中,在第二行

1018.041022.81(列 Mid_XYZMid_ZZZ

稍后,我计划将这些值的总和存储在新列中。 DataFrame 看起来像这样

      Mid_XYZ  Mid_YYY  Mid_ZZZ Select1 Select2 Sum
867    1019.11   1027.64  1022.68   XYZ   YYY   2046.75
873    1018.04   1027.58  1022.81   XYZ   ZZZ   2040.85

我可以将列名更改为精确匹配,但应该有一些正则表达式的解决方案?我知道 df.filter(regex='XYZ'),但如何按行进行操作?

4 个答案:

答案 0 :(得分:5)

使用以下矢量化解决方案:

import numpy as np

# clean rows
clean = df.columns.str.replace('^Mid_', '', regex=True)

# find matching column indices
s1 = np.argmax(clean.values == df['Select1'].values[:, None], axis=1)
s2 = np.argmax(clean.values == df['Select2'].values[:, None], axis=1)

# index and sum
df['Sum'] = df.values[np.arange(len(s1)), s1] + df.values[np.arange(len(s2)), s2]

print(df)

输出

     Mid_XYZ  Mid_YYY  Mid_ZZZ Select1 Select2      Sum
867  1019.11  1027.64  1022.68     XYZ     YYY  2046.75
873  1018.04  1027.58  1022.81     XYZ     ZZZ  2040.85

答案 1 :(得分:2)

import pandas as pd

如果你有:

df=pd.DataFrame.from_dict({'Mid_XYZ':[1019.11,1018.04],
                           'Mid_YYY':[1027.64,1027.58],
                           'Mid_ZZZ':[1022.68,1022.81],
                           'Select1':['XYZ','XYZ'],
                           'Select2':['YYY','ZZZ']})

你可以这样做:

df['Sum']=df.apply(lambda row:
                   row['Mid_'+row['Select1']]+\
                   row['Mid_'+row['Select2']],
                   axis=1)

df 将是:

   Mid_XYZ  Mid_YYY  Mid_ZZZ Select1 Select2      Sum
0  1019.11  1027.64  1022.68     XYZ     YYY  2046.75
1  1018.04  1027.58  1022.81     XYZ     ZZZ  2040.85

如果你不喜欢lambda函数,可以通过定义一个函数来达到同样的效果:

def sumfunc(row):
    return row['Mid_'+row['Select1']]+row['Mid_'+row['Select2']]

那么:

df['Sum']=df.apply(sumfunc,axis=1)

答案 2 :(得分:2)

另一种使用 meltconcat 的解决方案:

cols = ['Select1', 'Select2']
df1 = df.melt(id_vars=cols, ignore_index=False)
df['Sum'] = (pd.concat([df1[('Mid_' + df1[col]) == df1['variable']] 
                        for col in cols]).groupby(level=0).sum())  # can also pass `sort=False` to `groupby` for ~10% or something speed boost
df
Out[1]: 
     Mid_XYZ  Mid_YYY  Mid_ZZZ Select1 Select2      Sum
867  1019.11  1027.64  1022.68     XYZ     YYY  2046.75
873  1018.04  1027.58  1022.81     XYZ     ZZZ  2040.85

答案 3 :(得分:2)

除了@Dani Mesejo 的回答之外,我还使用内置在 where 中的 numpy 添加了更快的实现和更直接的...

我的实现是 vec2 :

def vec1(df):
    clean = df.columns.str.replace('^Mid_', '', regex=True)
    s1 = np.argmax(clean.values == df['Select1'].values[:, None], axis=1)
    s2 = np.argmax(clean.values == df['Select2'].values[:, None], axis=1)
    # index and sum
    df['Sum'] = df.values[np.arange(len(s1)), s1] + df.values[np.arange(len(s2)), s2]
    return df

def vec2(df):
    clean = df.columns.str.replace('^Mid_', '', regex=True)
    idx1 = np.where(clean.values == df['Select1'].values[:,None] )
    idx2 = np.where(clean.values == df['Select2'].values[:,None] )
    df['Sum'] = df.values[idx1] + df.values[idx2]
    return df

这里是时间比较:

我的实现:

%timeit vec2(df) : 388 µs ± 3.97 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

@Dani Mesejo :

%timeit vec1(df) : 405 µs ± 6.42 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
相关问题