pandas - 带有外连接的 DataFrame 扩展

Posted

技术标签:

【中文标题】pandas - 带有外连接的 DataFrame 扩展【英文标题】:pandas - DataFrame expansion with outer join 【发布时间】:2014-10-10 22:57:44 【问题描述】:

首先,我是 pandas 的新手,我正在努力学习,所以我们将不胜感激。

我想生成一个表示地图witter tag subtoken -> poster 的pandas DataFrame,其中标记子标记表示集合hashtagA U i | i in split('_', hashtagA) 中的任何内容,来自匹配poster -> tweet 的表

例如:

In [1]: df = pd.DataFrame([["jim", "i was like #yolo_omg to her"], ["jack", "You are so #yes_omg #best_place_ever"], ["neil", "Yo #rofl_so_funny"]])

In [2]: df
Out[2]: 
      0                                     1
0   jim           i was like #yolo_omg to her
1  jack  You are so #yes_omg #best_place_ever
2  neil                     Yo #rofl_so_funny

我想从中得到类似的东西

      0          1
0   jim          yolo_omg
1   jim          yolo
2   jim          omg
3  jack          yes_omg
4  jack          yes
5  jack          omg
6  jack          best_place_ever
7  jack          best
8  jack          place
9  jack          ever
10 neil          rofl_so_funny
11 neil          rofl
12 neil          so
13 neil          funny

我设法构建了这个真正完成这项工作的大多数人:

In [143]: df[1].str.findall('#([^\s]+)') \
    .apply(pd.Series).stack() \
    .apply(lambda s: [s] + s.split('_') if '_' in s else [s]) \
    .apply(pd.Series).stack().to_frame().reset_index(level=0) \
    .join(df, on='level_0', how='right', lsuffix='_l')[['0','0_l']]

Out[143]: 
        0              0_l
0 0   jim         yolo_omg
  1   jim             yolo
  2   jim              omg
  0  jack          yes_omg
  1  jack              yes
  2  jack              omg
1 0  jack  best_place_ever
  1  jack             best
  2  jack            place
  3  jack             ever
0 0  neil    rofl_so_funny
  1  neil             rofl
  2  neil               so
  3  neil            funny

但我有一种非常强烈的感觉,即有更好的方法可以做到这一点,特别是考虑到真实的数据集非常庞大。

【问题讨论】:

似乎是一个合理的问题,我很惊讶还没有人回答。您可能需要进行编辑,将行拆分成更小的部分,使其更具可读性。 一个初步的想法是,您正在将字符串方法与其他数据混杂在一起。我想知道您是否只想使用常规 python 在一个地方执行所有字符串操作,然后读入数据帧?不确定它是否会更快,但几乎可以肯定会更简单。 也许我应该这么说,但我从带有frame_query 的 sql 数据库中读取了我的数据,所以我从一开始就把我的数据放在了一个数据框中。正如我所说,我对哪个是最佳实践没有强烈的意见。无论如何用常规python处理数据是个好主意吗?反正我用的是lambda... 更有经验的 pandas 用户可能会给你更优雅的代码,但我怀疑你使用的工具不正确。您的单行 python 可能会在某个阶段工作,但不会是可维护的。多几行将为您提供具有标准 python 结构的代码,如果您需要该格式,您可以将其放回数据框中。 【参考方案1】:

pandas 确实有本机执行此操作的功能。 Series.str.findall() 这基本上应用了一个正则表达式并捕获您在其中指定的组。

如果我有你的数据框:

df = pd.DataFrame([["jim", "i was like #yolo_omg to her"], ["jack", "You are so #yes_omg #best_place_ever"], ["neil", "Yo #rofl_so_funny"]])

我要做的是首先设置列的名称,如下所示:

df.columns = ['user', 'tweet']

或者在创建数据框时进行:

df = pd.DataFrame([["jim", "i was like #yolo_omg to her"], ["jack", "You are so #yes_omg #best_place_ever"], ["neil", "Yo #rofl_so_funny"]], columns=['user', 'tweet'])

然后我将简单地使用正则表达式应用提取函数:

df['tag'] = df["tweet"].str.findall("(#[^ ]*)")

我会使用否定字符组而不是肯定字符组,这更有可能在特殊情况下存活。

【讨论】:

【参考方案2】:

在 python 中使用列表推导然后恢复到 pandas 怎么样?需要几行代码,但可能更具可读性。

import re
获取哈希标签
tags = [re.findall('#([^\s]+)', t) for t in df[1]]
为每个用户制作带有子标记的标签列表
st = [[t] + [s.split('_') for s in t] for t in tags]
subtokens = [[i for s in poster for i in s] for poster in st]
放回带有海报名称的DataFrame
df2 = pd.DataFrame(subtokens, index=df[0]).stack()

In [250]: df2
Out[250]: 
jim   0           yolo_omg
      1               yolo
      2                omg
jack  0            yes_omg
      1    best_place_ever
      2                yes
      3                omg
      4               best
      5              place
      6               ever
neil  0      rofl_so_funny
      1               rofl
      2                 so
      3              funny
dtype: object

【讨论】:

以上是关于pandas - 带有外连接的 DataFrame 扩展的主要内容,如果未能解决你的问题,请参考以下文章

我的 pandas DataFrame 选择没有错误吗?

使用完全外连接在 pandas 中连接两个数据框

Pandas DataFrame 列连接

Join&Merge Pandas Dataframe

绘制带有条件列的 pandas DataFrame

使用 iloc 时的 Pandas SettingWithCopyWarning