如何在熊猫的多列和多行中选择条件条件的值(最佳做法)

时间:2019-08-22 15:24:31

标签: python pandas

我想基于多行列上的条件从熊猫数据框中的一列中选择(唯一)值。考虑以下示例数据帧:

df = pd.DataFrame({'Developer': ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'C'],
                   'Language': ['Java', 'Python', 'Python', 'Java', 'Python', 'Python', 'Java', 'Python', 'C++'],
                   'Skill_Level': [1, 3, 3, 3, 2, 3, 3, 1, 3],
                   'Version': ["x.x", "2.x", "3.x", "x.x", "2.x", "3.x", "x.x", "3.x", "x.x"]
                   })
    Developer    Language    Skill_Level    Version
0           A        Java              1        x.x
1           A      Python              3        2.x
2           A      Python              3        3.x
3           B        Java              3        x.x
4           B      Python              2        2.x
5           B      Python              3        3.x
6           C        Java              3        x.x
7           C      Python              1        3.x
8           C         C++              3        x.x

现在,我想找到所有了解Java且技能水平至少为3的开发人员,并且也知道Python(无论版本如何)至少具有2级的技能。

我现在解决该问题的方法是,根据Java条件选择一组,然后根据Python条件选择另一组,然后进行内部合并以获取符合所有条件的开发人员:

result_java_df = df[(df["Language"] == "Java") & (df["Skill_Level"] >= 3)][["Developer"]]
result_python_df = df[(df["Language"] == "Python") & (df["Skill_Level"] >= 2)][["Developer"]]
result_df = result_java_df.merge(result_python_df, on="Developer")
result_df = result_df.drop_duplicates()
    Developer
0   B

是否有更“优雅”的方式来做到这一点?我感觉自己在忽略水木清华。特别是如果我想基于更多基于行的条件进行选择(例如选择以某种技能水平了解四种语言的开发人员),这将变得很复杂,当然可以证明编写处理此类选择的函数是合理的。因此,我想知道熊猫是否以某种方式支持此功能,而我只是没有找到该功能。

2 个答案:

答案 0 :(得分:4)

我跑步时

    qualified=    df.groupby("Developer").apply(
        lambda x: 
            any(
                    (x.Language == "Java") & 
                    (x.Skill_Level >=3)
                ) & 
            any(
                    (x.Language == "Python") & 
                    (x.Skill_Level >= 2))
        )

我知道了

Developer
A    False
B     True
C    False
dtype: bool

然后可以使用各种方法(例如

)进行子集化
[developer for developer,status in qualified.items() if status]

(返回列表)

qualified[qualified]

(返回系列)

如果要使其更通用,可以执行以下操作:

minimum_skill_levels = {"Java":3,
                    "Python":2}

qualified=    df.groupby("Developer").apply(
        lambda x: 
            all([any(
                    (x.Language == Language)&
                    (x.Skill_Level >= Skill_Level)
                    )
                 for Language, Skill_Level in minimum_skill_levels.items()
                 ])
        )

答案 1 :(得分:0)

好吧,多亏了pandas的多索引功能,我还是可以正常工作,但从正面来看,它还不错,没有循环,没有lambda。我认为这是最佳做法,因为它使用切片和索引,并且一旦数据正确格式化(正确的索引和列),性能也应该会更好。

import pandas as pd

idx = pd.IndexSlice


df_p = df.pivot_table(index = 'Language', columns = 'Developer')

java = df_p.loc['Java'] >= 3

python = df_p.loc['Python'] >= 2

df_p.loc[:, idx[:, java & python]]

将适当的开发者输出为一列

df_p.loc[:, idx[:, java & python]]['Skill_Level'].columns.tolist() 

如果以后需要它们,则将它们列出在列表中。