7
votes

Comment trouver l'index d'une valeur par ligne dans un dataframe en python et extraire la valeur de la colonne suivante

J'ai le dataframe suivant utilisant des pandas

df = pd.DataFrame({'Last_Name': ['Smith', None, 'Brown'], 
                   'Date0': ['01/01/1999','01/06/1999','01/01/1979'], 'Age0': [29,44,21],
                   'Date1': ['08/01/1999','07/01/2014','01/01/2016'],'Age1': [35, 45, 47],
                   'Date2': [None,'01/06/2035','08/01/1979'],'Age2': [47, None, 74],
                   'Last_age': [47,45,74],
                   'Last_age_date': ['Error no date','07/01/2014','08/01/1979']})

Je voudrais ajouter une nouvelle colonne pour obtenir la date correspondant à la valeur présente dans 'Last_age' pour chaque ligne pour obtenir quelque chose comme ça:

df = pd.DataFrame({'Last_Name': ['Smith', None, 'Brown'], 
                   'Date0': ['01/01/1999','01/06/1999','01/01/1979'], 'Age0': [29,44,21],
                   'Date1': ['08/01/1999','07/01/2014','01/01/2016'],'Age1': [35, 45, 47],
                   'Date2': [None,'01/06/2035','08/01/1979'],'Age2': [47, None, 74],
                   'Last_age': [47,45,74]})


0 commentaires

3 Réponses :


1
votes

Quelque chose comme ceci devrait faire ce que vous recherchez:

# get the age and column rows (you might have more than just the 2)
age_columns = [c for c in df.columns if 'Age' in c][::-1]
date_columns = [c for c in df.columns if 'Date' in c][::-1]

def get_last_age_date(row):
    for age, date in zip(age_columns, date_columns):
        if not np.isnan(row[age]):
            return row[date]
    return np.nan

# apply the function to all the rows in the dataframe
df['Last_age_date'] = df.apply(lambda row: get_last_age_date(row), axis=1)

# fix the NaN values to say 'Error no date'
df.Last_age_date.where(~df.Last_age_date.isna(), 'Error no date', inplace=True)
print(df)


4 commentaires

Merci ça marche. Puis-je demander comment fonctionne la fonction? Je comprends que j'obtiens deux listes (une pour l'âge et une pour la date) que vous vérifiez si la valeur de la ligne [age] est nulle ou non et sinon vous obtenez la date. Mais je ne comprends pas comment vous obtenez la bonne date.


vous pouvez simplement obtenir les colonnes Date et Age en faisant df.filter (regex = 'Date | Age')


Désolé, je veux dire que je ne comprends pas comment vous obtenez la bonne date dans votre code. La fonction zip prend-elle les premiers éléments de chaque liste, puis le second et ainsi de suite?


Non. zip est un générateur très pratique qui trouve les éléments correspondants dans les listes adjacentes. Donc list1 = [1,2,3,4] et list2 = [a, b, c, d] puis zip (list1, list2) = [ (1, a), (2, b), (3, c), (4, d)] . La correspondance réelle se produit dans l'instruction if . Il dit, si je trouve un age et que la valeur n'est pas None, alors renvoie la date correspondante. Si je ne trouve rien (la dernière ligne de la fonction), retournez NaN.



0
votes

Bienvenue dans Stackoverflow! Vous pouvez écrire une petite fonction et y parvenir. Votre trame de données d'entrée ressemble à ceci.

def last_Age(row):
    if row['Last_age'] == row['Age2']:
        return row['Date2']
    elif row['Last_age'] == row['Age1']:
        return row['Date1']
    elif row['Last_age'] == row['Age0']:
        return row['Date0']
df['Last_age_date']=df.apply(last_Age, axis = 1)
df
   Last_Name       Date0  Age0       Date1  Age1       Date2  Age2  Last_age  Last_age_date
 0     Smith  01/01/1999    29  08/01/1999    35        None  47.0        47          None
 1      None  01/06/1999    44  07/01/2014    45  01/06/2035   NaN        45    07/01/2014
 2     Brown  01/01/1979    21  01/01/2016    47  08/01/1979  74.0        74    08/01/1979

Écrivez une fonction comme celle-ci:

df
        Last_Name       Date0  Age0       Date1  Age1       Date2  Age2  Last_age
      0     Smith  01/01/1999    29  08/01/1999    35        None  47.0        47
      1      None  01/06/1999    44  07/01/2014    45  01/06/2035   NaN        45
      2     Brown  01/01/1979    21  01/01/2016    47  08/01/1979  74.0        74


0 commentaires

3
votes

Je vais simplement utiliser wide_to_long pour remodeler votre df

s=pd.wide_to_long(df.reset_index(),['Date','Age'],i=['Last_age','index'],j='Drop')
s.loc[s.Age==s.index.get_level_values(0),'Date']
Out[199]: 
Last_age  index  Drop
47        0      2             None
45        1      1       07/01/2014
74        2      2       08/01/1979
Name: Date, dtype: object
df['Last_age_date']=s.loc[s.Age==s.index.get_level_values(0),'Date'].values
df
Out[201]: 
  Last_Name       Date0  Age0      ...       Age2  Last_age Last_age_date
0     Smith  01/01/1999    29      ...       47.0        47          None
1      None  01/06/1999    44      ...        NaN        45    07/01/2014
2     Brown  01/01/1979    21      ...       74.0        74    08/01/1979
[3 rows x 9 columns]


2 commentaires

cela devrait être plus élevé car c'est la seule approche vectorisée parmi toutes les réponses


@JohnJohn regarde d'abord wide_to_long pandas.pydata.org/ pandas-docs / stable / reference / api /…