在压缩Pandas DataFrame时了解.groupby()。first()?]

问题描述 投票:0回答:1

由于我不确定确切的术语-假设我有此文件:

dataA.csv:

event,car,bike,bus
63175,,18,
65641,45,9,
65805,,,54
68388,,65,
68388,,,39
73041,7,,18
79336,,44,
79423,,,5

dataA = pd.read_csv("dataA.csv", dtype='Int64')阅读此书,我们得到一个熊猫DataFrame:

dataA:
   event   car  bike   bus
0  63175  <NA>    18  <NA>
1  65641    45     9  <NA>
2  65805  <NA>  <NA>    54
3  68388  <NA>    65  <NA>
4  68388  <NA>  <NA>    39
5  73041     7  <NA>    18
6  79336  <NA>    44  <NA>
7  79423  <NA>  <NA>     5

有两行,其中“事件”列具有相同的值(我称之为“重复项”:]

3  68388  <NA>    65  <NA>
4  68388  <NA>  <NA>    39

...并且我希望将它们“压缩”成一个单行(这是正确的词吗?),以便存在实际值(如果有),而不是NaN(即NA):

3  68388  <NA>    65    39

How to compact a merge between two Pandas Dataframes with NaN and duplicate join keys?中我得到了答案,我应该使用.groupby(...).first()-实际上,它可以工作;此脚本:

#!/usr/bin/env python3

import pandas as pd
print(pd.__version__) # 1.0.2 for me

dataA = pd.read_csv("dataA.csv", dtype='Int64')
print("dataA:")
print(dataA)

# make sure Pandas prints entirety of DataFrame
pd.set_option('display.max_rows', None)
pd.set_option('display.max_columns', None)
pd.set_option('display.width', None)
pd.set_option('display.max_colwidth', None)

dataCompact = dataA.groupby('event').first() ##***
print("\ndataCompact:")
print(dataCompact)

最终打印:

dataCompact:
        car  bike   bus
event
63175  <NA>    18  <NA>
65641    45     9  <NA>
65805  <NA>  <NA>    54
68388  <NA>    65    39
73041     7  <NA>    18
79336  <NA>    44  <NA>
79423  <NA>  <NA>     5

...这就是我想要的,因此可以使用。

但是,仔细观察,我意识到我并不真正理解它是如何工作的-也就是说,在这种情况下,我无法真正分辨出.first()具体指的是什么; https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.first.html对我没有多大帮助,因为它指出“ 基于日期偏移量对时间序列数据的初始时期进行子集化的方法。

”(以及大多数其他在线介绍性页面均以日期为例),但是这里我不使用日期。

所以,我做了一些实验-基本上在上面的代码中更改了标有##***的行,并查看了打印输出。

首先,如果我改用此行:

dataCompact = dataA.groupby('event').apply(lambda x: "{} ({}): {}".format(type(x), len(x), x.values.tolist())) ##***

...我得到此打印输出:

dataCompact:
event
63175                             <class 'pandas.core.frame.DataFrame'> (1): [[63175, <NA>, 18, <NA>]]
65641                                <class 'pandas.core.frame.DataFrame'> (1): [[65641, 45, 9, <NA>]]
65805                             <class 'pandas.core.frame.DataFrame'> (1): [[65805, <NA>, <NA>, 54]]
68388    <class 'pandas.core.frame.DataFrame'> (2): [[68388, <NA>, 65, <NA>], [68388, <NA>, <NA>, 39]]
73041                                <class 'pandas.core.frame.DataFrame'> (1): [[73041, 7, <NA>, 18]]
79336                             <class 'pandas.core.frame.DataFrame'> (1): [[79336, <NA>, 44, <NA>]]
79423                              <class 'pandas.core.frame.DataFrame'> (1): [[79423, <NA>, <NA>, 5]]
dtype: object

[据此,我收集到-本质上,groupby('event')为'event'列的每个唯一值提供一个DataFrame:

  • 如果该值在原始数据集中是唯一的,则该DataFrame仅包含一行;但是
  • 如果它是一个“重复的”值,我们将获得一个包含两行的DataFrame(或与该特定值的“重​​复”一样多的行)。
  • 因此,.first()必须采用N> = 1行作为输入的DataFrame,并返回单行。

但是,这是我开始困惑的地方-我读过.first()是指返回N> = 1个输入行中的first

;但是在那种情况下,这些值将不会被“压缩”(即,具有实际数字的插槽用<NA>替换插槽(未定义的值)); -相反,除第一行外的所有其他行都将被删除!那不是这里发生的事情...

因此,我尝试通过为.first()编写自己的Lambda处理程序来模拟.apply()的功能:

def proc_df_first(x):
  # here we get a DataFrame with single row, if "event" (groupby arg) is a unique value;
  # or a DataFrame with as many rows, as there are repeated rows with "event" of same value ("duplicate")
  if len(x) == 1:
    return x
  elif len(x) > 1:
    # create empty return DataFrame (eventually it will only have a single row)
    retdf = pd.DataFrame(columns = x.columns)
    #return retdf # is empty, so is skipped in final result of .groupby.apply
    # must populate rowdata first, then assign via .loc (SO:17091769)
    for icol in x.columns:
      coldata = x[icol] # is Series
      thisval = pd.NA # initialize the "compact" single value we want to set for this column (eventually derived from all the row values in this column)
      for idx, val in coldata.iteritems():
        #print("***", idx, val, val is pd.NA) # `val is None` is always False; `val==pd.NA` always prints `<NA>`; `val is pd.NA` is correct
        if thisval is pd.NA:
          if val is not pd.NA:
            # found the first non-NA value; save it, and stop looking further
            thisval = val
            break
      # store saved non-NA value into return DataFrame
      retdf.at[ x.index[0], icol ] = thisval # SO: 13842088
    return retdf

dataCompact = dataA.groupby('event').apply(lambda x: proc_df_first(x)) ##***

...最终打印:

dataCompact:
         event   car  bike   bus
event
63175 0  63175  <NA>    18  <NA>
65641 1  65641    45     9  <NA>
65805 2  65805  <NA>  <NA>    54
68388 3  68388   NaN    65    39
73041 5  73041     7  <NA>    18
79336 6  79336  <NA>    44  <NA>
79423 7  79423  <NA>  <NA>     5

...这与.groupby('event').first()基本上具有相同的结果(除了重复的“事件”列(是否是层次结构标签?)和索引列)。

所以,这是我的问题:

  • 如上所述,我想说.first()返回一组行中的第一个非NA每列值,从而导致该行组的单行表示-这是正确的吗?
  • 为什么,为了大声喊叫,我在“ event” == 68388的输出的“ car”列中得到NaN吗?当我尝试将内部所有内容都处理为“ Int64”(具有相应的pd.NA值时) ?我知道我可以在任何地方执行dataA.groupby('event').apply(lambda x: proc_df_first(x)).astype('Int64')并获得pd.NA-但鉴于我已经逐个元素地迭代了整个表,因此我不希望在表上再进行一次循环-只是为了摆脱一个单浮点NaN。如果不确定该特定值,我该怎么办才能确保proc_df_first()中从.apply()返回的值始终是pd.NA值?

由于我不确定确切的术语-假设我有这个文件:dataA.csv:event,car,bike,bus 63175,,18,65641,45,9,65805 ,,, 54 68388, ,65,68388 ,,, 39 73041,7,,18 79336,,44,79423 ,,, 5 ...

python pandas dataframe
1个回答
0
投票

在熊猫中有2种不同的first功能,它们是不同的:

© www.soinside.com 2019 - 2024. All rights reserved.