возвращает пол по стране из моего фрейма данных

#python #pandas

#python #pandas

Вопрос:

У меня есть фрейм данных следующим образом:

 name   country    gender
wang    ca         1
jay     us         1
jay     ca         0
jay     ca         1
lisa    en         0
lisa    us         1
  

Я хочу назначить пол на основе кода ‘US’. Если имя такое же, то весь пол должен совпадать с полом, присвоенным code us. Для имени, которое не имеет дубликатов, мы возвращаем ту же строку.

Возвращаемый результат должен быть

 name    code   gender
wang     ca     1
jay      us     1
lisa     us     1
  

Я использовал

 df.gropuby(['name', 'country'])['gender'].transform()
  

Есть предложения о том, как это исправить?

Комментарии:

1. есть ли только одна строка для каждого имени / страны? Если нет, то как вы хотите определить пол?

2. если «страна» — это США, и есть повторяющиеся имена, весь пол соответствует полу США. Если повторяющихся имен нет, строка остается.

Ответ №1:

 # Get country and gender in separate lists for a name
a = df.groupby('name')['country'].apply(list).reset_index(name='country_list')
b = df.groupby('name')['gender'].apply(list).reset_index(name='gender_list')

# Merge 
df2 = a.merge(b, on='name', how='left')

# Using apply get final required values
def get_val(x):
    cl, gl = x
    final = [cl[0], gl[0]]
    for c,g in zip(cl,gl):
        if c=='us':
            final.append(c)
            final.append(g)
    return final

df2['final_col'] = df2[['country_list', 'gender_list']].apply(get_val, axis=1) 
df2['code'] = df2['final_col'].apply(lambda l: l[0])
df2['gender'] = df2['final_col'].apply(lambda l: l[1])
print(df2)

  

Комментарии:

1. Я не sure…as ваша логика для вычисления gender не straightforward..so возможно, вам придется создать свою собственную, используя apply функцию.

Ответ №2:

Подход, который я использовал, — это merge() с последующей условной заменой ( np.where() )

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

 import io
import numpy as np
df = pd.read_csv(io.StringIO("""name   country    gender
wang    ca         1
jay     us         1
jay     ca         0
jay     ca         1
lisa    en         0
lisa    us         1"""), sep="s ")

# use "us" as basis for lookup. left merge on name only
df2 = (df.merge(df.query("country=='us'"), 
          on=["name"], how="left", suffixes=("", "_new"))
 # replace only where it's not "us" and "us" has a different value
 .assign(gender=lambda x: np.where((x["country"]!="us")amp;
                                   (x["gender"]!=x["gender_new"])amp;
                                   ~(x["gender_new"].isna())
                                   # force type casting so it doesn't become float64 because of NaN
                                   , x["gender_new"].fillna(-1).astype("int64"), 
                                    x["gender"]))
 # remove columns inserted by merge...
 .drop(columns=["country_new", "gender_new"])
)

  

вывод

  name country  gender
 wang      ca       1
  jay      us       1
  jay      ca       1
  jay      ca       1
 lisa      en       1
 lisa      us       1

  

Комментарии:

1. это однострочный… Я разделил на несколько строк для удобства чтения. отсутствие цикла плюс очень защитные условия, гарантирующие, что он всегда будет работать.