如何在数据框中的列之间进行匹配并保留另一列

时间:2019-04-21 21:46:44

标签: python python-3.x pandas postgresql dataframe

我想从数据框中的一列中获取匹配项。下面是一个示例:

  date        tableNameFrom   tableNameJoin   attributeName
1 29-03-2019  film            language        [film.languageId, language.languageID]
2 30-03-2019  inventory       rental          [invetory.inventoryId, rental.filmId]

在上面的示例中,我想在tablenameFrom和tablenameJoin与attributeName之间进行匹配。但是,我想保留日期列。这里是期望的输出:

  date        tableName    attributeName
1 29-03-2019  film         languageId
2 29-03-2019  language     languageID
3 30-03-2019  inventory    inventoryId
4 30-03-2019  rental       filmId

任何想法我该怎么办?谢谢。

4 个答案:

答案 0 :(得分:2)

这可能不是您想要的,但是会产生给定数据帧的预期输出:

(df.set_index('date').attributeName.apply(pd.Series).stack()
 .reset_index().drop('level_1', axis=1).set_index('date')[0]
 .str.split('.').apply(pd.Series)
 )

它忽略tableNameFrometableNameJoin,并假定它们在attributeName中给出。

+----+------------+----------+-------------+
|    |       date |        0 |           1 |
|----+------------+----------+-------------|
|  0 | 29-03-2019 |     film |  languageId |
|  1 | 29-03-2019 | language |  languageID |
|  2 | 30-03-2019 | invetory | inventoryId |
|  3 | 30-03-2019 |   rental |      filmId |
+----+------------+----------+-------------+

答案 1 :(得分:1)

这是avoids using apply

的一种可能方法

原始DataFrame

         date tableNameFrom tableNameJoin                           attributeName
0  29-03-2019          film      language  [film.languageId, language.languageID]
1  30-03-2019     inventory        rental   [invetory.inventoryId, rental.filmId]

步骤1-(1)使用attributeName作为分隔符,将,分成2个单独的列,(2)删除不需要的方括号([]), (3)删除不必要的列

# 1
df[['tableName','attributeName2']] = df['attributeName'].str.split(',', expand=True)

# 2
df['tableName'] = df['tableName'].str.strip('[')
df['attributeName2'] = df['attributeName2'].str.strip(']')

# 3
df.drop(['attributeName','tableNameFrom','tableNameJoin'], axis=1, inplace=True)

print(df)
         date             tableName        attributeName2
0  29-03-2019       film.languageId   language.languageID
1  30-03-2019  invetory.inventoryId         rental.filmId

第2步-最后,使用this SO post将列tableNameattributeName2中的行拆分为单独的列

df_match = (df.set_index(['date'])
               .stack()
               .str.split('.', expand=True)
               .stack()
               .unstack(-1)
               .reset_index(-1, drop=True)
               .reset_index()
            )
df_match.columns = ['date','tableName','attributeName']

print(df_match)
         date  tableName attributeName
0  29-03-2019       film    languageId
1  29-03-2019   language    languageID
2  30-03-2019   invetory   inventoryId
3  30-03-2019     rental        filmId

详细信息

  • .set_index(['date']-设置要保留的列作为DataFrame的索引
  • .stack()-堆叠行
  • .str.split('.', expand=True)-按句点(.调用str.split将这些单元格拆分为单独的列
  • .stack()-摆脱NULL的值,因此再次调用stack
  • .unstack(-1)
    • 因为我们希望索引的最后一级成为我们的列,所以请使用unstack(-1)进行取消堆栈(在最后一级取消堆栈)
    • 我已经在下面详细显示了此内容 1
  • .reset_index(-1, drop=True)-使用reset_index(-1)
  • 消除多余的最后一级

1 这是.unstack(-1)步骤之前的输出,并解释了为什么我们需要在-1

中使用unstack()
df_intermediate = (df.set_index(['date'])
                       .stack()
                       .str.split('.', expand=True)
                       .stack()
                )

print(df_intermediate)
date                         
29-03-2019  tableName       0           film
                            1     languageId
            attributeName2  0       language
                            1     languageID
30-03-2019  tableName       0       invetory
                            1    inventoryId
            attributeName2  0         rental
                            1         filmId
dtype: object
  • 这表明我们希望最后一个索引级别(值为0、1)成为列,因此我们在-1中选择.unstack(-1)

答案 2 :(得分:0)

df.drop(["tableNameFrom","tableNameJoin"],inplace=True)
df2=pd.DataFrame()
for row in df.itertuples():
    for i in range(2):
        df2=df2.append(pd.Series(
            [row[1],"".join(row[2][i].split('.')[0]),"".join(row[2][i].split('.')[1])]).T,ignore_index=True)
df2.columns=["date","tableName","tableAttribute"]
df2

不明白为什么需要中间两列,所以我将它们放下。

答案 3 :(得分:0)

这基本上是一个melt问题,但有一个中间步骤来清理您的attributeName列:


# Clean up attributeName column by converting it to string and expanding it by splitting
df = pd.concat([df, df.attributeName.apply(lambda x: ' '.join(x).split('.')[1]).str.split(expand=True)], axis=1)\
     .drop('attributeName', axis=1)\
     .rename({0:'attribute1', 1:'attribute2'}, axis=1)

这给了我们以下数据框:

print(df)
         date tableNameFrom tableNameJoin   attribute1 attribute2
0  29-03-2019          film      language   languageId   language
1  30-03-2019     inventory        rental  inventoryId     rental

然后我们可以使用melt两次来获得所需的输出:

df1 = df.melt(id_vars='date', value_vars=['tableNameFrom', 'tableNameJoin'], value_name='tableName').drop('variable', axis=1)
df2 = df.melt(id_vars='date', value_vars=['attribute1', 'attribute2'], value_name='attributeName').drop(['variable', 'date'], axis=1)

df = pd.concat([df1, df2], axis=1)

哪个给了我们最终的输出:

print(df)
        date  tableName attributeName
0  29-03-2019       film    languageId
1  30-03-2019  inventory   inventoryId
2  29-03-2019   language      language
3  30-03-2019     rental        rental