pandas 分组依据子集 returns 错误的行数
pandas group by on a subset returns wrong number of rows
我正在极大地简化这个问题(与初稿相比)。
给定一个具有分类类型的数据框,如果我对数据框进行子集化,使其仅包含一些分类值,子集化的数据框仍会记住类别级别的完整列表。
当我 groupby
在这个较小的数据框上时,我继续得到我不期望的值。
下面是一些复制此代码的代码:
import pandas as pd
df = pd.DataFrame({
'colA':['a', 'b', 'b', 'c', 'c', 'c'],
'colB':1
})
df['colA'] = df['colA'].astype('category') #<= this is important
df
输出
colA colB
0 a 1
1 b 1
2 b 1
3 c 1
4 c 1
5 c 1
df.groupby('colA').max()
输出
colB
colA
a 1
b 1
c 1
smalldf = df.iloc[:3]
smalldf['colA']
输出
0 a
1 b
2 b
Name: colA, dtype: category
Categories (3, object): ['a', 'b', 'c']
注意上面 'c' 仍然在分类级别
smalldf.groupby('colA').max()
输出
colB
colA
a 1.0
b 1.0
c NaN
这里的这个'c'出乎意料。但是,我想这可以解释清楚,因为子集化不会删除类别级别。
当你写出较小的数据帧时,问题会变得更糟
FEATHER_PATH = Path.joinpath(Path.home(), 'Downloads', 'test.feather')
smalldf.to_feather(FEATHER_PATH)
pd.read_feather(FEATHER_PATH)['colA']
0 a
1 b
2 b
Name: colA, dtype: category
Categories (3, object): ['a', 'b', 'c']
假设你写出较小的数据框并将其传递给某人。他们查看了文件,只看到了 'a' 和 'b' 的 colA
个值。但是,当他们进行 groupby 时,会出现 'c'。 'c'在实际数据中找不到!
他们必须明确地寻找类别级别才能找到隐藏在其中的 'c'!
我不确定这种行为是否错误,但肯定会非常混乱!
不确定是否可以将其留在这里作为对其他人的警告。
这是正确的,基于 groups.get_group('colA')
的 DataFrame 的长度将与 'colA' 列的唯一值具有相同的长度。
编辑:假定 'colA' 是您最大的列。
没有错,只是在文档中有点隐藏。你可以找到它,例如 here:
DataFrame methods like DataFrame.sum() also show “unused” categories.
Groupby will also show “unused” categories
关于 writing/reading:没有它你会丢失类型信息,这也可能会造成伤害。所以需要权衡取舍。
您应该可以使用 .groupby()
的 observed=True
选项来处理它:
observed: bool, default False
This only applies if any of the groupers are Categoricals. If True: only show observed values for categorical groupers. If False: show all values for categorical groupers.
例如:
smalldf.groupby('colA', observed=True).max()
交付
colB
colA
a 1
b 1
我正在极大地简化这个问题(与初稿相比)。
给定一个具有分类类型的数据框,如果我对数据框进行子集化,使其仅包含一些分类值,子集化的数据框仍会记住类别级别的完整列表。
当我 groupby
在这个较小的数据框上时,我继续得到我不期望的值。
下面是一些复制此代码的代码:
import pandas as pd
df = pd.DataFrame({
'colA':['a', 'b', 'b', 'c', 'c', 'c'],
'colB':1
})
df['colA'] = df['colA'].astype('category') #<= this is important
df
输出
colA colB
0 a 1
1 b 1
2 b 1
3 c 1
4 c 1
5 c 1
df.groupby('colA').max()
输出
colB
colA
a 1
b 1
c 1
smalldf = df.iloc[:3]
smalldf['colA']
输出
0 a
1 b
2 b
Name: colA, dtype: category
Categories (3, object): ['a', 'b', 'c']
注意上面 'c' 仍然在分类级别
smalldf.groupby('colA').max()
输出
colB
colA
a 1.0
b 1.0
c NaN
这里的这个'c'出乎意料。但是,我想这可以解释清楚,因为子集化不会删除类别级别。
当你写出较小的数据帧时,问题会变得更糟
FEATHER_PATH = Path.joinpath(Path.home(), 'Downloads', 'test.feather')
smalldf.to_feather(FEATHER_PATH)
pd.read_feather(FEATHER_PATH)['colA']
0 a
1 b
2 b
Name: colA, dtype: category
Categories (3, object): ['a', 'b', 'c']
假设你写出较小的数据框并将其传递给某人。他们查看了文件,只看到了 'a' 和 'b' 的 colA
个值。但是,当他们进行 groupby 时,会出现 'c'。 'c'在实际数据中找不到!
他们必须明确地寻找类别级别才能找到隐藏在其中的 'c'!
我不确定这种行为是否错误,但肯定会非常混乱!
不确定是否可以将其留在这里作为对其他人的警告。
这是正确的,基于 groups.get_group('colA')
的 DataFrame 的长度将与 'colA' 列的唯一值具有相同的长度。
编辑:假定 'colA' 是您最大的列。
没有错,只是在文档中有点隐藏。你可以找到它,例如 here:
DataFrame methods like DataFrame.sum() also show “unused” categories.
Groupby will also show “unused” categories
关于 writing/reading:没有它你会丢失类型信息,这也可能会造成伤害。所以需要权衡取舍。
您应该可以使用 .groupby()
的 observed=True
选项来处理它:
observed: bool, default False
This only applies if any of the groupers are Categoricals. If True: only show observed values for categorical groupers. If False: show all values for categorical groupers.
例如:
smalldf.groupby('colA', observed=True).max()
交付
colB
colA
a 1
b 1