【问题标题】:pandas efficiently compress columns into column with lists of tuplespandas 有效地将列压缩到带有元组列表的列中
【发布时间】:2020-06-07 15:40:27
【问题描述】:

我有一个代表帐户持有人之间交换组的数据框。数据显示了交互的帐户和交换的项目。有时有明确的匹配,但有时交换的物品总数匹配,但您无法准确判断个人之间交换的金额。

想要的输入输出如下:

  id group   rx   tx
0  A     x   50    0
1  B     x    0   50
2  A     y  210    0
3  B     y    0   50
4  C     y    0  350
5  D     y  190    0
  group                                          exchanges
0     x                                       [(B, A, 50)]
1     y  [(unk, A, 210), (B, unk, 50), (C, unk, 350), (unk, D, 190)]

目前我正在像这样使用“groupby”和“apply”:

def sort_out(x):
  # create the row to be returned
  y = pd.Series(index=['group','exchanges'])
  y['group'] = x.group.iloc[0]
  y['exchanges'] = []

  # Find all rx and make tuples list
  # determine source and destinations
  sink = [tuple(i) for i in x.loc[x['rx'] != 0][[
      'id', 'rx'
  ]].to_records(index=True)]
  source = [tuple(i) for i in x.loc[x['tx'] != 0][[
      'id', 'tx'
  ]].to_records(index=True)] 

  # find match
  match = []
  for item in source:
      match = [o for o in sink if o[2] == item[2]]
      if len(match):
          y['exchanges'].append((item[1], match[0][1], match[0][2]))
          sink.remove(match[0])
          continue

  # handle the unmatched elements
  tx_el = x.loc[~x['tx'].isin(x['rx'])][[
      'id', 'tx']].to_records(index=True)
  rx_el = x.loc[~x['rx'].isin(x['tx'])][[
      'id', 'rx']].to_records(index=True)

  [y['exchanges'].append((item[1], 'unk', item[2])) for item in tx_el]
  [y['exchanges'].append(('unk', item[1], item[2])) for item in rx_el]

  return y

b = a.groupby('group').apply(lambda x: sort_out(x))

这种方法在大约 2000 万行上最多需要 7 个小时。我认为最大的障碍是'groupby'-'apply'。我最近被介绍给“爆炸”。从那里我看着“融化”,但它似乎不是我想要的。有什么改进建议吗?

[另一个尝试]

根据 YOBEN_S 的建议,我尝试了以下方法。部分挑战是匹配,部分是跟踪哪些正在发送(tx)和哪些正在接收(rx)。所以我通过显式添加标签来作弊,即方向['dir']。我也使用嵌套三元,但我不确定这是否非常高效:

a['dir'] = a.apply(lambda x: 't' if x['tx'] !=0 else 'r', axis=1)
a[['rx','tx']]=np.sort(a[['rx','tx']].values,axis=1)

out = a.drop(['group','rx'],1).apply(tuple,1).groupby([a['group'],a.tx]).agg('sum') \
   .apply(lambda x: (x[3],x[0],x[1]) if len(x)==6 else  
     ((x[0],'unk',x[1]) if x[2]=='t' else ('unk',x[0],x[1]))
    ).groupby(level=0).agg(list)

【问题讨论】:

    标签: python-3.x pandas dataframe


    【解决方案1】:

    我们可以试试

    out=df.drop('group',1).apply(tuple,1).groupby(df['group']).agg(list).to_frame('exchange').reset_index()
      group                                           exchange
    0     x                           [(A, 50, 0), (B, 0, 50)]
    1     y  [(A, 210, 0), (B, 0, 50), (C, 0, 350), (D, 190...
    

    更新

    df[['rx','tx']]=np.sort(df[['rx','tx']].values,axis=1)
    out=df.drop(['group','rx'],1).apply(list,1).groupby([df['group'],df.tx]).agg('sum').apply(set).groupby(level=0).agg(list)
    out
    group
    x                               [{50, A, B}]
    y    [{50, B}, {D, 190}, {210, A}, {C, 350}]
    dtype: object
    

    【讨论】:

    • 这需要 repl.it 中时间的 1/8。但我仍在弄清楚它是如何工作的,例如。 'group' 被删除但随后在 'groupby' 中使用,或者如何进行匹配?
    • @MikeB2019x 这就是所谓的pd.serise groupby
    • 我一块一块地看。剩下要做的是匹配,例如对于组 x 'exchange' 应该是 [(A, B, 50)]。
    • 我认为更接近,但我得到了 dicts: x [{0, A}, {50, B}] Vice x [(A,B,50)]。
    猜你喜欢
    • 1970-01-01
    • 2020-11-21
    • 2020-09-20
    • 2015-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多