Я работаю с сериями, которые выглядят примерно так:

l0 = ['smartphone', 'battery', 'case', 'grey', '10071852']
l1 = ['phone', 'new', 'charging', 'case', 'white']
l2 = ['tablet', 'phone', 'pin', 'adapter', 'ex766']
l3 = ['phone', 'silicon', 'case', 'brown']

mySeries = pd.Series([l0,l1,l2,l3])

print(mySeries)

0    [smartphone, battery, case, grey, 10071852]
1            [phone, new, charging, case, white]
2           [tablet, phone, pin, adapter, ex766]
3                  [phone, silicon, case, brown]

И я пытаюсь найти ключевые слова и наборы ключевых слов, которые могут содержаться в каждой строке (каждом списке) Серии. В частности, скажем, я хочу узнать, содержит ли строка в Серии следующие ключевые слова:

simple_keywords = {'case', 'adapter'}

Но также найдите, если серия содержит следующие пары ключевых слов:

double_keywords = {'battery case', 'charging case'}

Чтобы искать простые ключевые слова, это кажется легким. Тем не менее, я хочу также найти пары и убедиться, что, если есть пара, такая как «случай батареи», я хочу, чтобы она возвращала пару ключевых слов, а не только «случай».

Кроме того, у меня есть датафрейм, который выглядит следующим образом:

d = {'Date': ['03/08/2014', '04/08/2014', '05/08/2014', '06/08/2014'], 'Product': ['none', 'none','none','none'],'Frequency': [5, 10, 1, 2]}
myDF = pd.DataFrame(data=d)

print(myDF)

         Date  Frequency Product
0  03/08/2014          5    none
1  04/08/2014         10    none
2  05/08/2014          1    none
3  06/08/2014          2    none

Моя конечная цель - записать в этот фрейм данных (в столбце «Продукт») соответствующее ключевое слово (или пару ключевых слов), которые я определил в Серии. Каждая строка Series соответствует одной и той же строке в кадре данных, что означает, что порядок очень важен. Я хочу видеть, что продукт «чехол для батареи», 3 августа 2014 года, имел частоту 5.

Я попытался найти какое-то решение, разделив пары ключевых слов, но оно кажется очень медленным и не таким эффективным, поскольку у меня есть более 350 000 строк в серии, с которой я работаю (оставил на ночь, и это было закончили):

first_keywords = {'case', 'adapter'}
second_keywords = {'battery', 'charging'}    

mySeries_range = len(mySeries)

for i in range(mySeries_range):
        for x, y in [(x, y) for x in first_keywords for y in second_keywords]:
            if x in mySeries[i] and y in mySeries[i]:
                myDF.Product[i] = y + ' ' + x
            elif x in mySeries[i] and y not in mySeries[i]:
                myDF.Product[i] = x

И конечный результат, который я хочу получить:

         Date  Frequency        Product
0  03/08/2014          5   battery case
1  04/08/2014         10  charging case
2  05/08/2014          1        adapter
3  06/08/2014          2           case

Если бы кто-то мог мне помочь, это было бы здорово. Извиняюсь, если мой код не такой красивый ... Стараюсь поправиться!

1
Notna 23 Фев 2018 в 15:08

3 ответа

Лучший ответ

Вы можете создать столько слов, сколько хотите, из слова в списке mySeries следующим образом:

import itertools
df_comb = pd.concat([mySeries.apply(lambda x: [" ".join(l) 
                     for l in list(itertools.combinations(x,max_len))
                     ]).rename(max_len) 
                     for max_len in [1,2]],axis=1).astype(str)

Это результат:

>>> df_comb                                             1  \
0  [smartphone, battery, case, grey, 10071852]   
1          [phone, new, charging, case, white]   
2         [tablet, phone, pin, adapter, ex766]   
3                [phone, silicon, case, brown]   

                                                   2  
