首页 > 解决方案 > 具有无序分类变量的 Pandas 交叉表

问题描述

对于一个有趣的项目,我生成了一个包含所有当前存在的口袋妖怪(916 个,不包括 Megas 或其他形式)的数据集,并收集了有关基本统计数据、能力和类型的数据。现在我想生成一个交叉表,显示每种类型组合的分布。当前对数据进行编码,使得第一类和第二类是单独的变量,Type1并且Type2. 这种格式适用于pd.crosstab(),假设类型的顺序是不同('Flying','Normal')的,与('Normal','Flying');不同。然而,游戏并没有做出这样的区分。我想生成反映这一点的频率表 - 基本上将pd.crosstab()表沿对角线折叠成两半。

#### For data structured like...
In[1]: dfNatDex[dfNatDex['DexNum']<10]
Out[4]: 
    DexNum        Name  Type1   Type2
0      1.0   Bulbasaur  grass  poison
1      2.0     Ivysaur  grass  poison
2      3.0    Venusaur  grass  poison
3      4.0  Charmander   fire    fire
4      5.0  Charmeleon   fire    fire
5      6.0   Charizard   fire  flying
6      7.0    Squirtle  water   water
7      8.0   Wartortle  water   water
8      9.0   Blastoise  water   water

[10 rows x 16 columns]

#### I am getting...
In[2]: crosstab(dfNatDex['Type2'][...],dfNatDex['Type1'][...])
Out[2]: 
Type1   flying  normal  water
Type2                        
flying       3      26      7
normal       0      69      0
water        1       1     67

#### I want to get...
Type1   flying  normal  water
Type2                        
flying       3      26      8
normal       .      69      1
water        .       .     67

我的猜测是,如果没有我还没有找到的 Pandas 函数,那么也许我可以通过矩阵运算来实现。如果做不到这一点,我认为可能会有一个缓慢的迭代过程来实现这一点。

标签: pythonpython-3.xpandascategorical-datacrosstab

解决方案


一种选择是用于np.sort对axis = 1上的值进行排序,然后用于value_counts获取计数:

import numpy as np
import pandas as pd

cols = ['Type1', 'Type2']
types_df = pd.DataFrame(
    np.sort(df[cols], axis=1),
    columns=cols
).value_counts().reset_index(name='Count')

types_df

   Type1   Type2  Count
0  grass  poison      3
1  water   water      3
2   fire    fire      2
3   fire  flying      1

crosstab也可以在排序后的值上使用,但是会有很多0值可能会掩盖试图展示的信息:

cols = ['Type1', 'Type2']
types_df = pd.DataFrame(np.sort(df[cols], axis=1), columns=cols)
ct_df = pd.crosstab(types_df['Type2'], types_df['Type1'])

ct_df

Type1   fire  grass  water
Type2                     
fire       2      0      0
flying     1      0      0
poison     0      3      0
water      0      0      3

假设这些类型:

df[['Type1', 'Type2']]
    Type1   Type2
0  poison   grass  # poison grass
1   grass  poison  # grass poison
2   grass  poison
3    fire    fire
4    fire    fire
5    fire  flying
6   water   water
7   water   water
8   water   water

排序后:

np.sort(df[['Type1', 'Type2']], axis=1)
[['grass' 'poison']  # grass poison
 ['grass' 'poison']  # grass poison
 ['grass' 'poison']
 ['fire' 'fire']
 ['fire' 'fire']
 ['fire' 'flying']
 ['water' 'water']
 ['water' 'water']
 ['water' 'water']]

这样,无论它们在 DataFrame 中如何出现,所有类型都以相同的顺序出现,并且无论它们在列中出现的顺序如何,值计数都会产生正确的值。


推荐阅读