【问题标题】:Counting number of certain values in each column using pandas and collections使用熊猫和集合计算每列中某些值的数量
【发布时间】:2020-12-15 22:48:46
【问题描述】:

我有一个包含 9 列和 6 行的 txt 文件。前 8 列是以下值之一:“1”、“2”和“3”。我将这些列从“A”命名为“H”。我将最后一列命名为:“类”。 最后一列是名称:“HIGH”。这是txt文件(data.txt):

1,1,1,1,2,1,1,3,HIGH 
1,1,1,2,2,1,1,3,HIGH 
1,1,1,1,1,1,1,3,HIGH 
1,1,1,2,1,1,1,3,HIGH 
1,1,1,3,2,1,1,3,HIGH 
1,1,1,2,1,2,1,3,HIGH

我正在尝试计算每列中每个值的数量并打印一个应该包含 3 个组件的列表,包括该列中“1”、“2”和“3”值的数量分别。例如,在第一列(例如 A)中,所有值都是“1”。我希望得到:A : [6,0,0]。对于所有值为“3”的第 8 列(例如 H),我希望得到:H : [0,0,6] 或第四列(例如 D)我有两个“ 1”,三个“2”和一个“3”。所以我期望:D:[2,3,1]。我尝试使用 pandas 和 collection 来完成它。这是我所做的:

import pandas as pd
from collections import Counter

df = pd.read_csv('data.txt')
df.columns = ['A','B','C','D','E','F','G','H','class']

X = df.ix[:, 0:8].values
y = df.ix[:, 8].values

deg = ['HIGH']

names = ['A','B','C','D','E','F','G','H']

for j in range(0, 8):

    freqs = Counter(X[y == deg[0], j])
    print(names[j],':',list(freqs.values()))

上述代码的输出是空列表。这是它返回的内容:

A : []
B : []
C : []
D : []
E : []
F : []
G : []
H : []

如何修改上面的代码来得到我想要的? 谢谢!

