根据条件从数据框中选择行

时间:2017-09-20 22:23:57

标签: python pandas dataframe conditional

我有一个数据框:

>>> d = {'ID' : ['ABC', 'ABC', 'ABC', 'DFG', 'DFG', 'DFG', 'EGF', '2BD', '2BD'], 'Val': ['High', 'Low', 'High', 'High', 'High', 'Low', 'Low', 'Low', 'High'], 
... 'Num': [22,2,16,10,50,3,2,34,2], 'Val2':['Low', 'High', 'Low', 'High', 'High', 'High', 'High', 'High', 'High']}
>>> import pandas as pd
>>> df = pd.DataFrame(d)
>>> df
    ID  Num   Val  Val2
0  ABC   22  High   Low
1  ABC    2   Low  High
2  ABC   16  High   Low
3  DFG   10  High  High
4  DFG   50  High  High
5  DFG    3   Low  High
6  EGF    2   Low  High
7  2BD   34   Low  High
8  2BD    2  High  High

是否有办法将条件应用于列中具有相同值的行,然后应用某些条件来检查其他列中的值?

我想要这样的输出:

ID | Val | Num | Val2

ABC | High | 22 | Low
DFG | High | 50 | High
EGF | Low  | 2  | High
2BD | High  | 2  | High

即,对于第一列中相同ID的位置,它检查Val列,优先于'High'值而不是'Low'或'Mod',然后从该ID中的行中选择'High'在Val列中,在“Num”列中选择值较高的行。

我这样做:

import pandas as pd
d = {'ID' : ['ABC', 'ABC', 'ABC', 'DFG', 'DFG', 'DFG', 'EGF', '2BD', '2BD'], 'Val': ['High', 'Low', 'High', 'High', 'High', 'Low', 'Low', 'Low', 'High'], 'Num': [22,2,16,10,50,3,2,34,2], 'Val2':['Low', 'High', 'Low', 'High', 'High', 'High', 'High', 'High', 'High']}
df = pd.DataFrame(d)
print df

x = df.ID.unique().tolist()
f_df=pd.DataFrame()
idlist=[]
vallist=[]
numlist=[]

for i in x:
    idlist.append(i)
    new_df = df.loc[df['ID'] == i]
    h_df = new_df.loc[df['Val'] == 'High']
    if h_df.empty:
        m_df = new_df.loc[df['Val'] == 'Mod']
        if m_df.empty:
            l_df = new_df.loc[df['Val'] == 'Low']
            vallist.append('Low')
            if len(l_df) > 1:
                m = l_df['Num'].max()
                numlist.append(m)
            else:
                m = l_df['Num'].max()
                numlist.append(m)
        else:
            vallist.append('Mod')
            if len(m_df) > 1:
                m = m_df['Num'].max()
                numlist.append(m)
            else:
                m = m_df['Num'].max()
                numlist.append(m)

    else:
        vallist.append('High')
        if len(h_df) > 1:
            m = h_df['Num'].max()
            numlist.append(m)
        else:
            m = h_df['Num'].max()
            numlist.append(m)

f_df['ID'] = idlist
f_df['Val'] = vallist
f_df['Num'] = numlist

print f_df

有更好的方法吗?另外,如何在输出中获得Val2的相应值?因为我实际上有一个包含12列的数据框。

1 个答案:

答案 0 :(得分:0)

已编辑添加

真正的 pandonic 方法是使用类别

>>> df['Val'] = df.Val.astype('category').cat.set_categories(['High','Mod','Low'], ordered=True)
>>> df['Val2'] = df.Val2.astype('category').cat.set_categories(['High','Mod','Low'], ordered=True)
>>> df
    ID  Num   Val  Val2
0  ABC   22  High   Low
1  ABC    2   Low  High
2  ABC   16  High   Low
3  DFG   10  High  High
4  DFG   50  High  High
5  DFG    3   Low  High
6  EGF    2   Low  High
7  2BD   34   Low  High
8  2BD    2  High  High
>>> df.dtypes
ID        object
Num        int64
Val     category
Val2    category
dtype: object

所以现在排序是我们想要的!

>>> (df.sort_values(['Val','Num'], ascending=[True, False])
...    .groupby('ID')
...    .nth(0))
     Num   Val  Val2
ID
2BD    2  High  High
ABC   22  High   Low
DFG   50  High  High
EGF    2   Low  High

原始答案

是的,我认为您不想使用内置排序和groupby,因此首先要创建将“高”,“模”和“低”值映射到的列数字所以我们可以很容易地和他们一起工作:

>>> df['valmap'] = df.Val.map({'High':0, 'Mod':1, 'Low':2})
>>> df['val2map'] = df.Val2.map({'High':0, 'Mod':1, 'Low':2})
>>> df
    ID  Num   Val  Val2  valmap  val2map
0  ABC   22  High   Low       0        2
1  ABC    2   Low  High       2        0
2  ABC   16  High   Low       0        2
3  DFG   10  High  High       0        0
4  DFG   50  High  High       0        0
5  DFG    3   Low  High       2        0
6  EGF    2   Low  High       2        0
7  2BD   34   Low  High       2        0
8  2BD    2  High  High       0        0

然后我想你只想:

>>> df.sort_values(['valmap','Num'], ascending=[True, False]).groupby('ID').nth(0)
     Num   Val  Val2  val2map  valmap
ID
2BD    2  High  High        0       0
ABC   22  High   Low        2       0
DFG   50  High  High        0       0
EGF    2   Low  High        0       2

当然,您可以随时选择您想要的列:

>>> (df.sort_values(['valmap','Num'], ascending=[True, False])
...    .groupby('ID')['Num','Val', 'Val2']
...    .nth(0))

     Num   Val  Val2
ID
2BD    2  High  High
ABC   22  High   Low
DFG   50  High  High
EGF    2   Low  High

所以,如果你考虑你的要求:

“第一列中相同ID的位置,”=>使用groupby('ID')

“优先于'High'值而不是'Low'或'Mod',然后从Val列中的'High'行中选择'Num'列中值较高的行。 “ =>按Val排序,然后按Num(降序)排序,然后取最高值。