微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Pandas DataFrame.agg 在选择缺少类别后生成多索引

如何解决Pandas DataFrame.agg 在选择缺少类别后生成多索引

我仍在研究可重现的示例,但不幸的是,我是 Pandas 的绝对初学者,我对自己做错了什么感到迷茫。该行为似乎是 Pandas 1.2.4 中的一个错误

我有两个数据框,files_df 提供了多个存储库中源代码文件的类型和复杂性,而 proj_df 提供了项目及其上次更新时间。

我试图按复杂性为每种语言挑选前两个项目,它看起来像这样:

def largest(x):
    return (
        # Pick the top two rows in each language (from the groupby) by scc_complexity
        x.nlargest(2,'scc_complexity')
        # Combine the proj_repo values (we don't actually care about scc_complexity at this point)
        .agg({'proj_repo': lambda y: '<br>'.join(y.values)})
    )

max_proj = (
    # Pick the language and complexity columns
    files_df[['scc_lang','scc_complexity','proj_repo']]
    # Sum scc_complexity by language and repo
    .groupby(['scc_lang','proj_repo'],observed=True).sum()
    .reset_index()
)

max_proj = (
    max_proj
    # Select only repos updated in the last two years
    .loc[max_proj['proj_repo'].isin(proj_df.loc[proj_df['last_author_time'] > '2019-05-01','proj_repo'])]
    # Now pick the top repos by language complexity
    .groupby('scc_lang').apply(largest)
)

这应该会生成一个scc_lang 作为其索引和 proj_repo 作为其唯一列的框架,但它会生成以下形状:

<class 'pandas.core.frame.DataFrame'>
MultiIndex: 151 entries,('ASP','proj_repo') to ('XML Schema (min)','proj_repo')
Data columns (total 2 columns):
 #   Column     Non-Null Count  Dtype 
---  ------     --------------  ----- 
 0   0          151 non-null    object
 1   proj_repo  0 non-null      object
dtypes: object(2)
memory usage: 8.7+ KB
MultiIndex([(                        'ASP','proj_repo'),(                   'Autoconf',(                       'BASH',(                      'Batch',...

也就是说,现在有一个多索引,proj_info 列现在是一个名为 0 的列,而 proj_info 列现在是空的。

现在是真正奇怪的部分。如果您从 .loc[]删除 max_proj 选择,此代码生成正确的形状。对于我的一生,我无法弄清楚为什么进行选择会改变结果的形状。我无法用一个完整的小例子来重现结果。

我会继续尝试,如果我学到任何有趣的东西,我会在这里报告。

轻微更新:我发现删除 observed=True 似乎也能产生正确的形状——所以这可能与缺少键有关?

更大的更新:我设法重现了它,是的,它确实与丢失的密钥有关,但我不确定如何:

tdf = pd.DataFrame([['lang1',1,'ab'],['lang2',2,'cd'],4,3,'ef'],'gh'],['lang3','ef']
                   ],columns=['lang','size','name']).astype({'lang': 'category'},copy=False).set_index('lang')

d = tdf.groupby(['lang','name'],observed=True).sum().reset_index()
d = d.loc[d['name'].isin(pd.Series(['ab','cd','gh']))].groupby('lang').apply(lambda x: x.agg({'name': lambda y: ' '.join(y.values)}))
display(d)
d.info()
0 姓名
语言
lang1 姓名 ab NaN
lang2 姓名 cd gh NaN
<class 'pandas.core.frame.DataFrame'>
MultiIndex: 2 entries,('lang1','name') to ('lang2','name')
Data columns (total 2 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   0       2 non-null      object
 1   name    0 non-null      object
dtypes: object(2)
memory usage: 356.0+ bytes

删除“ab”或“ef”名称会触发此操作,这意味着它与缺少的类别有关。事实上,将列类型改回 object 解决了这个问题。所以我似乎误解了类别...

一个更新:我已设法将其缩减为这两行:

tdf2 = pd.DataFrame([['a','boof']],'name']).astype({'lang': pd.CategoricalDtype(['a','b'])})
display(tdf2.groupby('lang').apply(lambda x: x.agg({'name': lambda y: y.values})))

我们现在非常小。删除上述代码中的几乎任何一点都会导致生成的数据框对齐到正确的形状。

我们这里有一个 agg 应用于由 .groupby('lang') 生成的空数据帧,它复活了一个已从数据中删除的类别。在 apply() 内重新加入结果似乎有些奇怪。

这里的一个新发现是从 y.values lambda 返回 apply() 是其中的一部分:如果我返回 y(系列),则不会发生奇怪的结构。

解决方法

终于找到了。奇怪的结构结果是因为空数据帧上的单列agg的结果是一个DataFrame,但如果DataFrame有行,结果是一个Series

tdf2 = pd.DataFrame([],columns=['lang','name'])
print(type(tdf2.agg({'name': lambda y: y.values})))

tdf2 = pd.DataFrame([['a','boof']],'name'])
print(type(tdf2.agg({'name': lambda y: y.values})))
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.series.Series'>

groupby 的 apply() 返回奇怪的结构,因为它试图将两者结合起来:

tdf2 = pd.DataFrame([['a','boof'],['b','toop']],'name'])
print(tdf2.groupby('lang').apply(lambda x: x['name'] if x.iloc[0,0] == 'a' else x))
           0 lang  name
lang                   
a    0  boof  NaN   NaN
b    1   NaN    b  toop

我不知道我是否会称其为错误。这当然是令人惊讶的行为,一般来说程序should not be surprising

更新:归档为 https://github.com/pandas-dev/pandas/issues/41672

更新 2:现在我了解了类别的工作原理,对原始代码的最终修复是在应用之前将 observed=True 添加到 groupby,消除空数据框。 >

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?