熊猫:使用混合数据类型对多级列进行排序

时间:2020-11-03 06:08:24

标签: python python-3.x pandas dataframe sorting

这是我的previous问题的扩展。

下面是df:

In [28]: df = pd.DataFrame({'A':['a','b:all:c','all:1:3','c','d','e'], 'D':[{"value": '126', "perc": None, "unit": None}, {"value": 324, "perc": None, "unit": None}, {"value": 'N/A', "perc": None, "unit": None}, {}, {"value": '100', "perc": None, "unit":
    ...:  None}, np.nan]})
    ...: 
In [34]: df.columns = pd.MultiIndex.from_product([df.columns, ['E']])

In [35]: df
Out[35]: 
         A                                             D
         E                                             E
0        a  {'value': '126', 'perc': None, 'unit': None}
1  b:all:c    {'value': 324, 'perc': None, 'unit': None}
2  all:1:3  {'value': 'N/A', 'perc': None, 'unit': None}
3        c                                            {}
4        d  {'value': '100', 'perc': None, 'unit': None}
5        e                                           NaN

我需要根据字典中的值键对索引为(D,E)的多级列进行降序排序。

但是我需要保留所有先前列中包含子字符串all的行。

如您所见,值键可以具有混合数据类型的值,例如int,字符串或空值(例如{}或NaN)。

N / A和Nan值应始终在排序后最后显示(升序和降序)。

因此,预期输出将为:

In [38]: df1 = pd.DataFrame({'A':['a','b:all:c','all:1:3','d','c','e'], 'D':[{"value": '126', "perc": None, "unit": None}, {"value": 324, "perc": None, "unit": None}, {"value": 'N/A', "perc": None, "unit": None}, {"value": '100', "perc": None, "unit": No
    ...: ne},{}, np.nan]})
    ...: 

In [40]: df1.columns = pd.MultiIndex.from_product([df1.columns, ['E']])

In [41]: df1
Out[41]: 
         A                                             D
         E                                             E
0        a  {'value': '126', 'perc': None, 'unit': None}
1  b:all:c    {'value': 324, 'perc': None, 'unit': None}
2  all:1:3  {'value': 'N/A', 'perc': None, 'unit': None}
3        d  {'value': '100', 'perc': None, 'unit': None}
4        c                                            {}
5        e                                           NaN

1 个答案:

答案 0 :(得分:1)

想法是先查找all列之前(D, E)的所有行以进行屏蔽,然后将不匹配的行过滤到df1,对用于映射原始索引值的索引值进行排序和提取,并最后排序:

print (df)
mask = (df.iloc[:, : df.columns.get_loc(('D','E'))]
          .apply(lambda x: x.astype(str).str.contains('all'))
          .any(axis=1))
print (mask)
0    False
1     True
2     True
3    False
4    False
5    False
dtype: bool

df1 = df[~mask].copy()
df1['tmp'] = pd.to_numeric(df1[('D','E')].str.get('value'), errors='coerce')
idx = df1.sort_values('tmp', ascending=False).index
print (idx)
Int64Index([0, 4, 3, 5], dtype='int64')

d = dict(zip(df.index[~mask], idx))
print (d)
{0: 0, 3: 4, 4: 3, 5: 5}

df = df.set_index(df.rename(d).index).sort_index()
print (df)
         A                                             D
         E                                             E
0        a  {'value': '126', 'perc': None, 'unit': None}
1  b:all:c    {'value': 324, 'perc': None, 'unit': None}
2  all:1:3  {'value': 'N/A', 'perc': None, 'unit': None
3        d  {'value': '100', 'perc': None, 'unit': None}
4        c                                            {}
5        e                                           NaN