第8章 分类数据
import pandas as pd
import numpy as np
df = pd. read_csv( 'data/table.csv' )
df. head( )
School
Class
ID
Gender
Address
Height
Weight
Math
Physics
0
S_1
C_1
1101
M
street_1
173
63
34.0
A+
1
S_1
C_1
1102
F
street_2
192
73
32.5
B+
2
S_1
C_1
1103
M
street_2
186
82
87.2
B+
3
S_1
C_1
1104
F
street_2
167
81
80.4
B-
4
S_1
C_1
1105
F
street_4
159
64
84.8
B+
一、category的创建及其性质
1. 分类变量的创建
(a)用Series创建
pd. Series( [ "a" , "b" , "c" , "a" ] , dtype= "category" )
0 a
1 b
2 c
3 a
dtype: category
Categories (3, object): [a, b, c]
(b)对DataFrame指定类型创建
temp_df = pd. DataFrame( { 'A' : pd. Series( [ "a" , "b" , "c" , "a" ] , dtype= "category" ) , 'B' : list ( 'abcd' ) } )
temp_df. dtypes
A category
B object
dtype: object
(c)利用内置Categorical类型创建
cat = pd. Categorical( [ "a" , "b" , "c" , "a" ] , categories= [ 'a' , 'b' , 'c' ] )
pd. Series( cat)
0 a
1 b
2 c
3 a
dtype: category
Categories (3, object): [a, b, c]
(d)利用cut函数创建
默认使用区间类型为标签
pd. cut( np. random. randint( 0 , 60 , 5 ) , [ 0 , 10 , 30 , 60 ] )
[(30, 60], (0, 10], (30, 60], (10, 30], (30, 60]]
Categories (3, interval[int64]): [(0, 10] < (10, 30] < (30, 60]]
可指定字符为标签
pd. cut( np. random. randint( 0 , 60 , 5 ) , [ 0 , 10 , 30 , 60 ] , right= False , labels= [ '0-10' , '10-30' , '30-60' ] )
[30-60, 10-30, 10-30, 30-60, 30-60]
Categories (3, object): [0-10 < 10-30 < 30-60]
2. 分类变量的结构
一个分类变量包括三个部分,元素值(values)、分类类别(categories)、是否有序(order)
从上面可以看出,使用cut函数创建的分类变量默认为有序分类变量
下面介绍如何获取或修改这些属性
(a)describe方法
该方法描述了一个分类序列的情况,包括非缺失值个数、元素值类别数(不是分类类别数)、最多次出现的元素及其频数
s = pd. Series( pd. Categorical( [ "a" , "b" , "c" , "a" , np. nan] , categories= [ 'a' , 'b' , 'c' , 'd' ] ) )
s. describe( )
count 4
unique 3
top a
freq 2
dtype: object
s. values
[a, b, c, a, NaN]
Categories (4, object): [a, b, c, d]
(b)categories和ordered属性
查看分类类别和是否排序
s. cat. categories
Index(['a', 'b', 'c', 'd'], dtype='object')
s. cat. ordered
False
3. 类别的修改
(a)利用set_categories修改
修改分类,但本身值不会变化
s = pd. Series( pd. Categorical( [ "a" , "b" , "c" , "a" , np. nan] , categories= [ 'a' , 'b' , 'c' , 'd' ] ) )
s. cat. set_categories( [ 'new_a' , 'c' ] )
0 NaN
1 NaN
2 c
3 NaN
4 NaN
dtype: category
Categories (2, object): [new_a, c]
(b)利用rename_categories修改
需要注意的是该方法会把值和分类同时修改
s = pd. Series( pd. Categorical( [ "a" , "b" , "c" , "a" , np. nan] , categories= [ 'a' , 'b' , 'c' , 'd' ] ) )
s. cat. rename_categories( [ 'new_%s' % i for i in s. cat. categories] )
0 new_a
1 new_b
2 new_c
3 new_a
4 NaN
dtype: category
Categories (4, object): [new_a, new_b, new_c, new_d]
利用字典修改值
s. cat. rename_categories( { 'a' : 'new_a' , 'b' : 'new_b' } )
0 new_a
1 new_b
2 c
3 new_a
4 NaN
dtype: category
Categories (4, object): [new_a, new_b, c, d]
(c)利用add_categories添加
s = pd. Series( pd. Categorical( [ "a" , "b" , "c" , "a" , np. nan] , categories= [ 'a' , 'b' , 'c' , 'd' ] ) )
s. cat. add_categories( [ 'e' ] )
0 a
1 b
2 c
3 a
4 NaN
dtype: category
Categories (5, object): [a, b, c, d, e]
s. cat. add_categories( 'e' )
0 a
1 b
2 c
3 a
4 NaN
dtype: category
Categories (5, object): [a, b, c, d, e]
(d)利用remove_categories移除
s = pd. Series( pd. Categorical( [ "a" , "b" , "c" , "a" , np. nan] , categories= [ 'a' , 'b' , 'c' , 'd' ] ) )
s. cat. remove_categories( [ 'd' ] )
0 a
1 b
2 c
3 a
4 NaN
dtype: category
Categories (3, object): [a, b, c]
(e)删除元素值未出现的分类类型
s = pd. Series( pd. Categorical( [ "a" , "b" , "c" , "a" , np. nan] , categories= [ 'a' , 'b' , 'c' , 'd' ] ) )
s. cat. remove_unused_categories( )
0 a
1 b
2 c
3 a
4 NaN
dtype: category
Categories (3, object): [a, b, c]
二、分类变量的排序
前面提到,分类数据类型被分为有序和无序,这非常好理解,例如分数区间的高低是有序变量,考试科目的类别一般看做无序变量
1. 序的建立
(a)一般来说会将一个序列转为有序变量,可以利用as_ordered方法
s = pd. Series( [ "a" , "d" , "c" , "a" ] ) . astype( 'category' ) . cat. as_ordered( )
s
0 a
1 d
2 c
3 a
dtype: category
Categories (3, object): [a < c < d]
退化为无序变量,只需要使用as_unordered
s. cat. as_unordered( )
0 a
1 d
2 c
3 a
dtype: category
Categories (3, object): [a, c, d]
(b)利用set_categories方法中的order参数
pd. Series( [ "a" , "d" , "c" , "a" ] ) . astype( 'category' ) . cat. set_categories( [ 'a' , 'c' , 'd' ] , ordered= True )
0 a
1 d
2 c
3 a
dtype: category
Categories (3, object): [a < c < d]
(c)利用reorder_categories方法
这个方法的特点在于,新设置的分类必须与原分类为同一集合
s = pd. Series( [ "a" , "d" , "c" , "a" ] ) . astype( 'category' )
s. cat. reorder_categories( [ 'a' , 'c' , 'd' ] , ordered= True )
0 a
1 d
2 c
3 a
dtype: category
Categories (3, object): [a < c < d]
2. 排序
先前在第1章介绍的值排序和索引排序都是适用的
s = pd. Series( np. random. choice( [ 'perfect' , 'good' , 'fair' , 'bad' , 'awful' ] , 50 ) ) . astype( 'category' )
s. cat. set_categories( [ 'perfect' , 'good' , 'fair' , 'bad' , 'awful' ] [ : : - 1 ] , ordered= True ) . head( )
0 good
1 bad
2 bad
3 good
4 good
dtype: category
Categories (5, object): [awful < bad < fair < good < perfect]
s. sort_values( ascending= False ) . head( )
46 perfect
43 perfect
9 perfect
11 perfect
13 perfect
dtype: category
Categories (5, object): [awful, bad, fair, good, perfect]
s. sort_values( ascending= True ) . head( )
39 awful
47 awful
6 awful
23 awful
8 awful
dtype: category
Categories (5, object): [awful, bad, fair, good, perfect]
df_sort = pd. DataFrame( { 'cat' : s. values, 'value' : np. random. randn( 50 ) } ) . set_index( 'cat' )
df_sort. head( )
value
cat
good
0.371380
bad
0.799006
bad
-0.039575
good
0.631024
good
0.905758
df_sort. sort_index( ) . head( )
value
cat
awful
0.713834
awful
0.108047
awful
-0.290348
awful
2.646020
awful
-0.212087
三、分类变量的比较操作
1. 与标量或等长序列的比较
(a)标量比较
s = pd. Series( [ "a" , "d" , "c" , "a" ] ) . astype( 'category' )
s == 'a'
0 True
1 False
2 False
3 True
dtype: bool
(b)等长序列比较
s == list ( 'abcd' )
0 True
1 False
2 True
3 False
dtype: bool
2. 与另一分类变量的比较
(a)等式判别(包含等号和不等号)
两个分类变量的等式判别需要满足分类完全相同
s = pd. Series( [ "a" , "d" , "c" , "a" ] ) . astype( 'category' )
s == s
0 True
1 True
2 True
3 True
dtype: bool
s != s
0 False
1 False
2 False
3 False
dtype: bool
s_new = s. cat. set_categories( [ 'a' , 'd' , 'e' ] )
s_new
0 a
1 d
2 NaN
3 a
dtype: category
Categories (3, object): [a, d, e]
(b)不等式判别(包含>=,<=,<,>)
两个分类变量的不等式判别需要满足两个条件:① 分类完全相同 ② 排序完全相同
s = pd. Series( [ "a" , "d" , "c" , "a" ] ) . astype( 'category' )
s = pd. Series( [ "a" , "d" , "c" , "a" ] ) . astype( 'category' ) . cat. reorder_categories( [ 'a' , 'c' , 'd' ] , ordered= True )
s >= s
0 True
1 True
2 True
3 True
dtype: bool
四、问题与练习
【问题一】 如何使用union_categoricals方法?它的作用是什么?
from https://juejin.im/post/5b680a7af265da0f7a1d1de4
blood_type1 = pd. Categorical( [ "A" , "AB" ] )
blood_type2 = pd. Categorical( [ "B" , "O" ] )
pd. concat( [ pd. Series( blood_type1) , pd. Series( blood_type2) ] )
0 A
1 AB
0 B
1 O
dtype: object
可以发现,分类数据经过 pd.concat 合并后类型转为了 object 类型。如果想要保持分类类型的话,可以借助 union_categoricals 来完成。
from pandas. api. types import union_categoricals
pd. Series( union_categoricals( [ blood_type1, blood_type2] ) )
0 A
1 AB
2 B
3 O
dtype: category
Categories (4, object): [A, AB, B, O]
【问题二】 利用concat方法将两个序列纵向拼接,它的结果一定是分类变量吗?什么情况下不是?
blood_type1 = pd. Categorical( [ "A" , "AB" ] )
blood_type2 = pd. Categorical( [ "B" , "O" ] )
pd. concat( [ pd. Series( blood_type1) , pd. Series( blood_type2) ] )
0 A
1 AB
0 B
1 O
dtype: object
可以发现,分类数据经过 pd.concat 合并后类型转为了 object 类型。
blood_type1 = pd. Categorical( [ 1 , 2 ] )
blood_type2 = pd. Categorical( [ 2 , 3 ] )
pd. concat( [ pd. Series( blood_type1) , pd. Series( blood_type2) ] )
0 1
1 2
0 2
1 3
dtype: int64
【问题三】 当使用groupby方法或者value_counts方法时,分类变量的统计结果和普通变量有什么区别?
df = pd. read_csv( 'data/table.csv' )
df. head( )
School
Class
ID
Gender
Address
Height
Weight
Math
Physics
0
S_1
C_1
1101
M
street_1
173
63
34.0
A+
1
S_1
C_1
1102
F
street_2
192
73
32.5
B+
2
S_1
C_1
1103
M
street_2
186
82
87.2
B+
3
S_1
C_1
1104
F
street_2
167
81
80.4
B-
4
S_1
C_1
1105
F
street_4
159
64
84.8
B+
df[ 'Physics' ] . value_counts( )
B+ 9
B 8
B- 6
A 4
A- 3
A+ 3
C 2
Name: Physics, dtype: int64
df[ 'Physics' ] . astype( 'category' ) . value_counts( )
B+ 9
B 8
B- 6
A 4
A- 3
A+ 3
C 2
Name: Physics, dtype: int64
df[ 'Physics' ] = df[ 'Physics' ] . astype( 'category' )
for name , group in df. groupby( 'Physics' ) :
print ( name)
display( group)
A
School
Class
ID
Gender
Address
Height
Weight
Math
Physics
13
S_1
C_3
1304
M
street_2
195
70
85.2
A
19
S_2
C_1
2105
M
street_4
170
81
34.2
A
26
S_2
C_3
2302
M
street_5
171
88
32.7
A
30
S_2
C_4
2401
F
street_2
192
62
45.3
A
A+
School
Class
ID
Gender
Address
Height
Weight
Math
Physics
0
S_1
C_1
1101
M
street_1
173
63
34.0
A+
7
S_1
C_2
1203
M
street_6
160
53
58.8
A+
22
S_2
C_2
2203
M
street_4
155
91
73.8
A+
A-
School
Class
ID
Gender
Address
Height
Weight
Math
Physics
5
S_1
C_2
1201
M
street_5
188
68
97.0
A-
11
S_1
C_3
1302
F
street_1
175
57
87.7
A-
28
S_2
C_3
2304
F
street_6
164
81
95.5
A-
B
School
Class
ID
Gender
Address
Height
Weight
Math
Physics
8
S_1
C_2
1204
F
street_5
162
63
33.8
B
12
S_1
C_3
1303
M
street_7
188
82
49.7
B
20
S_2
C_2
2201
M
street_5
193
100
39.1
B
24
S_2
C_2
2205
F
street_7
183
76
85.4
B
29
S_2
C_3
2305
M
street_4
187
73
48.9
B
31
S_2
C_4
2402
M
street_7
166
82
48.7
B
33
S_2
C_4
2404
F
street_2
160
84
67.7
B
34
S_2
C_4
2405
F
street_6
193
54
47.6
B
B+
School
Class
ID
Gender
Address
Height
Weight
Math
Physics
1
S_1
C_1
1102
F
street_2
192
73
32.5
B+
2
S_1
C_1
1103
M
street_2
186
82
87.2
B+
4
S_1
C_1
1105
F
street_4
159
64
84.8
B+
10
S_1
C_3
1301
M
street_4
161
68
31.5
B+
16
S_2
C_1
2102
F
street_6
161
61
50.6
B+
18
S_2
C_1
2104
F
street_5
159
97
72.2
B+
21
S_2
C_2
2202
F
street_7
194
77
68.5
B+
25
S_2
C_3
2301
F
street_4
157
78
72.3
B+
32
S_2
C_4
2403
F
street_6
158
60
59.7
B+
B-
School
Class
ID
Gender
Address
Height
Weight
Math
Physics
3
S_1
C_1
1104
F
street_2
167
81
80.4
B-
6
S_1
C_2
1202
F
street_4
176
94
63.5
B-
9
S_1
C_2
1205
F
street_6
167
63
68.4
B-
14
S_1
C_3
1305
F
street_5
187
69
61.7
B-
17
S_2
C_1
2103
M
street_4
157
61
52.5
B-
23
S_2
C_2
2204
M
street_1
175
74
47.2
B-
C
School
Class
ID
Gender
Address
Height
Weight
Math
Physics
15
S_2
C_1
2101
M
street_7
174
84
83.3
C
27
S_2
C_3
2303
F
street_7
190
99
65.9
C
【问题四】 下面的代码说明了Series创建分类变量的什么“缺陷”?如何避免?(提示:使用Series中的copy参数)
cat = pd. Categorical( [ 1 , 2 , 3 , 10 ] , categories= [ 1 , 2 , 3 , 4 , 10 ] )
s = pd. Series( cat, name= "cat" )
cat
[1, 2, 3, 10]
Categories (5, int64): [1, 2, 3, 4, 10]
s. iloc[ 0 : 2 ] = 10
cat
[10, 10, 3, 10]
Categories (5, int64): [1, 2, 3, 4, 10]
问题应该是我们对于Series里面的内容进行改变时,Categories中相对应的内容也进行了改变,避免的方式时在创建Series时copy 参数设为True这样一来就会自动拷贝一份输入的Categories,这时候我i们再对Series进行改变,Categories中相对应的内容不变。
copy:一个布尔值。如果为True,则拷贝输入数据data
cat = pd. Categorical( [ 1 , 2 , 3 , 10 ] , categories= [ 1 , 2 , 3 , 4 , 10 ] )
s = pd. Series( cat, name= "cat" , copy= True )
cat
[1, 2, 3, 10]
Categories (5, int64): [1, 2, 3, 4, 10]
s. iloc[ 0 : 2 ] = 10
cat
[1, 2, 3, 10]
Categories (5, int64): [1, 2, 3, 4, 10]
【练习一】 现继续使用第四章中的地震数据集,请解决以下问题:
(a)现在将深度分为七个等级:[0,5,10,15,20,30,50,np.inf],请以深度等级Ⅰ,Ⅱ,Ⅲ,Ⅳ,Ⅴ,Ⅵ,Ⅶ为索引并按照由浅到深的顺序进行排序。
pd. read_csv( 'data/Earthquake.csv' ) . head( )
日期
时间
维度
经度
方向
距离
深度
烈度
0
2003.05.20
12:17:44 AM
39.04
40.38
west
0.1
10.0
0.0
1
2007.08.01
12:03:08 AM
40.79
30.09
west
0.1
5.2
4.0
2
1978.05.07
12:41:37 AM
38.58
27.61
south_west
0.1
0.0
0.0
3
1997.03.22
12:31:45 AM
39.47
36.44
south_west
0.1
10.0
0.0
4
2000.04.02
12:57:38 AM
40.80
30.24
south_west
0.1
7.0
0.0
a= pd. read_csv( 'data/Earthquake.csv' )
a[ '深度' ] = pd. cut( a[ '深度' ] , [ 0 , 5 , 10 , 15 , 20 , 30 , 50 , np. inf] , right= False , labels= [ 'Ⅰ' , 'Ⅱ' , 'Ⅲ' , 'Ⅳ' , 'Ⅴ' , 'Ⅵ' , 'Ⅶ' ] )
a. sort_values( '深度' )
日期
时间
维度
经度
方向
距离
深度
烈度
1182
1999.07.05
12:57:31 AM
41.24
32.78
north_west
0.9
Ⅰ
0.0
1486
1994.12.24
12:40:49 AM
37.48
28.35
north_east
1.0
Ⅰ
0.0
7092
2001.12.12
12:59:55 AM
37.42
37.28
north_east
3.2
Ⅰ
0.0
2810
2017.04.21
12:25:56 AM
38.78
29.06
south_east
1.5
Ⅰ
3.8
1483
1992.08.21
12:10:52 AM
37.61
27.48
north_east
1.0
Ⅰ
0.0
...
...
...
...
...
...
...
...
...
7771
1981.08.04
12:52:19 AM
38.90
37.00
north
3.7
Ⅶ
0.0
525
1968.03.21
12:42:51 AM
38.80
27.60
south
0.6
Ⅶ
4.3
3921
1929.04.27
12:18:06 AM
40.51
31.43
south_west
1.9
Ⅶ
4.8
3896
2008.03.26
12:16:15 AM
37.04
30.27
east
1.8
Ⅶ
0.0
1214
1956.07.18
12:46:53 AM
39.96
27.30
north_east
0.9
Ⅶ
4.6
10062 rows × 8 columns
参考答案
df = pd. read_csv( 'data/Earthquake.csv' )
df. head( )
df_a = df. copy( )
df_a[ '深度' ] = pd. cut( df_a[ '深度' ] , [ - 1e - 10 , 5 , 10 , 15 , 20 , 30 , 50 , np. inf] , labels= [ 'Ⅰ' , 'Ⅱ' , 'Ⅲ' , 'Ⅳ' , 'Ⅴ' , 'Ⅵ' , 'Ⅶ' ] )
df_a. set_index( '深度' ) . sort_index( ) . head( )
日期
时间
维度
经度
方向
距离
烈度
深度
Ⅰ
2009.09.09
12:54:13 AM
42.42
43.03
north_east
95.4
0.0
Ⅰ
1997.06.16
12:18:04 AM
37.92
29.17
north_east
3.2
0.0
Ⅰ
2011.10.25
12:29:45 AM
38.96
43.64
south_east
1.6
3.9
Ⅰ
1995.07.23
12:05:04 AM
37.61
29.29
north_east
3.2
0.0
Ⅰ
2013.06.10
12:39:19 AM
38.53
43.85
south_east
1.6
3.7
(b)在(a)的基础上,将烈度分为4个等级:[0,3,4,5,np.inf],依次对南部地区的深度和烈度等级建立多级索引排序。
a[ '烈度' ] = pd. cut( a[ '烈度' ] , [ 0 , 3 , 4 , 5 , np. inf] , right= False )
a. set_index( [ '深度' , '烈度' ] )
日期
时间
维度
经度
方向
距离
深度
烈度
Ⅲ
[0.0, 3.0)
2003.05.20
12:17:44 AM
39.04
40.38
west
0.1
Ⅱ
[4.0, 5.0)
2007.08.01
12:03:08 AM
40.79
30.09
west
0.1
Ⅰ
[0.0, 3.0)
1978.05.07
12:41:37 AM
38.58
27.61
south_west
0.1
Ⅲ
[0.0, 3.0)
1997.03.22
12:31:45 AM
39.47
36.44
south_west
0.1
Ⅱ
[0.0, 3.0)
2000.04.02
12:57:38 AM
40.80
30.24
south_west
0.1
...
...
...
...
...
...
...
[3.0, 4.0)
2015.11.18
12:17:48 AM
42.31
42.94
north
81.6
Ⅰ
[0.0, 3.0)
1990.01.28
12:22:43 AM
42.70
26.20
north_west
89.5
Ⅱ
[0.0, 3.0)
2001.08.09
12:58:14 AM
42.77
26.47
north
90.6
Ⅵ
[0.0, 3.0)
1994.06.05
12:20:03 AM
42.41
43.06
north_east
94.3
Ⅱ
[0.0, 3.0)
2009.09.09
12:54:13 AM
42.42
43.03
north_east
95.4
10062 rows × 6 columns
a[ a[ '方向' ] == 'south' ] . set_index( [ '深度' , '烈度' ] ) . sort_index( )
日期
时间
维度
经度
方向
距离
深度
烈度
Ⅰ
[0.0, 3.0)
2000.05.14
12:18:59 AM
38.60
39.92
south
0.3
[0.0, 3.0)
1982.01.05
12:53:17 AM
39.61
28.50
south
0.5
[0.0, 3.0)
1986.07.20
12:01:18 AM
37.81
35.91
south
0.5
[0.0, 3.0)
1996.08.14
12:14:37 AM
40.70
35.43
south
0.5
[0.0, 3.0)
2002.09.16
12:54:15 AM
41.19
34.16
south
0.5
...
...
...
...
...
...
...
...
Ⅶ
[4.0, 5.0)
1933.01.02
12:56:58 AM
38.01
38.24
south
2.6
[4.0, 5.0)
1936.08.02
12:21:09 AM
37.88
29.70
south
2.9
[4.0, 5.0)
1971.04.30
12:10:04 AM
37.76
36.18
south
3.5
[4.0, 5.0)
1964.11.20
12:59:19 AM
40.20
28.06
south
3.6
[4.0, 5.0)
1970.03.30
12:15:44 AM
38.96
29.73
south
4.0
605 rows × 6 columns
参考答案
df_a[ '烈度' ] = pd. cut( df_a[ '烈度' ] , [ - 1e - 10 , 3 , 4 , 5 , np. inf] , labels= [ 'Ⅰ' , 'Ⅱ' , 'Ⅲ' , 'Ⅳ' ] )
df_a. set_index( [ '深度' , '烈度' ] ) . sort_index( ) . head( )
日期
时间
维度
经度
方向
距离
深度
烈度
Ⅰ
Ⅰ
1978.05.07
12:41:37 AM
38.58
27.61
south_west
0.1
Ⅰ
2000.02.07
12:11:45 AM
40.05
34.07
south_east
0.1
Ⅰ
1971.05.20
12:08:46 AM
37.72
30.00
north_east
0.1
Ⅰ
1985.01.28
12:20:56 AM
38.85
29.06
north_east
0.1
Ⅰ
1990.07.05
12:43:04 AM
37.87
29.18
east
0.1
【练习二】 对于分类变量而言,调用第4章中的变形函数会出现一个BUG(目前的版本下还未修复):例如对于crosstab函数,按照官方文档的说法 ,即使没有出现的变量也会在变形后的汇总结果中出现,但事实上并不是这样,比如下面的例子就缺少了原本应该出现的行’c’和列’f’。基于这一问题,请尝试设计my_crosstab函数,在功能上能够返回正确的结果。
foo = pd. Categorical( [ 'a' , 'b' ] , categories= [ 'a' , 'b' , 'c' ] )
bar = pd. Categorical( [ 'd' , 'e' ] , categories= [ 'd' , 'e' , 'f' ] )
pd. crosstab( foo, bar)
col_0
d
e
row_0
a
1
0
b
0
1
pd. crosstab( index= foo. categories, columns= bar. categories, values= 1 , aggfunc= 'count' )
def my_crosstab ( foo, bar) :
df= pd. DataFrame( { i: [ 0 ] * len ( foo. categories) for i in bar. categories} , index= foo. categories)
for i in range ( len ( foo. categories) ) :
df. iat[ i, i] = 1
df. rename_axis( index= { None : 'row_0' } , columns= { None : 'col_0' } , inplace= True )
return df
my_crosstab( foo , bar )
col_0
d
e
f
row_0
a
1
0
0
b
0
1
0
c
0
0
1
查看答案后改进
pd. crosstab( index= foo. categories, columns= bar. categories, values= 1 , aggfunc= 'count' )
def my_crosstab ( foo, bar) :
col= bar. categories. union( bar)
row= foo. categories. union( foo)
df= pd. DataFrame( { i: [ 0 ] * len ( row) for i in col} , index= row)
for i in range ( len ( row) ) :
df. iat[ i, i] = 1
df. rename_axis( index= { None : 'row_0' } , columns= { None : 'col_0' } , inplace= True )
return df
my_crosstab( foo , bar )
col_0
d
e
f
row_0
a
1
0
0
b
0
1
0
c
0
0
1
参考答案
bar. categories. union( set ( bar) )
Index(['d', 'e', 'f'], dtype='object')
def my_crosstab ( foo, bar) :
num = len ( foo)
s1 = pd. Series( [ i for i in list ( foo. categories. union( set ( foo) ) ) ] , name= '1nd var' )
print ( 's1' )
display( s1)
s2 = [ i for i in list ( bar. categories. union( set ( bar) ) ) ]
print ( 's2' )
display( s2)
df = pd. DataFrame( { i: [ 0 ] * len ( s1) for i in s2} , index= s1)
for i in range ( num) :
df. at[ foo[ i] , bar[ i] ] += 1
return df. rename_axis( '2st var' , axis= 1 )
my_crosstab( foo, bar)
s1
0 a
1 b
2 c
Name: 1nd var, dtype: object
s2
['d', 'e', 'f']
2st var
d
e
f
1nd var
a
1
0
0
b
0
1
0
c
0
0
0