F# 如何在Deedle中对非唯一列/索引执行左联接
我试图在Deedle中的两个数据帧之间进行左连接。两个数据帧的示例如下:F# 如何在Deedle中对非唯一列/索引执行左联接,f#,pandas,deedle,F#,Pandas,Deedle,我试图在Deedle中的两个数据帧之间进行左连接。两个数据帧的示例如下: let workorder= 柱的框架[ “workOrderCode”=?>系列[(2005020050);(2005120051);(2006020060)] “工作指令说明”=?>系列[(20050,“车门维修”);(20051,“升降机更换”);(20060,“车窗清洁”)] //由于工单代码重复,因此无法编译 设workOrderScores= 柱的框架[ “workOrderCode”=>系列[(2005020
let workorder=
柱的框架[
“workOrderCode”=?>系列[(2005020050);(2005120051);(2006020060)]
“工作指令说明”=?>系列[(20050,“车门维修”);(20051,“升降机更换”);(20060,“车窗清洁”)]
//由于工单代码重复,因此无法编译
设workOrderScores=
柱的框架[
“workOrderCode”=>系列[(2005020050);(2005020050);(2005120051)]
“运行时”=>系列[(200502100112);(200502010130);(2005120100215)]
“分数”=>系列[(20050100);(20050120);(20051,80)]]
Frame.join JoinKind.Outer workOrders workOrders cores
问题是Deedle不允许我创建具有非唯一索引的数据帧,我得到以下错误:System.ArgumentException:重复键“20050”。索引中不允许有重复的键
有趣的是,在Python/Pandas中,我可以完成以下完美的工作。如何在Deedle中重现此结果?我在想,我可能必须展平第二个数据帧,以删除重复的数据帧,然后加入,然后取消填充/取消堆叠它
workOrders=pd.DataFrame(
{'workOrderCode':[200502005120060],
“workOrderDescription:[“车门维修”、“升降机更换”、“车窗清洁”]]
workOrderScores=pd.DataFrame(
{'workOrderCode':[200502005020051],
“运行时”:[20100112、20100130、20100215],
‘得分’:[100、120、80]})
pd.merge(workOrders,workOrderScores,on='workOrderCode',how='left')
#结果:
#workOrderCode workOrderDescription运行时分数
#0 20050车门维修20100112 100
#1 20050车门维修20100130 120
#2 20051升降机的更换2010021580
#3 20060擦窗楠楠楠楠
这是一个很好的问题-我必须承认,目前没有一种优雅的方法可以用Deedle做到这一点。能否请您向GitHub提交一个问题,以确保我们跟踪此问题并添加一些解决方案
正如您所说,Deedle目前不允许在键中有重复的值—尽管您的Pandas解决方案也不使用重复的键—您只需使用Pandas允许您在加入时指定要使用的列这一事实(我认为这对Deedle来说是一个很好的补充)
这里有一种方法可以做你想做的事——但不是很好。我认为使用数据透视是另一种选择(在最新的源代码中有一个很好的数据透视表函数,但在NuGet上还没有)
我使用groupByRows
和nest
将数据帧转换为按workOrderCode
分组的系列(每个项目现在包含一个包含所有具有相同工单代码的行的帧):
现在我们可以加入这两个系列(因为它们的工单代码是键)。但是,对于每个连接的订单代码,您将获得一个或两个数据帧,并且需要大量的工作来外部连接两个帧的行:
// Join the two series to align frames with the same work order code
Series.zip workOrders workOrderScores
|> Series.map(fun _ (orders, scores) ->
match orders, scores with
| OptionalValue.Present s1, OptionalValue.Present s2 ->
// There is a frame with some rows with the specified code in both
// work orders and work order scores - we return a cross product of their rows
[ for r1 in s1.Rows.Values do
for r2 in s2.Rows.Values do
// Drop workOrderCode from one series (they are the same in both)
// and append the two rows & return that as the result
yield Series.append r1 (Series.filter (fun k _ -> k <> "workOrderCode") r2) ]
|> Frame.ofRowsOrdinal
// If left or right value is missing, we just return the columns
// that are available (others will be filled with NaN)
| OptionalValue.Present s, _
| _, OptionalValue.Present s -> s)
|> Frame.unnest
|> Frame.indexRowsOrdinally
//连接两个系列以使用相同的工单代码对齐框架
Series.zip工作单工作单核心
|>系列地图(乐趣(订单,分数))->
与命令、分数相匹配
|可选值。当前s1,可选值。当前s2->
//有一个框架,其中的某些行在这两个框架中都具有指定的代码
//工单和工单分数-返回其行的叉积
[对于s1.Rows.Values中的r1
对于s2.Rows.Values中的r2
//从一个系列中删除workOrderCode(两个系列中的代码相同)
//并附加这两行&返回结果
收益率序列.append r1(序列.filter(fun k uk->k“workOrderCode”)r2)]
|>顺序框架
//如果缺少left或right值,则只返回列
//可用的(其他将填写NaN)
|可选值。当前值s,\u
|_u,可选值。显示s->s)
|>Frame.unnest
|>Frame.indexRowsOrdinally
这可能很慢(尤其是在NuGet版本中)。如果您正在处理更多数据,请尝试从源代码构建最新版本的Deedle(如果没有帮助,请提交一个问题-我们应该对此进行研究!)谢谢您的回答。它似乎没有编译,因为缺少匹配的案例。我添加了大小写“| u,->frame[]),这似乎已经修复了它,但正如您所说的,性能不是很好。@jeremyh这应该只是一个警告(您可以忽略它,因为您永远不会在两侧都丢失值)。但是您的修复是避免警告的一个很好的方法(我也会在生产代码中这样做,以确保我没有留下任何无法解释的警告!)哦,是的,您的警告是正确的。当我输入更大的数据集时,警告会立即返回,而结果会延迟。我以为它会阻止结果返回,但它仍在后台运行。为此,我将在github上添加一个问题。
// Join the two series to align frames with the same work order code
Series.zip workOrders workOrderScores
|> Series.map(fun _ (orders, scores) ->
match orders, scores with
| OptionalValue.Present s1, OptionalValue.Present s2 ->
// There is a frame with some rows with the specified code in both
// work orders and work order scores - we return a cross product of their rows
[ for r1 in s1.Rows.Values do
for r2 in s2.Rows.Values do
// Drop workOrderCode from one series (they are the same in both)
// and append the two rows & return that as the result
yield Series.append r1 (Series.filter (fun k _ -> k <> "workOrderCode") r2) ]
|> Frame.ofRowsOrdinal
// If left or right value is missing, we just return the columns
// that are available (others will be filled with NaN)
| OptionalValue.Present s, _
| _, OptionalValue.Present s -> s)
|> Frame.unnest
|> Frame.indexRowsOrdinally