如何在 Pandas DataFrame 中一次获取多列的值计数?

Posted

技术标签:

【中文标题】如何在 Pandas DataFrame 中一次获取多列的值计数?【英文标题】:How to get value counts for multiple columns at once in Pandas DataFrame? 【发布时间】:2015-12-11 22:22:16 【问题描述】:

给定一个 Pandas DataFrame,它具有多个具有分类值(0 或 1)的列,是否可以方便地同时获取每列的 value_counts?

例如,假设我生成一个DataFrame如下:

import numpy as np
import pandas as pd
np.random.seed(0)
df = pd.DataFrame(np.random.randint(0, 2, (10, 4)), columns=list('abcd'))

我可以得到这样的 DataFrame:

   a  b  c  d
0  0  1  1  0
1  1  1  1  1
2  1  1  1  0
3  0  1  0  0
4  0  0  0  1
5  0  1  1  0
6  0  1  1  1
7  1  0  1  0
8  1  0  1  1
9  0  1  1  0

如何方便地获取每列的值计数并方便地获取以下内容?

   a  b  c  d
0  6  3  2  6
1  4  7  8  4

我目前的解决方案是:

pieces = []
for col in df.columns:
    tmp_series = df[col].value_counts()
    tmp_series.name = col
    pieces.append(tmp_series)
df_value_counts = pd.concat(pieces, axis=1)

但一定有更简单的方法,比如堆叠、旋转或分组?

【问题讨论】:

【参考方案1】:

用一行包裹的解决方案看起来比使用 groupby、堆叠等更简单:

pd.concat([df[column].value_counts() for column in df], axis = 1)

【讨论】:

【参考方案2】:

您可以使用 lambda 函数:

df.apply(lambda x: x.value_counts())

【讨论】:

【参考方案3】:

可以做的另一种解决方案:

df = pd.DataFrame(np.random.randint(0, 2, (10, 4)), columns=list('abcd'))
l1 = pd.Series()
for var in df.columns:
    l2 = df[var].value_counts()
    l1 = pd.concat([l1, l2], axis = 1)
l1

【讨论】:

【参考方案4】:

你也可以试试这个代码:

for i in heart.columns:
    x = heart[i].value_counts()
    print("Column name is:",i,"and it value is:",x)

【讨论】:

【参考方案5】:

选择所有分类列并一次创建一个包含所有值计数的数据框的解决方案:

df = pd.DataFrame(
'fruits': ['apple', 'mango', 'apple', 'mango', 'mango', 'pear', 'mango'],
'vegetables': ['cucumber', 'eggplant', 'tomato', 'tomato', 'tomato', 'tomato', 'pumpkin'],
'sauces': ['chili', 'chili', 'ketchup', 'ketchup', 'chili', '1000 islands', 'chili'])

cat_cols = df.select_dtypes(include=object).columns.tolist()
(pd.DataFrame(
    df[cat_cols]
    .melt(var_name='column', value_name='value')
    .value_counts())
.rename(columns=0: 'counts')
.sort_values(by=['column', 'counts']))

                            counts
column      value   
fruits      pear            1
            apple           2
            mango           4
sauces      1000 islands    1
            ketchup         2
            chili           4
vegetables  pumpkin         1
            eggplant        1
            cucumber        1
            tomato          4
            

【讨论】:

【参考方案6】:

仅获取特定列的计数:

df[['a', 'b']].apply(pd.Series.value_counts)

其中 df 是您的数据框的名称,“a”和“b”是您要计算其值的列。

【讨论】:

【参考方案7】:

这对我有用:

for column in df.columns:
     print("\n" + column)
     print(df[column].value_counts())

link to source

【讨论】:

【参考方案8】:

跑到这里看看是否有更好的方法来做我正在做的事情。事实证明,在 DataFrame 上调用 df.apply(pd.value_counts),每列都有自己的许多不同的值,这将导致相当大的性能损失。

在这种情况下,最好简单地遍历字典推导中的非数字列,并将其保留为字典:

types_to_count = "object", "category", "string"
result = 
    col: df[col].value_counts()
    for col in df.columns[df.dtypes.isin(types_to_count)]

types_to_count 的过滤有助于确保您不会尝试获取连续数据的value_counts

【讨论】:

【参考方案9】:

crosstabmelt 实际上有一个相当有趣和先进的方法来解决这个问题

df = pd.DataFrame('a': ['table', 'chair', 'chair', 'lamp', 'bed'],
                   'b': ['lamp', 'candle', 'chair', 'lamp', 'bed'],
                   'c': ['mirror', 'mirror', 'mirror', 'mirror', 'mirror'])

df

       a       b       c
0  table    lamp  mirror
1  chair  candle  mirror
2  chair   chair  mirror
3   lamp    lamp  mirror
4    bed     bed  mirror

我们可以先融化DataFrame

df1 = df.melt(var_name='columns', value_name='index')
df1

   columns   index
0        a   table
1        a   chair
2        a   chair
3        a    lamp
4        a     bed
5        b    lamp
6        b  candle
7        b   chair
8        b    lamp
9        b     bed
10       c  mirror
11       c  mirror
12       c  mirror
13       c  mirror
14       c  mirror

然后使用交叉表函数计算每一列的值。这会将数据类型保留为整数,而当前选择的答案不会是这种情况:

pd.crosstab(index=df1['index'], columns=df1['columns'])

columns  a  b  c
index           
bed      1  1  0
candle   0  1  0
chair    2  1  0
lamp     1  2  0
mirror   0  0  5
table    1  0  0

或者在一行中,将列名扩展为带有**的参数名(这是高级)

pd.crosstab(**df.melt(var_name='columns', value_name='index'))

另外,value_counts 现在是一个***函数。因此,您可以将当前选择的答案简化为以下内容:

df.apply(pd.value_counts)

【讨论】:

crosstab 很好,因为它给你留下了整数,虽然我们也可以用df.apply(pd.value_counts).fillna(0).astype(int)【参考方案10】:

只需调用apply 并传递pd.Series.value_counts

In [212]:
df = pd.DataFrame(np.random.randint(0, 2, (10, 4)), columns=list('abcd'))
df.apply(pd.Series.value_counts)
Out[212]:
   a  b  c  d
0  4  6  4  3
1  6  4  6  7

【讨论】:

如何将 dropna=False 添加到此? na 默认不会被丢弃 同样的问题,如何添加“normalize=True”? --- 抱歉找到了解决方案:df.apply(pd.Series.value_counts, normalize=True)

以上是关于如何在 Pandas DataFrame 中一次获取多列的值计数?的主要内容,如果未能解决你的问题,请参考以下文章

一次访问多个索引行时有效地迭代 pandas.DataFrame

根据其他字段的计算,在 pandas 数据框中一次创建两个新字段

Pandas 从列表列表中一次添加多个新列

如何在pandas dataframe中为新列添加值?

将Dask包的Pandas DataFrame转换为单个Dask DataFrame

Python Pandas Dataframe:如何同时将多个索引附加到列表中?