【问题标题】:Extracting specific rows from a data frame从数据框中提取特定行
【发布时间】:2017-08-08 03:25:30
【问题描述】:

我有一个数据框 df1,其中包含两列“ids”和“names”-

ids     names
fhj56   abc
ty67s   pqr
yu34o   xyz

我有另一个数据框 df2,其中一些列是 -

user     values                       
1        ['fhj56','fg7uy8']
2        ['glao0','rt56yu','re23u']
3        ['fhj56','ty67s','hgjl09']

我的结果应该给我那些来自 df2 的用户,其值包含至少一个来自 df1 的 id,并且还告诉哪些 id 负责将它们放入结果表中。结果应该看起来像 -

   user     values_responsible     names
   1        ['fhj56']              ['abc']
   3        ['fhj56','ty67s']      ['abc','pqr']

用户 2 没有出现在结果表中,因为它的值都不存在于 df1 中。

我试图这样做 -

df2.query('values in @df1.ids')

但这似乎效果不佳。

【问题讨论】:

  • 您需要取消嵌套您的列values

标签: python pandas


【解决方案1】:

您可以遍历行,然后使用.locisindf2 中查找匹配的行。我将此过滤后的数据框转换为字典

ids = []
names = []
users = []
for _, row in df2.iterrows():
    result = df1.loc[df1['ids'].isin(row['values'])]
    if not result.empty:
        ids.append(result['ids'].tolist())
        names.append(result['names'].tolist())
        users.append(row['user'])

>>> pd.DataFrame({'user': users, 'values_responsible': ids, 'names': names})[['user', 'values_responsible', 'names']]
   user values_responsible       names
0     1            [fhj56]       [abc]
1     3     [fhj56, ty67s]  [abc, pqr]

或者,对于整洁的数据:

ids = []
names = []
users = []
for _, row in df2.iterrows():
    result = df1.loc[df1['ids'].isin(row['values'])]
    if not result.empty:
        ids.extend(result['ids'].tolist())
        names.extend(result['names'].tolist())
        users.extend([row['user']] * len(result['ids']))

>>> pd.DataFrame({'user': users, 'values_responsible': ids, 'names': names})[['user', 'values_responsible', 'names']])
   user values_responsible names
0     1              fhj56   abc
1     3              fhj56   abc
2     3              ty67s   pqr

【讨论】:

  • Pandas 中的逐行操作是解决问题的一种相当肮脏的方法。 Here's 很好地解释了原因。在许多情况下,可以通过逐行迭代直观地解决的数据帧问题也可以通过切割器过滤或应用applymap 函数来解决。
  • 是的,逐行不是最有效的,但那是因为开始时数据不整齐。
【解决方案2】:

试试这个,使用取消嵌套列表单元的想法。

Temp_unnest = pd.DataFrame([[i, x]
              for i, y in df['values'].apply(list).iteritems()
                  for x in y], columns=list('IV'))

Temp_unnest['user']=Temp_unnest.I.map(df.user)
df1.index=df1.ids
Temp_unnest.assign(names=Temp_unnest.V.map(df1.names)).dropna().groupby('user')['V','names'].agg({(lambda x: list(x))})


Out[942]: 
                   V       names
            <lambda>    <lambda>
user                            
1            [fhj56]       [abc]
3     [fhj56, ty67s]  [abc, pqr]

【讨论】:

    【解决方案3】:

    我会重构您的第二个数据框(本质上是标准化您的数据库)。类似的东西

    user     gid     id                       
    1        1       'fhj56'
    1        1       'fg7uy8'
    2        1       'glao0'
    2        1       'rt56yu'
    2        1       're23u'
    3        1       'fhj56'
    3        1       'ty67s'
    3        1       'hgjl09'
    

    然后,您所要做的就是合并 id 列上的第一个和第二个数据框。

    r = df2.merge(df1, left_on='id', right_on='ids', how='left')
    

    您可以排除某些 id 没有匹配名称的任何 gid。

    r[~r[gid].isin(  r[r['names'] == None][gid].unique()  )]
    

    其中r[r['names'] == None][gid].unique() 查找所有没有名称的gid,然后r[~r[gid].isin( ... )] 只抓取不在isin 的列表参数中的条目。


    如果您有更多的 id 组,第二个表可能看起来像

    user     gid     id                       
    1        1       'fhj56'
    1        1       'fg7uy8'
    1        2       '1asdf3'
    1        2       '7ada2a'
    1        2       'asd341'
    2        1       'glao0'
    2        1       'rt56yu'
    2        1       're23u'
    3        1       'fhj56'
    3        1       'ty67s'
    3        1       'hgjl09'
    

    相当于

    user     values                       
    1        ['fhj56','fg7uy8']
    1        ['1asdf3', '7ada2a', 'asd341']
    2        ['glao0','rt56yu','re23u']
    3        ['fhj56','ty67s','hgjl09']
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-22
      • 2023-03-07
      • 2022-09-30
      • 2021-11-27
      • 2017-02-03
      相关资源
      最近更新 更多