0  [smartphone battery, smartphone case, smartpho...  
1  [phone new, phone charging, phone case, phone ...  
2  [tablet phone, tablet pin, tablet adapter, tab...  
3  [phone silicon, phone case, phone brown, silic...  

Теперь давайте сделаем словесные слова списком, чтобы легче было повторять:

simple_keywords = ['case', 'adapter']
double_keywords = ['battery case', 'charging case']

Тогда вы можете посчитать элементы следующим образом:

>>> pd.concat([df_comb.apply(lambda x: pd.Series(x).str.count(w),axis=0)[len(' '.split(w))].rename(w) 
for w in simple_keywords],axis=1)
   case  adapter
0     1        0
1     1        0
2     0        1
3     1        0

>>> pd.concat([df_comb.apply(lambda x: pd.Series(x).str.count(w),axis=0)[len(w.split(' '))].rename(w) for w in double_keywords],axis=1)

  battery case  charging case
0             1              0
1             0              1
2             0              0
3             0              0

Или мы можем сделать это итерацией следующим образом:

df_count = pd.DataFrame()
for list_of_keywords in [simple_keywords, double_keywords]:
    df_count_temp = pd.concat([df_comb.apply(lambda x: pd.Series(x).str.count(w),
                               axis=0)[len(w.split(' '))].rename(w) 
                               for w in list_of_keywords],axis=1)
    df_count = pd.concat([df_count, df_count_temp],axis=1)

Счет будет тогда:

>>> df_count

   case  adapter  battery case  charging case
0     1        0             1              0
1     1        0             0              1
2     0        1             0              0
3     1        0             0              0

Вы можете получить окончательный счет следующим образом:

>>> df_count.sum(axis=0).to_frame()

               0
case           3
adapter        1
battery case   1
charging case  1

Вы можете создать функцию, чтобы применять это к записям каждого дня.

def my_func(mySeries, keywords =  [['case', 'adapter'] ,['battery case', 'charging case']]):
    import itertools
    keyword_lengths = [len(k[0].split(' ')) for k in keywords]
    df_comb = pd.concat([mySeries.apply(lambda x: [" ".join(l) 
                         for l in list(itertools.combinations(x,max_len))
                         ]).rename(max_len) 
                         for max_len in keyword_lengths],axis=1).astype(str)

    df_count = pd.DataFrame()
    for list_of_keywords in keywords:
        df_count_temp = pd.concat([df_comb.apply(lambda x:pd.Series(x).str.count(w),
                                   axis=0)[len(w.split(' '))].rename(w) 
                                   for w in list_of_keywords],axis=1)
        df_count = pd.concat([df_count, df_count_temp],axis=1)

    return df_count

Представьте, что это ваш pd.Series:

>>> newSeries 
2014-03-08    [smartphone, battery, case, grey, 10071852]
2014-03-08            [phone, new, charging, case, white]
2014-03-08           [tablet, phone, pin, adapter, ex766]
2014-03-08                  [phone, silicon, case, brown]
2014-04-08            [phone, new, charging, case, white]
2014-04-08                           [tablet, phone, pin]
2014-04-08                               [phone, adapter]
dtype: object



>>> my_func(newSeries)

            case  adapter  battery case  charging case
2014-03-08     1        0             1              0
2014-03-08     1        0             0              1
2014-03-08     0        1             0              0
2014-03-08     1        0             0              0
2014-04-08     1        0             0              1
2014-04-08     0        0             0              0
2014-04-08     0        1             0              0

Затем вы можете поиграть с возвращенным фреймом данных, группировкой по датам и подсчетом элементов. Таким образом, вы получите появления по дате:

>>> df_appearances= my_func(newSeries).reset_index().groupby('index'
                     ).sum().T.unstack().reset_index()

>>> df_appearances.columns = ['Date', 'Product', 'Frequency']

>>> df_appearances

        Date        Product  Frequency
0 2014-03-08           case          3
1 2014-03-08        adapter          1
2 2014-03-08   battery case          1
3 2014-03-08  charging case          1
4 2014-04-08           case          1
5 2014-04-08        adapter          1
6 2014-04-08   battery case          0
7 2014-04-08  charging case          1
1
Mabel Villalba 23 Фев 2018 в 14:07

Для первой части о поиске ключевых слов, которые соответствуют вашему Series(), я бы предложил следующее:

mySeries.apply(lambda l: " ".join(e for e in keywords if all(keyword in l for keyword in e.split())))

Извините за формулировку, которая должна (должна) быть улучшена. Но идея состоит в том, чтобы просто проверить, находятся ли все элементы в ваших входных строках (разделенных по умолчанию " ") в строке Series. Если они это сделают, верните их.

Вы можете использовать это с simple_keywords или double_keywords (вместо keywords в моей строке, я думаю, это работает.

С simple_keywords:

0       case
1       case
2    adapter
3       case

С double_keywords:

0     battery case
1    charging case
2                 
3            
0
Arnaud 23 Фев 2018 в 13:08

Используя панд векторизованный метод

df=pd.Series([l0,l1,l2,l3])
df=df.apply(''.join)

df[df.str.contains('batterycase')]='batterycase'
df[df.str.contains('chargingcase')]='chargingcase'
df[df.str.contains('case')&~(df.str.contains('chargingcase') |(df.str.contains('batterycase')))]='case'
df[df.str.contains('adapter')]='adapter'

d = {'Date': ['03/08/2014', '04/08/2014', '05/08/2014', '06/08/2014'],'Frequency': [5, 10, 1, 2]}
myDF = pd.DataFrame(data=d)

myDF['Product']=df

Результат

        Date       Frequency       Product
0     03/08/2014          5    batterycase
1     04/08/2014         10    chargingcase
2     05/08/2014          1       adapter
3     06/08/2014          2          case
0
Rayadurai 23 Фев 2018 в 13:24