如何在 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】:crosstab
和 melt
实际上有一个相当有趣和先进的方法来解决这个问题
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 数据框中一次创建两个新字段