如何以特定顺序在两个(或更多)不同的列上对熊猫数据框进行排序

时间:2020-05-31 00:41:52

标签: python pandas dataframe data-manipulation

注意

df2是只能在此处使用的 事物-使用dfdf1将使用不可能的数据。数据以df2的形式接收,它希望被操纵为df1的形式。 df1df都不能用作解决方案的一部分(因为df1 是解决方案)。


设置测试数据

这只是该帖子的设置。

# sample data
reps = {1: "dog", 2: "ant", 3: "cat", 6: "orange", 7: "apple", 8: "grape"}
df = pd.DataFrame(
    {"one": [1, 1, 1, 2, 2, 2, 3, 3, 3], "two": [6, 7, 8, 6, 7, 8, 6, 7, 8]}
)
df = df.replace(reps).copy()
df1 = df.copy()
df2 = df.sample(frac=1, random_state=1).replace(reps).reset_index(drop=True)

问题

排序df1,使其与df1的顺序相同。

df2

   one     two
0  cat   grape
1  dog   grape
2  cat  orange
3  cat   apple
4  dog   apple
5  dog  orange
6  ant   apple
7  ant  orange
8  ant   grape

df1

   one     two
0  dog  orange
1  dog   apple
2  dog   grape
3  ant  orange
4  ant   apple
5  ant   grape
6  cat  orange
7  cat   apple
8  cat   grape

条件

您不能使用df1作为解决方案的一部分,或者df的数据是df2,并且 它需要按照df1的顺序进行排序。

尝试

我尝试使用pd.Categorical,但无法使某些工作正常。

order_one = ["dog", "ant", "cat"]
order_two = ["orange", "apple", "grape"]

df2 = (
    df2.groupby(["two"])
    .apply(lambda a: a.iloc[pd.Categorical(a["one"], order_one).argsort()])
    .reset_index(drop=True)
)

df2 = (
    df2.groupby(["one"])
    .apply(lambda a: a.iloc[pd.Categorical(a["two"], order_two).argsort()])
    .reset_index(drop=True)
)

编辑

解决方案应完全基于df2df1只是测试数据的一部分,并演示如何对df2进行排序。使用df1的解决方案不可行,因为这是对df2进行排序的结果,我不能将其用作解决方案的一部分

2 个答案:

答案 0 :(得分:2)

让我们尝试pd.Categorical

df2.one=pd.Categorical(df2.one,categories=df1.one.unique())
df2.two=pd.Categorical(df2.two,categories=df1.two.unique())
df2=df2.sort_values(['one','two'])
df2
   one     two
5  dog  orange
4  dog   apple
1  dog   grape
7  ant  orange
6  ant   apple
8  ant   grape
2  cat  orange
3  cat   apple
0  cat   grape

使其生效

def yourfunc(x,y):
...     for c in x.columns : 
...         x[c]=pd.Categorical(x[c],categories=y[c].unique())
...     return x.sort_values(x.columns.tolist())
... 
yourfunc(df1,df2)
   one     two
8  cat   grape
6  cat  orange
7  cat   apple
2  dog   grape
0  dog  orange
1  dog   apple
5  ant   grape
3  ant  orange
4  ant   apple

更新

order_fruit = ["orange", "apple", "grape"]
order_animals = ["dog", "ant", "cat"]
def yourfunc(x,y):
...      for c, self in zip(x.columns,y) : 
...          x[c]=pd.Categorical(x[c],categories=self)
...      return x.sort_values(x.columns.tolist())
... 
yourfunc(df2,[order_animals,order_fruit])
   one     two
5  dog  orange
4  dog   apple
1  dog   grape
7  ant  orange
6  ant   apple
8  ant   grape
2  cat  orange
3  cat   apple
0  cat   grape

答案 1 :(得分:1)

从技术上讲,您没有排序,因为顺序不是升序,降序或字母顺序。您要使用某些用户指定的顺序订购df_2。为此,您可以根据自定义顺序生成数字索引,然后按此顺序进行排序。

import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;

import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.core.importer.ImportOption;
import org.junit.jupiter.api.Test;

class ArchTest {

    @Test
    void servicesAndRepositoriesShouldNotDependOnWebLayer() {
        JavaClasses importedClasses = new ClassFileImporter()
            .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
            .importPackages("com.learning.springboot");

        noClasses()
            .that()
            .resideInAnyPackage("com.learning.springboot.service..")
            .or()
            .resideInAnyPackage("com.learning.springboot.repository..")
            .should()
            .dependOnClassesThat()
            .resideInAnyPackage("..com.learning.springboot.web..")
            .because("Services and repositories should not depend on web layer")
            .check(importedClasses);
    }
}

这应该使df_2保持您要查找的顺序。