如何在 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()
、lambda
和map()
,但无法解决这个问题。
任何帮助(也包括代码清晰/效率)将不胜感激!
【问题讨论】:
为了记录,我使用的是 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 计算两个日期之间的行数