【问题标题】:Sort pandas dataframe based on two columns that are similar but one will be NaN if the other has a value根据相似的两列对熊猫数据框进行排序,但如果另一列有值,则其中一列将为 NaN
【发布时间】:2018-02-09 11:33:26
【问题描述】:

我有一个合并的 df,它有 2 个实验 ID——experiment_a 和experiment_b

它们在通用命名法 EXPT_YEAR_NUM 中,但有些有附加值,没有年份而不是其他值。在这个df中experiment_a中有一个值,experiment_b = NaN,反之亦然。

即:

experiment_a    experiment_b
EXPT_2011_06     NaN
NaN              EXPT_2011_07

如何排序以使experiment_a 和_b 的升序值在一起,而不是在experiment_a 上升序,_b 具有所有NaN 值,然后在experiment_a 具有NaN 值时与experiment_b 升序?

这是我使用 sort_values 时发生的情况:

df = df.sort_values(['experiment_a', 'experiment_b'])

它显然只是先排序_a,然后排序_b。

【问题讨论】:

  • 使用where构造单列?
  • 你能添加更多的值来采样预期的输出吗?

标签: python pandas


【解决方案1】:

我相信你需要fillna 来获得Series,然后通过argsort 获取排序值的索引,最后通过iloc 选择 - 输出是排序的列:

print (df)
   experiment_a  experiment_b
0  EXPT_2011_06           NaN
1  EXPT_2010_06           NaN
2           NaN  EXPT_2011_07

df = df.iloc[df['experiment_a'].fillna(df['experiment_b']).argsort()]
print (df)
   experiment_a  experiment_b
1  EXPT_2010_06           NaN
0  EXPT_2011_06           NaN
2           NaN  EXPT_2011_07

详情

print (df['experiment_a'].fillna(df['experiment_b']))
0    EXPT_2011_06
1    EXPT_2010_06
2    EXPT_2011_07
Name: experiment_a, dtype: object

print (df['experiment_a'].fillna(df['experiment_b']).argsort())
0    1
1    0
2    2
Name: experiment_a, dtype: int64

我测试了更多的解决方案,np.where 的性能要好一些,但主要取决于数据:

print (df)
   experiment_a  experiment_b
0  EXPT_2011_03           NaN
1           NaN  EXPT_2009_08
2           NaN  EXPT_2010_06
3  EXPT_2010_07           NaN
4           NaN  EXPT_2011_07

#[500000 rows x 2 columns]
df = pd.concat([df] * 100000, ignore_index=True)

In [41]: %timeit (df.iloc[(np.where(df['experiment_a'].isnull(), df['experiment_b'], df['experiment_a'])).argsort()])
1 loop, best of 3: 318 ms per loop

In [42]: %timeit (df.iloc[df['experiment_a'].fillna(df['experiment_b']).argsort()])
1 loop, best of 3: 335 ms per loop

In [43]: %timeit (df.iloc[df['experiment_a'].combine_first(df['experiment_b']).argsort()])
1 loop, best of 3: 333 ms per loop

In [44]: %timeit (df.iloc[df.experiment_a.where(df.experiment_a.notnull(), df.experiment_b).argsort()])
1 loop, best of 3: 342 ms per loop

【讨论】:

    【解决方案2】:

    先构造单列:

    key = df.experiment_a.where(df.experiment_a.notnull(), df.experiment_b)
    

    然后是索引:

    idx = key.argsort()
    

    最后:

    df.iloc[idx]
    

    【讨论】:

      猜你喜欢
      • 2015-11-06
      • 2021-09-21
      • 2014-12-29
      • 2021-07-30
      • 2016-03-24
      • 2016-08-09
      • 1970-01-01
      • 2017-04-14
      • 2021-05-25
      相关资源
      最近更新 更多