Создание отдельного столбца в кадре данных после итерации функции groupby - PullRequest
0 голосов
/ 29 июня 2018

У меня очень большой фрейм данных, который похож на первые четыре столбца этого фрейма данных. Я пытаюсь сгенерировать 5-й, т. Е. Столбец DataType, который соответствует типу данных столбца «Word».

Обратите внимание, что тип данных соответствует "WEEKDAY", "DATE" и т. Д., А не типу данных python.

Page    LineNum    Word    Line                     DataType
1        1         Today   Today is 5th Sept 2015   NULL
1        1         is      Today is 5th Sept 2015   NULL
1        1         5th     Today is 5th Sept 2015   DATE
1        1         Sept    Today is 5th Sept 2015   DATE
1        1         2015    Today is 5th Sept 2015   DATE
...
1        4         Sunday  Sunday will be Sept 8th  WEEKDAY 
1        4         will    Sunday will be Sept 8th  NULL
1        4         be      Sunday will be Sept 8th  NULL
1        4         Sept    Sunday will be Sept 8th  DATE
1        4         8th     Sunday will be Sept 8th  DATE

У меня есть отдельные функции, которые извлекают список всех подстрок определенного типа данных из строки. Скажем isit_date возвращает ['5th Sept 2015'] для 1-й строки 1 *

Чтобы получить столбец DataType, я использую функции groupby и lambda. Здесь много страниц и много строк.

Я пытаюсь сделать это с помощью следующего кода:

file_dataframe['DataType'] = 'NULL'
for name, groups in file_dataframe.groupby(['Page', 'LineNum']):
    list_of_dates = isit_date(str(groups['Line'][0]))
    groups['DataType'] = groups['Word'].apply(lambda x: "DATE" if x in list_of_dates else 'NULL')

Я вижу много недостатков в этом. Группы не будут записываться в исходный фрейм данных ... но, тем не менее, получаю ошибку в этом коде. Может кто-нибудь предложить правильный и эффективный подход.

Я пытаюсь использовать групповые, потому что Функция isit_date () занимает некоторое время, и я не хочу повторять это для каждой группы, поскольку строка для каждой группы одинакова.

Я использую Python 3 и панд. Пожалуйста, прокомментируйте, если есть что-то еще, что мне нужно объяснить по моему вопросу.

Вот код isit_date

import datetime
import datefinder as dt
from dateutil.parser import parse
from commonregex import CommonRegex


    class FindDates:

        def __init__(self):
            pass

        def isit_date(self, s):
            commonregex_object = CommonRegex(s)
            dates_list = commonregex_object.dates
            additional_dates = [x for x in s.split(" ") if len(x) == 8 and x.isdigit()]
            if len(additional_dates) > 0:
                additional_dates = [x[0:2]+"/"+x[2:4]+"/"+x[4:] for x in additional_dates]
                dates_list.extend(additional_dates)
            datefinder_dates = [w[1] for w in list(dt.find_dates(s, source=True))]
            dates_list.extend(datefinder_dates)
            return self.verify_dates(dates_list)

        @staticmethod
        def verify_dates(dates_list):
            dates_list = list(set(dates_list))
            min_year = datetime.datetime.now().year - 200
            max_year = min_year + 400
            return_date_list = []
            for each_date in dates_list:
                try:
                    dt_obj = parse(each_date)
                    if min_year <= dt_obj.year <= max_year:
                        return_date_list.append(each_date)
                except:
                    pass
            return return_date_list

Ответы [ 3 ]

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

Я обнаружил, что apply + lambda часто неэффективен при строковых операциях по сравнению со списочными вычислениями с итерацией. Вот альтернативный подход:

# define row iterator
unique_tups = df.drop_duplicates(subset=['Page', 'LineNum']).itertuples()

# construct dictionary mapping page + line to set of dates
d = {(row['Page'], row['LineNum']): set(isit_date(str(row['Line']))) \
     for row in unique_tups}

# apply membership test in list comprehension
df['DateType'] = [row['Word'] in d[(row['Page'], row['LineNum'])] \
                  for row in df.itertuples()]

# use Pandas for Boolean mapping, which we know is efficient in Pandas
mapper = {True: 'Date', False: 'Null'}
df['DateType'] = df['DateType'].map(mapper)
0 голосов
/ 29 июня 2018

Вам не нужно использовать groupby для этого. Вы можете просто сделать:

df['isit_date'] = df.Line.map(isit_date)
df['DataType'] = df.apply(lambda row: "DATE" if row.Word in row.isit_date else "NULL", axis=1)
0 голосов
/ 29 июня 2018

Вы можете попробовать создать пользовательскую функцию:

def isit_date(x):
    return ['5th Sept 2015', 'Sept 8th']

def f(x):
    #split and flatten all values to one list of words
    list_of_dates = [y for x in isit_date(str(x['Line'].iat[0])) for y in x.split()]

    x['DataType'] = x['Word'].apply(lambda x: "DATE" if x in list_of_dates else 'NULL')
    return x

df = file_dataframe.groupby(['Page', 'LineNum']).apply(f)

print (df)
   Page  LineNum    Word                     Line DataType
0     1        1   Today   Today is 5th Sept 2015     NULL
1     1        1      is   Today is 5th Sept 2015     NULL
2     1        1     5th   Today is 5th Sept 2015     DATE
3     1        1    Sept   Today is 5th Sept 2015     DATE
4     1        1    2015   Today is 5th Sept 2015     DATE
5     1        4  Sunday  Sunday will be Sept 8th     NULL
6     1        4    will  Sunday will be Sept 8th     NULL
7     1        4      be  Sunday will be Sept 8th     NULL
8     1        4    Sept  Sunday will be Sept 8th     DATE
9     1        4     8th  Sunday will be Sept 8th     DATE
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...