1

我有一个这样的数据框

id            Merchant ID  Date                 App Details
601179aa      1           27/01/21 20:03  
[{:appName "FAU-G", :packageName "com.ncoregames.faug"} 
 {:appName "Truecaller", :packageName "com.truecaller"}]

我想要这样的输出

id           Merchant ID  Date                 App Name  Package Name
601179aa          1          27/01/21 20:03        FAU-G com.ncoreagames.faug
601179aa          1          27/01/21 20:03.   True Caller com.truecaller

我试过

df['App Details'] = df['App Details'].str.replace(r"\[","")
df['App Details'] = df['App Details'].str.replace(r"\]","")
foo = lambda x: pd.Series([i for i in (x.split(' '))])
app_df = df['App Details'].apply(foo)

列表中的字典数量不断变化。

4

3 回答 3

2

您可以使用正则表达式来做到这一点:

df=pd.DataFrame({'id': {0: '601179aa'},
 'Merchant': {0: 1},
 'ID': {0: '27/01/21'},
 'Date': {0: '20:03'},
 'App Details': {0: '[{:appName"FAU-G".:packageName"com.ncoreagames.faug"}{:appName"Truecaller",:packageName"com.truecaller"}]'}})

import re

df['App Details']=df['App Details'].str.split("}{")

    
df=df.explode('App Details')

df['App Name']=df['App Details'].apply(lambda x:re.findall('appName"(.+?)"',x)).explode()
df['Package Name']=df['App Details'].apply(lambda x:re.findall('packageName"(.+?)"',x)).explode()


     App Name          Package Name
0       FAU-G  com.ncoreagames.faug
0  Truecaller        com.truecaller
于 2021-01-31T14:25:32.843 回答
1

您可以通过以下方式开始:

  1. 将单元格扩展为多行:
df1 = pd.concat([pd.Series(row['id'], row['App'].split('}{'))        
                  for _, row in df.iterrows()]).reset_index().rename(columns = {'index':'temp1', 0:'id'})
df1['temp1'] = df1['temp1'].str.replace(r'\[{|}\]', '')
df1 

要得到这个(注意列名的变化):

temp1   id
0   :appName"FAU-G",:packageName"com.ncoreagames.f...   601179aa
1   :appName"Truecaller",:packageName"com.truecaller"   601179aa
  1. 将新行字符串拆分为多列:此处代码还获取列的名称并适当地重命名它们(假设所有行都以 :appName 或 :packageName 开头 - 否则在findall步骤中调整正则表达式)
df2 = df1["temp1"].str.split(",", n= 1 ,expand = True) 
names = []
for col in df2.columns:
    name = re.findall('(?<=\:)(.*?)(?=\")',df2[col][0])[0]
    df2.loc[:,col] = df2[col].str.replace(name, '')
    df2.loc[:,col] = df2[col].str.replace('\"|\:', '')
    names.append(name)
df2.columns = names
df2

你得到这个:

    appName packageName
0   FAU-G   com.ncoreagames.faug
1   Truecaller  com.truecaller
  1. 使用新的列名将它们放在一起:
finaldf = df[['id', 'Merchant','ID',    'Date', 'Details']].merge(df1[['id']].merge(df2, left_index = True, right_index = True, how = 'inner'), on = 'id')
finaldf


id  Merchant    ID  Date    Details appName packageName
0   601179aa    1   27/01/21    20:03   NaN FAU-G   com.ncoreagames.faug
1   601179aa    1   27/01/21    20:03   NaN Truecaller  com.truecaller
于 2021-01-31T16:09:08.173 回答
1

您的字符串看起来与 json 非常相似。一种方法可能是将字符串转换为有效的 json 并读入字典。然后explode,并使用json_normalize提取信息,最后将索引设置为正确的值。

与公认的答案相比,这种方法的一个好处是它更通用。如果您的结构不容易转换为 json,这种方法可能会失败。

在示例中,我假设键都是单词并且,记录之间没有,但可能有几个空格(实际上是非字母字符)。

import json
import pandas as pd

df = pd.DataFrame({
        'id': ['601179aa'],
        'Merchant ID': [1],
        'Date': ['27/01/21 20:03'],
        'App Details': [
            '[{:appName "FAU-G", :packageName "com.ncoreagames.faug"}{:appName "Truecaller", :packageName "com.truecaller"}]'
            ]
})

idx_cols = ['id', 'Merchant ID', 'Date']

df2 = df.set_index(idx_cols)['App Details'] \
  .str.replace(':(\w+)', '"\\1":') \
  .str.replace('}\W*{', '},{') \
  .apply(json.loads).explode()

df3 = pd.json_normalize(df2).set_index(df2.index).reset_index()

df3 输出:

         id  Merchant ID            Date     appName           packageName
0  601179aa            1  27/01/21 20:03       FAU-G  com.ncoreagames.faug
1  601179aa            1  27/01/21 20:03  Truecaller        com.truecaller
于 2021-01-31T17:43:41.093 回答