Python Pandas: таблица поиска путем поиска подстроки

У меня есть фрейм данных со столбцом для пользовательских агентов приложения. Что мне нужно сделать, так это определить конкретное приложение из этого столбца. Например,

NewWordsWithFriendsFree/2.3 CFNetwork/672.1.15 Darwin/14.0.0 будет отнесен к категории Words With Friends.

iPhone3,1; iPhone OS 7.1.2; com.fingerarts.sudoku2; 143441-1,24 will be Sudoku by FingerArts etc.

У меня будет еще один кадр данных со строками, которые мне нужно сопоставить. Например,

Keyword                 Game 
NewWordsWithFriends     Words With Friends
com.fingerarts.sudoku   Sudoku by FingerArts

Как мне сделать такой поиск для фрейма данных pandas? Например, кадр данных похож на

user    date                 user-agent
 A      2015-09-02 13:45:56  NewWordsWithFriendsFree/2.3 CFNetwork/672.1.15 Darwin/14.0.0
 B      2015-08-31 23:04:21  iPhone3,1; iPhone OS 7.1.2; com.fingerarts.sudoku2; 143441-1,24

Мне нужен новый столбец GameName после поиска.


person sfactor    schedule 02.09.2015    source источник


Ответы (2)


Одним из возможных способов достижения этого может быть:

import pandas as pd                                                              

# some example data
qry = pd.DataFrame.from_dict({"Keyword": ["NewWordsWithFriends",                 
                                          "com.fingerarts.sudoku"],              
                              "Game": ["Words With Friends",                     
                                       "Sudoku by FingerArts"]})                 

df = pd.DataFrame.from_dict({"user-agent" : ["NewWordsWithFriendsFree/2.3 CFNetwork/672.1.15 Darwin/14.0.0",     
                                             "iPhone3,1; iPhone OS 7.1.2; com.fingerarts.sudoku2; 143441-1,24"]})

keywords = qry.Keyword.tolist()                                                  
games = qry.Game.tolist()                                                        

def select(x):                                                                   
    for key, game in zip(keywords, games):                                       
        if key in x:                                                             
            return game                                                          

df["GameName"] = df["user-agent"].apply(select)  

Это даст:

In [41]: df
Out[41]: 
                                          user-agent              GameName
0  NewWordsWithFriendsFree/2.3 CFNetwork/672.1.15...    Words With Friends
1  iPhone3,1; iPhone OS 7.1.2; com.fingerarts.sud...  Sudoku by FingerArts

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

Если нет, возможно, оптимизируйте, например, способ проверки строк:

Наличие внешнего цикла для всех возможных игр, а затем использование .apply для возврата результатов для каждой игры по столбцу может ускорить работу, поскольку это позволит избежать цикла для всех игр при каждом вызове select() и т. д.

Чтобы определить узкие места, вы можете использовать line_profiler (см. Как я могу профилировать код Python построчно?).

person chris-sc    schedule 02.09.2015

df = pd.DataFrame({'date' : ['2015-09-02 13:45:56' , '2015-08-31 23:04:21'] , 'user-agent' : ['NewWordsWithFriendsFree/2.3 CFNetwork/672.1.15 Darwin/14.0.0' , 'iPhone3,1; iPhone OS 7.1.2; com.fingerarts.sudoku2; 143441-1,24']  })

map_df = pd.DataFrame({'Keyword' :  ['NewWordsWithFriends' , 'com.fingerarts.sudoku'], 'Game' : [ 'Words With Friends', 'Sudoku by FingerArts'] })

mapping = {vals[1] : vals[0] for vals in  map_df.values}


regex = '|'.join([keyword.replace('.' , '\.') for keyword in map_df['Keyword']])

def get_keyword(user_agent):
    matches = re.findall(regex ,user_agent)
    return matches[0] if len(matches) > 0 else np.nan


df['GameName'] = df['user-agent'].apply(get_keyword)

df['GameName'] = df['GameName'].map(mapping)

другая реализация для функции get_keyword может быть

def get_keyword(user_agent):
    for keyword in map_df['Keyword']:
        if keyword in user_agent:
            return keyword

также еще один способ получить сопоставление - создать series

mapping = pd.Series(map_df['Game'].values , index = map_df.Keyword )
person Nader Hisham    schedule 02.09.2015
comment
интересно посмотреть что быстрее - person Moritz; 02.09.2015