2016-12-07 2 views
1

У меня есть таблица с 150 000 строк и 15 столбцов. Важными столбцами для этого примера являются COUNTRY, COSTCENTER и EXTENSION. Я читаю из CSV в Pandas Dataframe. Все столбцы имеют тип объекта.Нужно фильтровать по нескольким столбцам и изменять значение одного в Python Pandas

То, что я хочу сделать, это:

  1. Поиск определенной страны (например, «Китай»)
  2. Фильтр для этих случаев, когда COSTCENTER является либо 1000 или 2000 или где РАСШИРЕНИЕ начинается с " 862 "
  3. После того, как все фильтры были применены, измените название страны в COUNTRY на что-то новое.

У меня было решение, но я всегда получал предупреждение для выпуска цепным:

df.COUNTRY[df.COUNTRY.str.match("China") & 
       (df.COSTCENTER.str.match("1000") | 
       df.COSTCENTER.str.match("2000"))] = 'China_new_name' 

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

Мой последний подход в настоящее время был:

filter_China = df.ix[(df["COUNTRY"]=="China") & 
((df["COSTCENTER"]=="1000") | (df["COSTCENTER"]=="2000"))] 

и, кажется, процедить, что я ищу (я не включил поиск по РАСПРОСТРАНЕНИЕ еще, как я первый хотел, чтобы это работало).

Но когда я пытаюсь изменить значение, на основе моих критериев поиска, я бег в неприятность:

df.ix[(df["COUNTRY"]=="China") & ((df["COSTCENTER"]=="1000") | 
(df["COSTCENTER"]=="2000")), df["COUNTRY"]] = "China_new_name" 

Я получаю эту ошибку: поднять исключение KeyError («% S не в индексе»% objarr [маска])

Что мне здесь не хватает? Является ли подход правильным или мне нужно идти по другому пути?

ответ

2

Вы должны прочитать section of the documentation на цепи, индексации и SettingWithCopy предупреждения

df.loc[df.COUNTRY.str.match("China") & 
       (df.COSTCENTER.str.match("1000") | 
       df.COSTCENTER.str.match("2000")), "COUNTRY"] = 'China_new_name' 
+0

Спасибо за ваш ответ. Я читал документацию, но мои знания о Python/Pandas все еще слишком низки, чтобы понять это полностью. Просто началось пару недель назад ... Не могли бы вы дать мне понять, почему вы изменили с df ["COUNTRY] ==" Китай "на str.match? И в целом, это правильный подход (например, скорость 44). – SLglider

+0

Я думаю, что 'str.match' не является необходимым. См. мой ответ. – jezrael

+0

Также он медленнее, сравнивается с вашей функцией без' str.startswith', а также медленнее. – jezrael

0

Я думаю, вам нужно сравнить с == и для проверки начала использования строки функции str.startswith:

df = pd.DataFrame({'COUNTRY':['China','China','China', 'USA'], 
        'COSTCENTER':['1000','2000','6000','1000'], 
        'EXTENSION':['86212','11862','1000', '8555']}) 

print (df) 
    COSTCENTER COUNTRY EXTENSION 
0  1000 China  86212 
1  2000 China  11862 
2  6000 China  1000 
3  1000  USA  8555 

df.loc[(df.COUNTRY == "China") & ((df.COSTCENTER == "1000") | (df.COSTCENTER == "2000")) & 
     (df.EXTENSION.str.startswith('862')), "COUNTRY"] = 'China_new_name' 

print (df) 
    COSTCENTER   COUNTRY EXTENSION 
0  1000 China_new_name  86212 
1  2000   China  11862 
2  6000   China  1000 
3  1000    USA  8555 

Другим решением с isin для сравнения нескольких значений столбца:

df.loc[(df.COUNTRY == "China") & (df.COSTCENTER.isin(["1000", "2000"])) & 
     (df.EXTENSION.str.startswith('862')), "COUNTRY"] = 'China_new_name' 

print (df) 
    COSTCENTER   COUNTRY EXTENSION 
0  1000 China_new_name  86212 
1  2000   China  11862 
2  6000   China  1000 
3  1000    USA  8555 

Timings:

df = pd.DataFrame({'COUNTRY':['China','China','China', 'USA'], 
        'COSTCENTER':['1000','2000','6000','1000'], 
        'EXTENSION':['86212','11862','1000', '8555']}) 

#[400000 rows x 3 columns] 
df = pd.concat([df]*100000).reset_index(drop=True) 
print (df) 

In [330]: %timeit df.loc[(df.COUNTRY == "China") & (df.COSTCENTER.isin(["1000", "2000"])) & (df.EXTENSION.str.startswith('862')), "COUNTRY"] = 'China_new_name' 
1 loop, best of 3: 198 ms per loop 

In [331]: %timeit df.loc[(df.COUNTRY == "China") & ((df.COSTCENTER == "1000") | (df.COSTCENTER == "2000")) & (df.EXTENSION.str.startswith('862')), "COUNTRY"] = 'China_new_name' 
1 loop, best of 3: 238 ms per loop 

In [332]: %timeit df.loc[df.COUNTRY.str.match("China") & (df.COSTCENTER.str.match("1000") | df.COSTCENTER.str.match("2000")), "COUNTRY"] = 'China_new_name' 
1 loop, best of 3: 745 ms per loop 
+0

Ах, это довольно круто.Спасибо за выполнение различных тестов. Я должен посмотреть на это позже, чтобы сделать это сам в будущем. – SLglider

+0

Несомненно, никаких проблем. Тогда, если мой ответ был полезным, не забудьте [принять] (http://meta.stackexchange.com/a/5235/295067). Благодарю. – jezrael

Смежные вопросы