【问题讨论】:

    标签: python-3.x pandas collections counter


    【解决方案1】:

    定义如下函数:

    def cntInts(col):
        vc = col.value_counts()
        return [ vc.get(i, 0) for i in range(1,4) ]
    

    然后应用它并打印结果:

    for k, v in df.loc[:, 'A':'H'].apply(cntInts).iteritems():
        print(f'{k}: {v}')
    

    对于您的数据样本,我得到了:

    A: [6, 0, 0]
    B: [6, 0, 0]
    C: [6, 0, 0]
    D: [2, 3, 1]
    E: [3, 3, 0]
    F: [5, 1, 0]
    G: [6, 0, 0]
    H: [0, 0, 6]
    

    或者只调用一下就足够了:

    df.loc[:, 'A':'H'].apply(cntInts)
    

    这一次的结果是一个系列,打印出来的结果是:

    A    [6, 0, 0]
    B    [6, 0, 0]
    C    [6, 0, 0]
    D    [2, 3, 1]
    E    [3, 3, 0]
    F    [5, 1, 0]
    G    [6, 0, 0]
    H    [0, 0, 6]
    dtype: object
    

    编辑

    根据您的 cmets,我认为您的数据有问题。

    追查实际原因:

    1. 定义一个字符串变量:

       txt = '''1,1,1,1,2,1,1,3,HIGH 
       1,1,1,2,2,1,1,3,HIGH 
       1,1,1,1,1,1,1,3,HIGH 
       1,1,1,2,1,1,1,3,HIGH 
       1,1,1,3,2,1,1,3,HIGH 
       1,1,1,2,1,2,1,3,HIGH'''
      
    2. 运行:

       import io
       df = pd.read_csv(io.StringIO(txt), names=['A','B','C','D','E','F','G','H','class'])
      
    3. 在我的数据上运行我的代码。结果应该和预期的一样。

    4. 然后读取你的输入文件(也进入df)并再次运行我的代码。 您的数据和我的数据之间可能存在一些差异。 特别是在您的输入文件中寻找任何额外的空格, 还要检查列类型(在 read_csv 之后)。

    【讨论】:

    • 感谢您的建议。它适用于除第一列(例如 A)之外的所有列。它返回:A:[1,0,0]。在我使用的代码的开头: df = pd.read_csv('data.txt',header=None) 这可能是问题所在。知道为什么会这样吗?
    • 如果您使用 header=None 阅读,那么您将获得作为连续数字的列名(0 到 8)。要获取预期的列名,请将它们传递到 names 参数中,然后不需要 header 参数。像 df = pd.read_csv('data.txt', names=['A','B','C','D','E','F','G','H ','class']).
    • 我按照你的建议做了,但我在 A 列得到了相同的结果: import pandas as pd df = pd.read_csv('data.txt', names=['A','B', 'C','D','E','F','G','H','class']) def cntInts(col): vc = col.value_counts() return [ vc.get(i, 0) for i in range(1,4) ] for k, v in df.loc[:, 'A':'H'].apply(cntInts).iteritems(): print(f'{k}: { v}')
    • 你为什么对 A: [1,0,0] 感到惊讶? A 列仅包含 1 的值(其中 6 个),因此这只是预期的结果。
    • 对不起,它应该是该列中“1”值的数量。我的意思是我应该得到: A: [6,0,0] NOT [1,0,0] !每列的列表包含 3 个组件。第一个是“1”值的数量,第二个是“2”值的数量,第三个是该列中“3”值的数量
    【解决方案2】:

    在 python 中工作,因为你的最终结果是一个字典:

    from string import ascii_uppercase
    from collections import Counter, defaultdict
    from itertools import chain, product
    import csv    
    
    d = defaultdict(list)
    fieldnames = ascii_uppercase[:9]
    # test.csv is your file above
    with open('test.csv') as csvfile:    
        reader = csv.DictReader(csvfile, fieldnames = list(fieldnames))
        reader = Counter(chain.from_iterable(row.items() for row in reader))
        for col, value in product(fieldnames, ("1","2","3")):
            if col != fieldnames[-1]:
                d[col].append(reader.get((col,value), 0))      
    

    打印(d)

    defaultdict(list,
                {'A': [6, 0, 0],
                 'B': [6, 0, 0],
                 'C': [6, 0, 0],
                 'D': [2, 3, 1],
                 'E': [3, 3, 0],
                 'F': [5, 1, 0],
                 'G': [6, 0, 0],
                 'H': [0, 0, 6]})
    

    【讨论】:

      【解决方案3】:

      使用集合的解决方案是选择没有最后一个的所有列,将Counter 转换为Series,因此输出为DataFrame,将缺失值替换为DataFrame.fillna,将值转换为整数并通过DataFrame.to_dict 将最后一个到字典:

      from collections import Counter
      
      d = (df.iloc[:, :-1].apply(lambda x: pd.Series(Counter(x)))
             .fillna(0)
             .astype(int)
             .to_dict("list"))
      print (d)
      {'A': [6, 0, 0], 'B': [6, 0, 0], 
       'C': [6, 0, 0], 'D': [1, 4, 1], 
       'E': [3, 3, 0], 'F': [5, 1, 0], 
       'G': [6, 0, 0], 'H': [0, 0, 6]}
      

      只有带有pandas.value_counts 的熊猫解决方案:

      d = (df.iloc[:, :-1].apply(pd.value_counts)
             .fillna(0)
             .astype(int)
             .to_dict("list"))
      print (d)
      {'A': [6, 0, 0], 'B': [6, 0, 0],
       'C': [6, 0, 0], 'D': [2, 3, 1], 
       'E': [3, 3, 0], 'F': [5, 1, 0], 
       'G': [6, 0, 0], 'H': [0, 0, 6]}
      

      【讨论】:

        【解决方案4】:

        使用pandas.Series.value_counts

        df.loc[:, :"H"].apply(pd.Series.value_counts).fillna(0).to_dict("l")
        

        输出:

        {'A': [6.0, 0.0, 0.0],
         'B': [6.0, 0.0, 0.0],
         'C': [6.0, 0.0, 0.0],
         'D': [2, 3, 1],
         'E': [3.0, 3.0, 0.0],
         'F': [5.0, 1.0, 0.0],
         'G': [6.0, 0.0, 0.0],
         'H': [0.0, 0.0, 6.0]}
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-08-03
          • 1970-01-01
          • 1970-01-01
          • 2018-07-17
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多