【问题标题】:How to filter a set of rows according to an indexed position?如何根据索引位置过滤一组行?
【发布时间】:2021-02-20 19:08:24
【问题描述】:

我被困在如何根据索引位置过滤掉一组行。为了更清楚,让我们有一个虚拟问题,假设我有一个用户有多个配置文件的数据框,例如 df1 我有三个用户 John、Johnny 和 Ben 有他们的多个配置文件..

df1 = pd.DataFrame({"user": ["Peter (1)", "Peter (2)", "Peter (3)","John (1)","John (2)","John (3)","Johnny (1)","Johnny (2)"], "value": [1, 3, 3, 1, 6, 3, 4, 1]}, )

我根据值对 df1 进行排序并重新索引它

df1=df1.sort_values(by='value', ascending=False)

df1.index=[0, 1, 2, 3, 4, 5, 6, 7]

df1 是这样的

现在我被困在如何过滤出具有第一个索引值的用户(在本例中为 John)的行,让我们说新数据框 df2,以及过滤掉第二个索引用户(在本例中为 Johnny)的行新数据框 df3 预期的 df2 应该是这样的

df3 应该如下所示

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    对数据框进行排序后,您可以使用str.split 拆分user 列中的字符串以创建分组key,然后group 此分组键上的数据框和每个user 创建的子组user -> dataframedict 理解中的映射:

    key = df1['user'].str.split().str[0]
    dct = {user:grp.reset_index(drop=True) for user, grp in df1.groupby(key)}
    

    现在要访问与user 对应的数据框,我们可以简单地在字典中查找:

    >>> dct['John']
    
           user  value
    0  John (2)      6
    1  John (3)      3
    2  John (1)      1
    
    >>> dct['Peter']
    
            user  value
    0  Peter (2)      3
    1  Peter (3)      3
    2  Peter (1)      1
    
    >>> dct['Johnny']
    
             user  value
    0  Johnny (1)      4
    1  Johnny (2)      1
    

    【讨论】:

    • key 是一个不在df1 中的系列,但它被用于df1 的分组...它有效:) ...只是想知道它是如何工作的?因为它们的索引相同
    • 哇,它有效!我投票支持这个解决方案,因为从我的角度来看,它是最值得回忆的。
    • 如果有 100 个或更多的用户拥有多个配置文件,这个解决方案似乎很困难
    • @Naveen groupby 方法可以用于 group 数据帧/系列 Series/ndarray/or even a list 即使它不存在于数据帧中。如果传递了一个系列,它的索引首先对齐..如果是ndarray or listndarray or list 的长度必须与需要分组的数据帧/系列的长度匹配..
    • @ArunMenon 你能详细解释一下为什么你认为这很困难吗?
    【解决方案2】:

    您可以获取第一个索引值并将其拆分并排除最后一项(假设用户名可能有括号),然后在整个数据框中搜索该特定列的值。 例如:

    firstIndexUser = df1['user'].str.split('(').str[:-1].str.join('(').iloc[0]
    

    这个 firstIndexUser 的值为 'John' 现在您可以与整个数据框进行比较以获得您的 df2

    df2 = df1[df1['user'].str.split('(').str[:-1].str.join('(')==firstIndexUser]
    

    输出如下:

    >>df2
           user  value
    0  John (2)      6
    4  John (3)      3
    6  John (1)      1
    

    如果需要,您可以重置 df2 的索引

    >>df2.reset_index(drop=True, inplace=True)
    >>df2
           user  value
    0  John (2)      6
    1  John (3)      3
    2  John (1)      1
    

    您可以对您的 df3 采用类似的方法

    【讨论】:

    • 看起来很有趣..我在执行 firstIndexUser AttributeError 时遇到错误:'str' object has no attribute 'str'
    • 你一定是搞错了,str方法适用于pandas系列,不适用于字符串变量。我认为您正在做一些类似 firstIndexUser.str 的事情,这会导致该错误。
    • 没有 ..我能够执行 firstIndexUser=df1.iloc[0]['user'] ..它给了 John (2) ...但是当我执行 firstIndexUser = df1.iloc[ 0]['user'].str.split('(').str[:-1].str.join('(') ..它给出了属性错误
    • 哦,是的,我明白了。只需将 .iloc[0] 放在 firstIndexUser 中表达式的最后一个。我已经编辑了您现在可以查看的答案。
    • 乐于助人。
    【解决方案3】:
    df1 = pd.DataFrame({"user": ["Peter (1)", "Peter (2)", "Peter (3)","John (1)","John (2)","John (3)","Johnny (1)","Johnny (2)"], "value": [1, 3, 3, 1, 6, 3, 4, 1]}, )
    
    df1=df1.sort_values(by='value', ascending=False)
    
    cols = df1.columns.tolist()
    df1['name'] = df1['user'].replace(r'\s\(\d\)','',regex=True)
    grp = df1.groupby(by=['name'])
    dataframes = [grp.get_group(x)[cols] for x in grp.groups]
    
    df2, df3 = dataframes[:2]  # as mentioned, we are interested just in first two users
    

    df2:

           user  value
    3  John (1)      1
    4  John (2)      6
    5  John (3)      3     
    

    df3:

           user    value
    6  Johnny (1)      4
    7  Johnny (2)      1    
    

    【讨论】:

    • 我的观点是因为约翰被索引在第一位(因为价值很高),我只想过滤第一个和第二个索引值..peter 不应该来
    • @ArunMenon 明白了。我稍微修改了代码。
    【解决方案4】:

    第一行为名称添加一列
    创建一个字典,将每个条目作为数据框,键作为唯一名称

    df1['name']=[x.split(' ')[0] for x in df1['user']]
    for nam in list(df1.name.value_counts().index):
        dct[nam] = df1[df1['name']==nam][['user','value']].reset_index(drop=True)
    

    【讨论】:

    • 实际上,我只需要为第一个(John)和第二个(Johnny)索引的用户创建一个数据框。在我的实际需求中,我有 100 多个用户,每个用户都有多个配置文件,所以为每个配置文件创建字典不是我所赞成的..尽管如此我喜欢这种方法!
    【解决方案5】:

    我相信一个好方法是首先在字典中获取您的键值对(使用 dictzip,然后使用 loc 过滤索引位置。这样可以确保您始终可以通过明确说明索引位置来取回您所需的dataframe

    k = dict(zip(df.index,df['user'].apply(lambda x: x.split(' ')[0])))
    
    {0: 'John',
     1: 'Johny',
     2: 'Peter',
     3: 'Peter',
     4: 'John',
     5: 'Peter',
     6: 'John',
     7: 'Johny'}
    
    # position 0
    k[0]
    'John'
    
    # position 1
    k[1]
    'Johny'
    
    # position 2
    k[2]
    'Peter'
    

    使用index 位置01 将John 和Johny 分成单独的df

    # John (indexed 0)
    df1 = df.loc[df['user'].str.split().str[0] == k[0]] # index position 0
    
    Out[31]: 
           user  value
    0  John (2)      6
    4  John (3)      3
    6  John (1)      1
    
    # Johny (indexed 1)
    df2 =  df.loc[df['user'].str.split().str[0] == k[1]] # index position 1
    
    Out[32]: 
            user  value
    1  Johny (1)      4
    7  Johny (2)      1
    

    【讨论】:

    • 这也是一个很好的解决方案..非常简单!!
    【解决方案6】:

    使用python基本功能List Comprehension我们可以列出我们想要的数据。

    list_john = [i for i in df1.user if i[0:5] == f'John '];
    list_johnny = [i for i in df1.user if i[0:5] == f'Johnny'];
    

    然后使用上面的列表创建两个 df 对象:

    pd.DataFrame(list_john)
    pd.DataFrame(list_johnny)
    

    【讨论】:

      猜你喜欢
      • 2014-03-04
      • 1970-01-01
      • 2013-11-10
      • 1970-01-01
      • 1970-01-01
      • 2021-05-06
      • 2021-05-06
      • 2014-06-20
      • 1970-01-01
      相关资源
      最近更新 更多