【问题标题】:sum values of columns starting with the same string in pandas dataframe熊猫数据框中以相同字符串开头的列的总和值
【发布时间】:2016-03-02 12:09:33
【问题描述】:

我有一个包含大约 100 列的数据框,如下所示:

   Id  Economics-1  English-107  English-2  History-3  Economics-zz  Economics-2  \
0  56          1            1          0        1       0           0   
1  11          0            0          0        0       1           0   
2   6          0            0          1        0       0           1   
3  43          0            0          0        1       0           1   
4  14          0            1          0        0       1           0   

   Histo      Economics-51      Literature-re         Literatureu4  
0           1            0           1                0  
1           0            0           0                1  
2           0            0           0                0  
3           0            1           1                0  
4           1            0           0                0  

我的目标是只保留全局类别(英语、历史、文学),并在此数据框中分别写出它们组件的值的总和。例如,“English”将是“English-107”和“English-2”之和:

    Id  Economics      English    History  Literature  
0  56          1            1          2        1                     
1  11          1            0          0        1                    
2   6          0            1          1        0                     
3  43          2            0          1        1                     
4  14          0            1          1        0          

为此,我尝试了两种方法。第一种方法:

df = pd.read_csv(file_path, sep='\t')
df['History'] = df.loc[df[df.columns[pd.Series(df.columns).str.startswith('History')]].sum(axes=1)]

第二种方法:

df = pd.read_csv(file_path, sep='\t')
filter_col = [col for col in list(df) if col.startswith('History')]
df['History'] = 0 # initialize value, otherwise throws KeyError
for c in df[filter_col]:
    df['History'] = df[filter_col].sum(axes=1)
    print df['History', df[filter_col]]

但是,两者都给出了错误:

TypeError: 'DataFrame' objects are mutable, thus they cannot be hashed

我的问题是:如何调试此错误,或者是否有其他解决方案可以解决我的问题。请注意,我有一个相当大的数据框,大约有 100 列和 400000 行,所以我正在寻找一个优化的解决方案,比如在 pandas 中使用loc

【问题讨论】:

    标签: python pandas dataframe startswith


    【解决方案1】:

    您可以使用这些来创建以特定名称开头的列的总和,

    df['Economics']= df[list(df.filter(regex='Economics'))].sum(axis=1)
    

    【讨论】:

    • 这是一个更优雅的解决方案。感谢您为这篇已有 5 年历史的帖子做出贡献
    【解决方案2】:

    我建议您做一些不同的事情,即执行转置,按行(您的原始列)的前缀分组,求和,然后再次转置。

    考虑以下几点:

    df = pd.DataFrame({
            'a_a': [1, 2, 3, 4],
            'a_b': [2, 3, 4, 5],
            'b_a': [1, 2, 3, 4],
            'b_b': [2, 3, 4, 5],
        })
    

    现在

    [s.split('_')[0] for s in df.T.index.values]
    

    是列的前缀。所以

    >>> df.T.groupby([s.split('_')[0] for s in df.T.index.values]).sum().T
        a   b
    0   3   3
    1   5   5
    2   7   7
    3   9   9
    

    做你想做的。

    在您的情况下,请确保使用 '-' 字符进行拆分。

    【讨论】:

    • groupby 接受一个axis=1 参数,所以像df.groupby(df.columns.str.split("-").str[0],axis=1).sum() 这样的东西可能会起作用。 (Histo 列让我想知道我们是否必须使用不同的分组条件,但你明白了。)
    • 除了这个很好的答案之外,如果列名包含多个 _ 字符,还可以在此处合并 RegEx:import re 然后 [re.split('_\d{2}', s)[0] for s in df.T.index.values]
    【解决方案3】:

    运用帝斯曼的绝妙理念:

    from __future__ import print_function
    
    import pandas as pd
    
    categories = set(['Economics', 'English', 'Histo', 'Literature'])
    
    def correct_categories(cols):
        return [cat for col in cols for cat in categories if col.startswith(cat)]    
    
    df = pd.read_csv('data.csv', sep=r'\s+', index_col='Id')
    
    #print(df)
    print(df.groupby(correct_categories(df.columns),axis=1).sum())
    

    输出:

        Economics  English  Histo  Literature
    Id
    56          1        1      2           1
    11          1        0      0           1
    6           1        1      0           0
    43          2        0      1           1
    14          1        1      1           0
    

    这是另一个版本,它解决了“Histo/History”问题..

    from __future__ import print_function
    
    import pandas as pd
    
    #categories = set(['Economics', 'English', 'Histo', 'Literature'])
    
    #
    # mapping: common starting pattern: desired name
    #
    categories = {
        'Histo': 'History',
        'Economics': 'Economics',
        'English': 'English',
        'Literature': 'Literature'
    }
    
    def correct_categories(cols):
        return [categories[cat] for col in cols for cat in categories.keys() if col.startswith(cat)]
    
    df = pd.read_csv('data.csv', sep=r'\s+', index_col='Id')
    #print(df.columns, len(df.columns))
    #print(correct_categories(df.columns), len(correct_categories(df.columns)))
    #print(df.groupby(pd.Index(correct_categories(df.columns)),axis=1).sum())
    
    rslt = df.groupby(correct_categories(df.columns),axis=1).sum()
    print(rslt)
    print('History\n', rslt['History'])
    

    输出:

        Economics  English  History  Literature
    Id
    56          1        1        2           1
    11          1        0        0           1
    6           1        1        0           0
    43          2        0        1           1
    14          1        1        1           0
    History
     Id
    56    2
    11    0
    6     0
    43    1
    14    1
    Name: History, dtype: int64
    

    PS 您可能希望将缺少的类别添加到 categories 地图/字典

    【讨论】:

    • 感谢您的回答,很棒的解决方案,但我在访问列时遇到问题:使用您的方法我总是遇到 keyError,即使在阅读 CSV 时尝试了不同的编码解决方案。即使我尝试使用df['History'] 我也有错误,但df.get('history') 没有错误
    • @Amanda,您的一个专栏以“Histo”作为名称,因此我决定使用“Histo”作为通用名称,否则您将同时拥有:Histo 和 History。所以试试 df['Histo'] 代替
    • @Amanda,你想用 Histo 专栏做什么?您想在结果数据框中同时包含“Histo”和“History”吗?
    • 感谢您的回答,实际上问题不仅在历史上,而且在一般的列名中:stackoverflow.com/questions/35764172/…!你的答案很好,但是当有多个数据帧应该被处理时,KeyError 会阻止一切
    猜你喜欢
    • 1970-01-01
    • 2018-08-15
    • 1970-01-01
    • 1970-01-01
    • 2016-05-17
    • 2022-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多