Как извлечь данные из текстового поля в панде dataframe? - PullRequest
0 голосов
/ 06 июня 2018

Я хочу получить распределение тегов из этого фрейма данных:

df=pd.DataFrame([
    [43,{"tags":["webcom","start","temp","webcomfoto","dance"],"image":["https://image.com/Kqk.jpg"]}],
    [83,{"tags":["yourself","start",""],"image":["https://images.com/test.jpg"]}],
    [76,{"tags":["en","webcom"],"links":["http://webcom.webcomdb.com","http://webcom.webcomstats.com"],"users":["otole"]}],
    [77,{"tags":["webcomznakomstvo","webcomzhiznx","webcomistoriya","webcomosebe","webcomfotografiya"],"image":["https://images.com/nt4wzguoh/y_a3d735b4.jpg","https://images.com/sucb0u24x/b1sd_Naju.jpg"]}],
    [81,{"tags":["webcomfotografiya"],"users":["myself","boattva"],"links":["https://webcom.com/nk"]}],
],columns=["_id","tags"])

Мне нужно получить таблицу с числом идентификаторов с определенным количеством тегов.например.

 Number of posts | Number of tags 
      31                9
      44                8
      ...
      129               1

Я использовал этот подход для случая, когда «теги» - единственное поле.В этом фрейме данных у меня также есть «изображение», «пользователи» и другие текстовые поля со значениями.Как я должен обрабатывать данные в этом случае?

Спасибо

Ответы [ 4 ]

0 голосов
/ 06 июня 2018

Проблема в том, что ваши данные в столбце tags являются strings, нет dictionaries.

Поэтому необходимо выполнить первый шаг:

import ast

df['tags'] = df['tags'].apply(ast.literal_eval)

, а затем применить оригинальный ответ, работаяочень хорошо, если несколько полей.

Проверка:

df=pd.DataFrame([
    [43,{"tags":[],"image":["https://image.com/Kqk.jpg"]}],
    [83,{"tags":["yourself","start",""],"image":["https://images.com/test.jpg"]}],
    [76,{"tags":["en","webcom"],"links":["http://webcom.webcomdb.com","http://webcom.webcomstats.com"],"users":["otole"]}],
    [77,{"tags":["webcomznakomstvo","webcomzhiznx","webcomistoriya","webcomosebe","webcomfotografiya"],"image":["https://images.com/nt4wzguoh/y_a3d735b4.jpg","https://images.com/sucb0u24x/b1sd_Naju.jpg"]}],
    [81,{"tags":["webcomfotografiya"],"users":["myself","boattva"],"links":["https://webcom.com/nk"]}],
],columns=["_id","tags"])
#print (df)

#convert column to string for verify solution
df['tags'] = df['tags'].astype(str)

print (df['tags'].apply(type))
0    <class 'str'>
1    <class 'str'>
2    <class 'str'>
3    <class 'str'>
4    <class 'str'>
Name: tags, dtype: object

#convert back
df['tags'] = df['tags'].apply(ast.literal_eval)

print (df['tags'].apply(type))
0    <class 'dict'>
1    <class 'dict'>
2    <class 'dict'>
3    <class 'dict'>
4    <class 'dict'>
Name: tags, dtype: object

c = Counter([len(x['tags']) for x in df['tags']])

df = pd.DataFrame({'Number of posts':list(c.values()), ' Number of tags ': list(c.keys())})
print (df)
   Number of posts   Number of tags 
0                1                 0
1                1                 3
2                1                 2
3                1                 5
4                1                 1
0 голосов
/ 06 июня 2018

Вы можете использовать аксессор str для доступа к словарным ключам и len с value_counts:

df.tags.str['tags'].str.len().value_counts()\
  .rename('Posts')\
  .rename_axis('Tags')\
  .reset_index()

Вывод:

   Tags  Posts
0     5      2
1     3      1
2     2      1
3     1      1
0 голосов
/ 06 июня 2018

Обновление: используйте комбинацию из f-строк, словаря и списка, чтобы извлечь длину всех списков в столбце tags, кратко:

extract_dict = [{f'count {y}':len(z) for y,z in x.items()} for x in df.tags]

# construct new df with only extracted counts
pd.DataFrame.from_records(extract_dict)

# new df with extracted counts & original data
df.assign(**pd.DataFrame.from_records(extract_dict))

# outputs:

   _id                                               tags  count image  \
0   43  {'tags': ['webcom', 'start', 'temp', 'webcomfo...          1.0
1   83  {'tags': ['yourself', 'start', ''], 'image': [...          1.0
2   76  {'tags': ['en', 'webcom'], 'links': ['http://w...          NaN
3   77  {'tags': ['webcomznakomstvo', 'webcomzhiznx', ...          2.0
4   81  {'tags': ['webcomfotografiya'], 'users': ['mys...          NaN

   count links  count tags  count users
0          NaN           5          NaN
1          NaN           3          NaN
2          2.0           2          1.0
3          NaN           5          NaN
4          1.0           1          2.0

оригинальный ответ:

Если вы заранее знаете имена столбцов, можно использовать списки для этой задачи

 extract = [(len(x.get('tags',[])), len(x.get('images',[])), len(x.get('users',[])))     
  for x in df.tags]
 # extract outputs:
 [(5, 0, 0), (3, 0, 0), (2, 0, 1), (5, 0, 0), (1, 0, 2)]

, которые затем можно использовать для создания нового кадра данных или для назначения дополнительных столбцов

# creates new df
pd.DataFrame.from_records(
  extract, 
  columns=['count tags', 'count images', 'count users']
)

# creates new dataframe with extracted data and original df
df.assign(
    **pd.DataFrame.from_records(
        extract, 
        columns=['count tags', 'count images', 'count users'])
)

Последнее выражение выдает следующий вывод:

   _id                                               tags  count tags  \
0   43  {'tags': ['webcom', 'start', 'temp', 'webcomfo...           5
1   83  {'tags': ['yourself', 'start', ''], 'image': [...           3
2   76  {'tags': ['en', 'webcom'], 'links': ['http://w...           2
3   77  {'tags': ['webcomznakomstvo', 'webcomzhiznx', ...           5
4   81  {'tags': ['webcomfotografiya'], 'users': ['mys...           1

   count images  count users
0             0            0
1             0            0
2             0            1
3             0            0
4             0            2
0 голосов
/ 06 июня 2018

Придерживаясь collections.Counter, вот один из способов:

from collections import Counter
from operator import itemgetter

c = Counter(map(len, map(itemgetter('tags'), df['tags'])))

res = pd.DataFrame.from_dict(c, orient='index').reset_index()
res.columns = ['Tags', 'Posts']

print(res)

   Tags  Posts
0     5      2
1     3      1
2     2      1
3     1      1
...