Pandas Dataframe - 过滤数据以获得唯一的最大和最小行

时间:2018-03-03 21:21:29

标签: python pandas dataframe replace duplicates

我的数据框包含以下4个数字列:['ID', 'A', 'B', 'C']

我想过滤数据以获取数据框,其中,对于列ID中的每个唯一值,我得到行不重复,它们对应于列A的最大值和最小值,B,C

下图显示了输入数据帧和所需的输出数据帧。

我还报告了df#2以蓝色突出显示与简单最大/最小搜索不同的行。因为其中一些是重复的,然后应该用第二个/第三个..最大/最小行替换。

例如,df2的第三行替换为包含B(63)列中第二个最大值的行,该列是df1的第三行。同样,df2的第四行替换为df1的第四行,因为它包含列B的第二个最小值(-75)

此外:

  1. 列数可以更改,这意味着更大的问题,我可以拥有的列数多于['A']['B']['C']

  2. ID的行数可以更改

  3. df3的总行数应为UniqueID*Columns*2

  4. 目前我只能使用idxmax() / idxmin()然后使用reindex数据框来获取df2

    df1 = pd.DataFrame({'ID': pd.Series([1. ,1. , 1. , 1  , 2 , 2, 2,2,2,2,2]),
       'A': pd.Series([100. , -97. , -56. , 69  , 150 , -120, 30,92,35,-41,-75]),
       'B': pd.Series([99., -96., 63., -75., 140, -110, 91,-62,76,10,2]),
       'C': pd.Series([98., -95., -45., 39., 130, -100,90,-50,70,-17,33])})
    
    
    
    max = df1.groupby('ID')['A', 'B','C'].idxmax().as_matrix()
    min = df1.groupby('ID')['A', 'B','C'].idxmin().as_matrix()
    
    index = []
    for i in range(len(max)):
        for j in range(len(max[0])):
            index.append(max[i][j])
            index.append(min[i][j])
    
    df2 = df1.reindex(index)
    

    我怎样才能获得df3?数据帧很大(> 1M行),所以我不仅需要一个有效的解决方案,而且我还需要一个有效的解决方案。

2 个答案:

答案 0 :(得分:3)

有一种快速方法可以只保留唯一的行:df3 = df1.reindex(set(index))。这将仅保留第一个最大值。现在,您可以删除df1之后df1 = df1.drop(df3.index)的第一个最大值的行,并根据需要重复整个过程(例如3次)

import pandas as pd
df1 = pd.DataFrame({'ID': pd.Series([1. ,1. , 1. , 1  , 2 , 2, 2,2,2,2,2]),
   'A': pd.Series([100. , -97. , -56. , 69  , 150 , -120, 30,92,35,-41,-75]),
   'B': pd.Series([99., -96., 63., -75., 140, -110, 91,-62,76,10,2]),
   'C': pd.Series([98., -95., -45., 39., 130, -100,90,-50,70,-17,33])})

def keep_minmax(df1):
    df_max = df1.groupby('ID')['A', 'B','C'].idxmax().as_matrix()
    df_min = df1.groupby('ID')['A', 'B','C'].idxmin().as_matrix()
    index = []
    for i in range(len(df_max)):
        for j in range(len(df_max[0])):
            index.append(df_max[i][j])
            index.append(df_min[i][j])
    return df1.reindex(set(index))

df = df1.copy()
results = []
for i in range(3):
    result = keep_minmax(df)
    result['order'] = i + 1
    results.append(result)
    df = df.drop(result.index)
df3 = pd.concat(results).sort_values(['ID', 'order'])
print(df3)

将输出

        A      B      C   ID  order
0   100.0   99.0   98.0  1.0      1
1   -97.0  -96.0  -95.0  1.0      1
2   -56.0   63.0  -45.0  1.0      2
3    69.0  -75.0   39.0  1.0      2
4   150.0  140.0  130.0  2.0      1
5  -120.0 -110.0 -100.0  2.0      1
6    30.0   91.0   90.0  2.0      2
7    92.0  -62.0  -50.0  2.0      2
10  -75.0    2.0   33.0  2.0      2
8    35.0   76.0   70.0  2.0      3
9   -41.0   10.0  -17.0  2.0      3

您可以看到ID=1没有第三个订单,因为df1中的所有行都已用完,您必须包含重复的行(如示例所示) df3)。 你真的想要吗?

我问这个问题,因为从你的帖子中我不清楚在模棱两可的情况下该做什么:如果不同的行对应k'不同列中的最佳值,或者这个k本身对于不同的列是不同的。例如,您会从df3生成什么样的df,为什么?为简单起见,我们只提取最大值:

   A  B   ID
0  2  1  1.0
1  3  2  1.0
2  1  0  1.0
3  0  3  1.0

我的算法(仅查看最大值)将返回

   A  B   ID  order
1  3  2  1.0      1
3  0  3  1.0      1
0  2  1  1.0      2
2  1  0  1.0      3

请注意,第2行和第2行的行(2,1)包含在2&n;顺序中,因为它更高。

您是否有任何其他建议如何处理这种含糊之处?

答案 1 :(得分:2)

使用辅助功能:

def filter_min_and_max(x):
    y = pd.DataFrame()
    for col in x.columns:
        if col != "ID":
            y[col] = [max(x[col]), min(x[col])]
            # for OP's comment
            y[col] = [val_1 for val in zip(x[col].nlargest(3).tolist(), x[col].nsmallest(3).tolist()) for val_1 in val]
    return y

df1.groupby("ID").apply(lambda x: filter_min_and_max(x)).reset_index().drop(["level_1"], axis=1)