【问题标题】:Pandas DateFrame.concat() screws up index sortingPandas DataFrame.concat() 搞砸了索引排序
【发布时间】:2020-12-05 00:25:20
【问题描述】:

这是对Sort Pandas DataFrame by numbers-as-string column 的补充,但我认为它值得拥有自己的范围。

我可以将链接主题中的解决方案应用于单个数据框。但是一旦我将这些 DF 中的多个组合起来,之前建立的顺序就会再次丢失。

我从两个具有这些奇数的数据结构开始,用字符串表示。

data = [
dict(name = 'test1', index = '1' , status='fail'),
dict(name = 'test3', index = '3', status='pass'),
dict(name = 'test1', index = '11', status='pass'),
dict(name = 'test1', index = '1 2 14 56', status='fail'),
dict(name = 'test1', index = '33' , status='pass'),
dict(name = 'test3', index = '20', status='fail'),
dict(name = 'test1', index = '2' , status='fail'),
dict(name = 'test1', index = '22' , status='fail'),
dict(name = 'test3', index = '5:1:50', status='pass'),]

data1 = [
dict(name = 'test1', index = '1' , status='fail'),
dict(name = 'test3', index = '3', status='fail'),
dict(name = 'test1', index = '11', status='pass'),
dict(name = 'test1', index = '1 2 14 56', status='fail'),
dict(name = 'test1', index = '33' , status='pass'),
dict(name = 'test3', index = '20', status='pass'),
dict(name = 'test1', index = '2' , status='fail'),]

首先我将它们转换成单独的数据框。

df = pd.DataFrame(data)
df1 = pd.DataFrame(data1)

现在我有例如df 为:

    name      index status
0  test1          1   fail
1  test3          3   pass
2  test1         11   pass
3  test1  1 2 14 56   fail
4  test1         33   pass
5  test3         20   fail
6  test1          2   fail
7  test1         22   fail
8  test3     5:1:50   pass

接下来,我对两个 DF 进行按摩,以创建一个排序的多索引,以非词法方式处理“数字字符串”。 (详情请参考上面链接的主题)

dfs = dict()
for i,d in enumerate((df, df1)):
    d = (d.assign(
          _tmpIdx=d['index'].str.extract(r'([\d]+)').astype(int))
         .sort_values(['name', '_tmpIdx'])
         .drop('_tmpIdx', axis=1)
         .set_index(['name', 'index'])
        )
     dfs[i] = d

现在例如df 看起来像这样 (请注意,尽管值是字符串,但索引列是非词法排序的):

                status
name  index           
test1 1           fail
      1 2 14 56   fail
      2           fail
      11          pass
      22          fail
      33          pass
test3 3           pass
      5:1:50      pass
      20          fail

我现在连接两个 DF

summary = pd.concat(dfs.values(), axis=1, keys=dfs.keys())

不幸的是,这会将之前的排序重置为词法:

                     0      1
                status status
name  index                  
test1 1           fail   fail
      1 2 14 56   fail   fail
      11          pass   pass
      2           fail   fail
      22          fail    NaN
      33          pass   pass
test3 20          fail   pass
      3           pass   fail
      5:1:50      pass    NaN

如何保持整体索引内层的排序? 有没有更好的方法来实现这一点?

【问题讨论】:

  • 您需要summary = pd.concat(dfs.values(), axis=1, keys=dfs.keys(), sort=False) 吗?
  • 试过了,这没什么区别。
  • 顺便说一句:这已经是默认设置了 (sort: bool, default False)

标签: python pandas


【解决方案1】:

我自己找到了一个解决方案,我想分享一下。

我不是在连接之前对每个单独的 DateFrame 应用自定义排序,而是对连接的结果进行排序。

如上所述,我首先为每个原始 DF 设置了一个多索引(与问题相同)。这是为了避免在串联结果中重复这些列。

dfs = dict()
for i,d in enumerate((df, df1)):
    d = d.sort_values(['name','index']).set_index(['name','index'])
    dfs[i] = d

这次结果仍将按index词法排序。 df,例如现在看起来像这样

                status
name  index           
test1 1           fail
      1 2 14 56   fail
      11          pass
      2           fail
      22          fail
      33          pass
test3 20          fail
      3           pass
      5:1:50      pass

串联保持不变:

s = pd.concat(dfs.values(), axis=1, keys=dfs.keys())

现在我首先展平多索引...

s = s.reset_index()

    name      index      0      1
                    status status
0  test1          1   fail   fail
1  test1  1 2 14 56   fail   fail
2  test1         11   pass   pass
3  test1          2   fail   fail
4  test1         22   fail    NaN
5  test1         33   pass   pass
6  test3          2    NaN   fail
7  test3         20   fail   pass
8  test3          3   pass   fail
9  test3     5:1:50   pass    NaN

...然后应用自定义排序并重新建立多索引:

s = (s.assign(_tmpIdx=s['index'].str.extract(r'([\d]+)').astype(int))
          .sort_values(['name', '_tmpIdx'])
          .set_index(['name', 'index'])
          .drop(['_tmpIdx'],axis=1)
      )

这给了我想要的结果:

                     0      1
                status status
name  index                  
test1 1           fail   fail
      1 2 14 56   fail   fail
      2           fail   fail
      11          pass   pass
      22          fail    NaN
      33          pass   pass
test3 2            NaN   fail
      3           pass   fail
      5:1:50      pass    NaN
      20          fail   pass

不确定这是否是做这种事情的最优雅的方式。但它有效!当然我愿意改进:)

【讨论】:

    猜你喜欢
    • 2022-01-05
    • 2014-01-16
    • 1970-01-01
    • 2016-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多