[英]pandas the frequency of occurrence of unique values in all the table by category of one column
從此開始:
df = pd.DataFrame(
{
"cat1": ["yes", "no", "yes", "no", "yes"],
"cat2": ["a", "a", "b", "b", "a"],
"cat3": ["yes", "no", "no", "yes", "no"],
"quant": [1, 2, 3, 4, 5],
}
)
示例數據框:
cat1 cat2 cat3 quant
0 yes a yes 1
1 no a no 2
2 yes b no 3
3 no b yes 4
4 yes a no 5
你可以做:
y = lambda x: x.value_counts(normalize=True).loc["yes"]
n = lambda x: x.value_counts(normalize=True).loc["no"]
df.groupby(["cat2"]).agg(
{
"cat1": [("yes", y), ("no", n)],
"cat3": [("yes", y), ("no", n)],
"quant": ["min", "max", "mean"],
}
)
結果:
cat1 cat3 quant
yes no yes no min max mean
cat2
a 0.666667 0.333333 0.333333 0.666667 1 5 2.666667
b 0.500000 0.500000 0.500000 0.500000 3 4 3.500000
這是一個更強大的版本:
from functools import partial
def agg_func(s: pd.Series, name: str):
try:
return s.value_counts(normalize=True).loc[name]
except KeyError:
return 0
yes_no_agg = [
("yes", partial(agg_func, name="yes")),
("no", partial(agg_func, name="no")),
]
df.groupby(["cat2"]).agg(
{
"cat1": yes_no_agg,
"cat3": yes_no_agg,
"quant": ["min", "max", "mean"],
}
)
我建議將兩種情況分開。 一種是數值數據,按類別查看它們的最小值、最大值和平均值。 另一個是標記數據及其頻率分布。
首先,讓我們准備數據,將'mode'
作為類別列和兩個數字字段'Measure1', 'Measure2'
:
import pandas as pd
data = {'mode': ['i','i','i','ii','ii','iii','ii','iii','ii'],
'Ofloxacin': ['no','no','no','yes','no','no','yes','no','no'],
'ChangeMode': ['yes','no','no','yes','no','yes','yes','no','yes'],
'Measure1': [*range(1, 10)],
'Measure2': [*range(-9, 0)]}
df = pd.DataFrame(data)
在這種情況下,我建議使用DataFrame.describe
來生成數值數據的統計信息:
df.groupby('mode').agg('describe')
在這種特殊情況下,我們可以看到'Ofloxacin','ChangeMode'
列的標簽相同。 出於這個原因,讓我們使用DataFrame(...).stack
按類別和字段形成帶有標簽分布數據的行:
columns = ['Ofloxacin','ChangeMode']
df.groupby('mode')[columns].apply(lambda group: (
pd.DataFrame((group.value_counts(col, True) for col in columns), index=columns)
.stack(dropna=False)
.fillna(0)
.sort_index()
)
)
讓我們添加內容稍微多樣化的新列:
data = {'mode': ['i','i','i','ii','ii','iii','ii','iii','ii'],
'Ofloxacin': ['no','no','no','yes','no','no','yes','no','no'],
'ChangeMode': ['yes','no','no','yes','no','yes','yes','no','yes'],
'Reaction': ['good','bad','so-so','good','good','so-so','bad','bad','good'],
'DummyData': 'hello my world and all the people out there'.split()}
df = pd.DataFrame(data)
在這種情況下,以前的解決方案將不起作用。 為了解決這個問題,讓我們為預期的列准備一個多索引:
from functools import reduce
columns = ['Ofloxacin','ChangeMode','Reaction','DummyData']
multicol = pd.MultiIndex.from_tuples(
reduce(
lambda x, y: x.append(y),
(
pd.Index(sorted(df[col].unique()))
.map(lambda label: (col, label))
for col in columns
),
pd.Index([])
)
)
我將使用它將數據存儲在正確的位置,如下所示:
final_output = df.groupby('mode')[columns].apply(
lambda group:
pd.DataFrame(
(group.value_counts(col, True) for col in columns),
index=columns
).stack().reindex(multicol)
).fillna(0)
這是最終輸出:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.