Python 熊猫根据日期合并行
我有一个客户数据框架,其中包含他们收到的发货记录。不幸的是,这些可能重叠。我试图减少行数,以便可以看到连续使用的日期。除了蛮力iterrows实现之外,还有其他方法可以做到这一点吗 这是一个示例,也是我想做的:Python 熊猫根据日期合并行,python,pandas,Python,Pandas,我有一个客户数据框架,其中包含他们收到的发货记录。不幸的是,这些可能重叠。我试图减少行数,以便可以看到连续使用的日期。除了蛮力iterrows实现之外,还有其他方法可以做到这一点吗 这是一个示例,也是我想做的: df = pd.DataFrame([['A','2011-02-07','2011-02-22',1],['A','2011-02-14','2011-03-10',2],['A','2011-03-07','2011-03-15',3],['A','2011-03-18','2011
df = pd.DataFrame([['A','2011-02-07','2011-02-22',1],['A','2011-02-14','2011-03-10',2],['A','2011-03-07','2011-03-15',3],['A','2011-03-18','2011-03-25',4]], columns = ['Cust','startDate','endDate','shipNo'])
df
reductionFunction将前3条记录分组为一条,因为在每种情况下,下一条记录的开始日期都在前一条记录的结束日期之前。我基本上是将多个重叠的记录转换成一个记录
关于一个好的“pythonic”实现的想法?我可以在每个小组内做一个讨厌的while循环,但我不想 从根本上说,我认为这是一个图连通性问题:解决这个问题的一个快速方法是某种形式的图连通性算法。熊猫不包括这样的工具,但是。您可以使用scipy中的压缩稀疏图(
csgraph
)子模块来解决以下问题:
from scipy.sparse.csgraph import connected_components
# convert to datetime, so min() and max() work
df.startDate = pd.to_datetime(df.startDate)
df.endDate = pd.to_datetime(df.endDate)
def reductionFunction(data):
# create a 2D graph of connectivity between date ranges
start = data.startDate.values
end = data.endDate.values
graph = (start <= end[:, None]) & (end >= start[:, None])
# find connected components in this graph
n_components, indices = connected_components(graph)
# group the results by these connected components
return data.groupby(indices).aggregate({'startDate': 'min',
'endDate': 'max',
'shipNo': 'first'})
df.groupby(['Cust']).apply(reductionFunction).reset_index('Cust')
从scipy.sparse.csgraph导入连接的\u组件
#转换为datetime,使min()和max()起作用
df.startDate=pd.to_datetime(df.startDate)
df.endDate=pd.to_datetime(df.endDate)
def还原功能(数据):
#创建日期范围之间连接的二维图形
开始=data.startDate.values
end=data.endDate.values
图形=(开始=开始[:,无])
#在此图中查找连接的组件
n_组件,索引=连接的_组件(图)
#按这些连接的组件对结果进行分组
返回数据.groupby(index).aggregate({'startDate':'min',
“结束日期”:“最大值”,
“shipNo”:“first”})
df.groupby(['Cust'])。apply(reductionFunction)。reset_index('Cust'))
如果您想从这里对shipNo
做一些不同的事情,那么应该非常简单
请注意,上面的函数不是蛮力,而是使用a来查找连接。如果您愿意使用辅助数据框来保存结果,老实说,您可以在所有行中循环
from time import strptime
results = [df.iloc[0]]
for i, (_, current_row) in enumerate(df1.iterrows()):
try:
next_row = df.iloc[i+1]
if strptime(current_row['endDate'], '%Y-%M-%d') < strptime(next_row['startDate'], '%Y-%M-%d'):
results[-1]['endDate'] = current_row['endDate']
results.append(next_row)
except IndexError:
pass
print pd.DataFrame(results).reset_index(drop=True)
从时间导入strtime
结果=[df.iloc[0]]
对于i,枚举(df1.iterrows())中的(u,当前_行):
尝试:
下一行=df.iloc[i+1]
如果strtime(当前行['endDate'],'%Y-%M-%d')
这个问题不完全相同,但很相似:答案可能是相关的。谢谢您的输入!我没有考虑过这种方法。您的解决方案适用于仅列出一个客户的示例数据。但是,它不适用于我的实际示例,其中有多个Cust值。修改df使其包含一个“B”cust,如df.ix[4]=['B'、'2011-02-07'、'2011-02-22',1]会破坏解决方案。有没有想过如何让它更通用于多个客户?我不熟悉那个特殊的scipy图形函数。在添加第二个客户后,解决方案对我有效。。。您得到了什么错误?ValueError:数据、索引和indptr应该是1-DI在Pandas 0.17和Scipy 0.16上看不到该错误。您使用的是什么版本?如果您使用的是SciPy 0.14或更高版本,则可能与此错误有关:感谢您的输入,我知道我可以通过对所有行的iterrows()调用进行暴力攻击,但我正在像瘟疫一样与之斗争。结果将被实时调用,并且需要有一些响应的外观。我已经有了一个iterrows()实现,它比我想要的要慢。@flyingmeatball干杯,我只想把这个hear留给我自己参考
from time import strptime
results = [df.iloc[0]]
for i, (_, current_row) in enumerate(df1.iterrows()):
try:
next_row = df.iloc[i+1]
if strptime(current_row['endDate'], '%Y-%M-%d') < strptime(next_row['startDate'], '%Y-%M-%d'):
results[-1]['endDate'] = current_row['endDate']
results.append(next_row)
except IndexError:
pass
print pd.DataFrame(results).reset_index(drop=True)