如何在 Pandas 数据框中按行值对日期时间列进行排序?

Posted

技术标签:

【中文标题】如何在 Pandas 数据框中按行值对日期时间列进行排序?【英文标题】:How can I sort datetime columns by row value in a Pandas dataframe? 【发布时间】:2017-02-04 09:43:27 【问题描述】:

我是 Python 和 Pandas 的新手,我提取了一个包含 15 多个不同日期时间列的数据库表。我的任务是按照行中最早到最新的值对这些列进行排序。但是,数据不干净;有时,在第 0 行中,A 列的日期会在 B 列的日期之前,而 A 会在第 1 行的 B 之后。

我编写了一些函数(为简单起见,在此进行了编辑),它们通过计算 A 中日期出现在 B 之前和之后的时间百分比来比较两列,然后根据该百分比对列进行排序:

def get_percentage(df, df_subset):
    return len(df_subset)/float(len(df))    

def duration_report(df, earlier_column, later_column):   
    results = 
    td = df[later_column] - df[earlier_column]
    results["Before"] = get_percentage(df, df.loc[td >= pd.Timedelta(0)])
    results["After"] = get_percentage(df, df.loc[td <= pd.Timedelta(0)])
    ind = "%s vs %s" % (earlier_column, later_column)
    return pd.DataFrame(data=results, index=[ind])

def order_date_columns(df, col1, col2):
    before = duration_report(df, col1, col2).Before.values[0]
    after = duration_report(df, col1, col2).After.values[0]
    if before >= after:
        return [col1, col2]
    else:
        return [col2, col1]

我使用上述代码的目标是以编程方式实现以下内容:

如果 Col A 日期在 50+% 的时间之前在 Col B 日期之前,则在最早到最晚日期时间列的列表中,Col A 应该在 Col B 之前。

order_date_columns() 函数成功地将两列排序为正确的顺序,但是如何一次将这种排序应用于 15+ 列?我已经查看了df.apply()lambdamap(),但无法解决这个问题。

任何帮助(也包括代码清晰/效率)将不胜感激!

【问题讨论】:

为了记录,我使用的是 Anaconda 的 Python 2.7.12。 【参考方案1】:

如果您不介意走捷径并使用每个日期列的中位数,这应该可行:

def order_date_columns(df, date_columns_to_sort):
    x = [(col, df[col].astype(np.int64).median()) for col in date_columns_to_sort]
    return [x[0] for x in sorted(x, key=lambda x: x[1])]

【讨论】:

谢谢!我将它应用于数据,输出看起来大部分是正确的,但测试了我的一些假设;我将不得不进一步调查。这些数据中的日期非常时髦,因此我更喜欢逐步的、基于百分比的方法。我仍然很想知道如何以“漫长”的方式做到这一点——更多的是作为一种实践来应用于未来的类似问题!【参考方案2】:

由于您使用的是 Python 2.7,因此您可以将 cmp 关键字参数用于 sorted。要按您要查找的顺序获取列名,我会执行以下操作:

# Returns -1 if first_column[i] > second_column[i] more often.
# Returns 1 if vice versa.
# Returns 0 if equal.
# Assumes df[first_column] and df[second_column] are the same length.
def compare_two(first_column, second_column):
    c1_greater_count = 0
    c2_greater_count = 0
    # Iterate over the two columns in the dataframe. df must be in accessible scope.
    for i in range(len(df[first_column])):
        if df[first_column].iloc(i) > df[second_column].iloc[i]:
            c1_greater_count += 1
        elif df[second_column].iloc[i] > df[first_column].iloc[i]:
            c2_greater_count += 1

    if c1_greater_count > c2_greater_count:
        return -1
    if c2_greater_count > c1_greater_count:
        return 1
    return 0

df = get_dataframe_from_somewhere()
relevant_column_names = get_relevant_column_names(df) # e.g., get all the dates.
sorted_column_names = sorted(relevant_column_names, cmp=compare_two)

# sorted_column_names holds the names of the relevant columns,
# sorted according to the given ordering.

我确信有一种更 Pythonic 的方法可以做到这一点,但这应该可行。请注意,对于 Python 3,您可以使用 cmp_to_key 实用程序。

【讨论】:

以上是关于如何在 Pandas 数据框中按行值对日期时间列进行排序?的主要内容,如果未能解决你的问题,请参考以下文章

在 Pandas GroupBy 数据框中按 ID 计算两个日期之间的行数

如何根据条件行值对 pandas 数据框进行取消堆叠或取消透视?

在 Spark 数据框中的 n 列中按行查找最频繁的值

在熊猫数据框中按日期和计数值分组

如何在 Pandas 数据框中按列值分组

无法在熊猫数据框中按时间戳索引