Python Pandas заполнить отсутствующий почтовый индекс значениями из другого сервера данных в зависимости от условий - PullRequest
2 голосов
/ 18 июня 2020

У меня есть набор данных, в котором я добавляю координаты городов на основе почтовых индексов, но некоторые из этих почтовых индексов отсутствуют. Кроме того, в некоторых случаях отсутствуют города, штаты или и то, и другое. Например:

     ca_df[['OWNER_CITY', 'OWNER_STATE', 'OWNER_ZIP']] 

     OWNER_CITY OWNER_STATE OWNER_ZIP
   495  MIAMI SHORE PA
   496      SEATTLE 

Однако во втором наборе данных есть город, штат и соответствующие почтовые индексы. Это завершено без каких-либо пропущенных значений.

df_coord.head() 

    OWNER_ZIP   CITY    STATE    
 0  71937   Cove        AR   
 1  72044   Edgemont    AR   
 2  56171   Sherburn    MN   

Я хочу заполнить отсутствующие почтовые индексы в первом фрейме данных, если:

  1. Почтовый индекс пуст
  2. Город присутствует
  3. Статус присутствует

Это операция «все или ничего» означает, что либо все три критерия выполнены, и почтовый индекс заполнен, либо ничего не меняется.

Однако это довольно большой набор данных с> 50 миллионами записей, поэтому в идеале я хочу векторизовать операцию, работая по столбцам.

Технически это подойдет np.where но , насколько мне известно, np.where принимает только условия в следующем формате:

df1['OWNER_ZIP'] = np.where(df["cond"] ==X, df_coord['OWNER_ZIP'], "") 

Как убедиться, что я заполняю только недостающие почтовые индексы, когда все условия соблюдены?

Ответы [ 4 ]

2 голосов
/ 18 июня 2020

Учитывая ca_df:

    OWNER_CITY OWNER_STATE OWNER_ZIP
0  Miami Shore     Florida       111
1  Los Angeles  California       NaN
2      Houston         NaN       NaN

и df_coord:

  OWNER_ZIP         CITY       STATE
0       111  Miami Shore     Florida
1       222  Los Angeles  California
2       333      Houston       Texas

Вы можете использовать pd.notna вместе с pd. DataFrame # index вот так:

inferrable_zips_df = pd.notna(ca_df["OWNER_CITY"]) & pd.notna(ca_df["OWNER_STATE"])
is_inferrable_zip = ca_df.index.isin(df_coord[inferrable_zips_df].index)

ca_df.loc[is_inferrable_zip, "OWNER_ZIP"] = df_coord["OWNER_ZIP"]

с ca_df в результате:

    OWNER_CITY OWNER_STATE OWNER_ZIP
0  Miami Shore     Florida       111
1  Los Angeles  California       222
2      Houston         NaN       NaN

Я изменил "" на np.nan, но если вы все еще wi sh, чтобы использовать "", тогда вам просто нужно изменить pd.notna(ca_df[...]) на ca_df[...] == "".

2 голосов
/ 18 июня 2020

Вы можете комбинировать операторы numpy .where, чтобы объединить несколько правил. Это должно дать вам массив индексов строк, соответствующих каждому из трех правил:

np.where(df["OWNER_ZIP"] == X) and np.where(df["CITY"] == Y) and np.where(df["STATE"] == Z)
1 голос
/ 18 июня 2020

Используйте:

print (df_coord)
   OWNER_ZIP         CITY STATE
0      71937         Cove    AR
1      72044     Edgemont    AR
2      56171     Sherburn    MN
3        123  MIAMI SHORE    PA
4        789      SEATTLE    AA

print (ca_df)
  OWNER_ZIP   OWNER_CITY OWNER_STATE
0       NaN          NaN         NaN
1     72044     Edgemont          AR
2     56171          NaN          MN
3       NaN  MIAMI SHORE          PA
4       NaN      SEATTLE         NaN

Сначала необходимо проверить, совпадают ли одинаковые типы в столбцах:

#or convert ca_df['OWNER_ZIP'] to integers
df_coord['OWNER_ZIP'] = df_coord['OWNER_ZIP'].astype(str)

print (df_coord.dtypes)
OWNER_ZIP    object
CITY         object
STATE        object
dtype: object

print (ca_df.dtypes)

OWNER_ZIP      object
OWNER_CITY     object
OWNER_STATE    object
dtype: object

Затем отфильтруйте каждую комбинацию столбцов - пропущенные и не пропущенные значения и добавьте новые данные с помощью merge, затем преобразуйте индекс в такой же, как отфильтрованные данные, и назначьте обратно:

mask1 = ca_df['OWNER_CITY'].notna() & ca_df['OWNER_STATE'].notna()  & ca_df['OWNER_ZIP'].isna()
df1 = ca_df[mask1].drop('OWNER_ZIP', axis=1).merge(df_coord.rename(columns={'CITY':'OWNER_CITY','STATE':'OWNER_STATE'})).set_index(ca_df.index[mask1])
ca_df.loc[mask1, ['OWNER_ZIP','OWNER_CITY','OWNER_STATE']] = df1

mask2 = ca_df['OWNER_CITY'].notna() & ca_df['OWNER_STATE'].isna()  & ca_df['OWNER_ZIP'].isna()
df2 = ca_df[mask2].drop(['OWNER_ZIP','OWNER_STATE'], axis=1).merge(df_coord.rename(columns={'CITY':'OWNER_CITY','STATE':'OWNER_STATE'})).set_index(ca_df.index[mask2])
ca_df.loc[mask2, ['OWNER_ZIP','OWNER_CITY','OWNER_STATE']] = df2

mask3 = ca_df['OWNER_CITY'].isna() & ca_df['OWNER_STATE'].notna()  & ca_df['OWNER_ZIP'].notna()
df3 = ca_df[mask3].drop(['OWNER_CITY'], axis=1).merge(df_coord.rename(columns={'CITY':'OWNER_CITY','STATE':'OWNER_STATE'})).set_index(ca_df.index[mask3])
ca_df.loc[mask3, ['OWNER_ZIP','OWNER_CITY','OWNER_STATE']] = df3

print (ca_df)
  OWNER_ZIP   OWNER_CITY OWNER_STATE
0       NaN          NaN         NaN
1     72044     Edgemont          AR
2     56171     Sherburn          MN
3       123  MIAMI SHORE          PA
4       789      SEATTLE          AA
0 голосов
/ 18 июня 2020

Вы можете выполнить левое соединение для этих фреймов данных с учетом объединения столбцов «город» и «штат». Это даст вам почтовый индекс, соответствующий городу и штату, если оба значения не равны нулю в первом фрейме данных (OWNER_CITY, OWNER_STATE, OWNER_ZIP) и, поскольку это будет левое соединение, оно также сохранит ваши строки, которые либо не имеют почтовый индекс или пустые / пустые значения города и штата.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...