3 votes

Vérifier si une série de chiffres se trouve entre deux colonnes dans un cadre de données pandas.

J'essaie de classer les emplacements génomiques, et j'ai un DataFrame comme le suivant, avec tous les emplacements et leurs types de classification respectifs. Le site Type n'a pas de classifications uniques, mais chaque rangée aura une combinaison unique de Chr , Low , High .

pd.DataFrame({
    'Chr':[1,1,3],
    'Low':[100,200,300],
    'High':[150,250,350],
    'Type':['Foo','Bar','Foo']
})

J'ai ensuite mon jeu d'échantillons qui doit être classé comme le DataFrame ci-dessous.

pd.DataFrame({
    'Chr':[1,1,5],
    'Loc':[125,325,325]
})

Pour classer les données, pour chaque emplacement dans l'ensemble d'échantillons, la position du chromosome trouvée dans l'ensemble d'échantillons est utilisée. Chr doit correspondre à une colonne Chr trouvée dans le DataFrame de référence et la valeur Loc doit être >= el Low valeur et <= el High valeur. Si c'est le cas, cette ligne doit alors être étiquetée avec la valeur respective de Type dans le DataFrame de référence. Dans l'exemple que je fournis, l'ensemble d'échantillons devrait être étiqueté comme suit.

pd.DataFrame({
    'Chr':[1,1,5],
    'Loc':[125,325,325],
    'Type':['Foo','None','None']
})

ce qui ressemble à :

   Chr  Loc  Type
0    1  125   Foo
1    1  325  None
2    5  325  None

2voto

Manlai A Points 1176

Vous pourriez merge les deux sur "Chr". Ensuite, sur la DataFrame fusionnée, regardez si "Loc" se situe entre "Low" et "High" et utilisez where pour remplir "Type" avec des valeurs NaN si ce n'est pas le cas. Enfin, supprimez les colonnes non pertinentes et les lignes en double :

merged = sample.merge(df, on='Chr', how='left')
merged['Type'] = merged['Type'].where(merged['Loc'].between(merged['Low'], merged['High']))
out = merged.drop(columns=['Low','High']).drop_duplicates(subset=['Chr','Loc'])

Sortie :

   Chr  Loc Type
0    1  125  Foo
2    1  325  NaN
4    5  325  NaN

1voto

JANO Points 139

Vous pouvez essayer apply() pour vérifier pour chaque ligne si les conditions retournent un Type así:

# Create your data frames
cat = pd.DataFrame({
    'Chr':[1,1,3],
    'Low':[100,200,300],
    'High':[150,250,350],
    'Type':['Foo','Bar','Foo']
})
test = pd.DataFrame({
    'Chr':[1,1,5],
    'Loc':[125,325,325]
})

# Check if there is type for each row
test['Type'] = test.apply(lambda x: cat[(cat['Chr']==x['Chr']) & (cat['Low'] < x['Loc']) & (cat['High'] > x['Loc'])]['Type'], axis=1)

test

Sortie :

    Chr Loc Type
0   1   125 Foo
1   1   325 NaN
2   5   325 NaN

1voto

Daniel Seger Points 111

Vous pouvez essayer ceci :

df2 = df2.assign(Type=None)

for l in df2["Loc"]:
    i = list(df2["Loc"]).index(l)
    if df1["Low"][i] < l < df1["High"][i]:
        df2["Type"][i] = df1["Type"][i]

Sortie :

   Chr  Loc  Type
0    1  125   Foo
1    1  325  None
2    5  325  None

0voto

Je ne comprends pas bien les exigences de votre question, comme indiqué dans un commentaire sur la question ci-dessus. Cependant, si la solution actuellement acceptée qui vérifie uniquement les conditions que vous avez spécifiées ligne par ligne, alors je pense que c'est une meilleure solution :

df1 = pd.DataFrame({
    'Chr':[1,1,3],
    'Low':[100,200,300],
    'High':[150,250,350],
    'Type':['Foo','Bar','Foo']
})
df2 = pd.DataFrame({
    'Chr':[1,1,5],
    'Loc':[125,325,325]
})
mask = (df2['Chr']==df1['Chr'])&(df2['Loc']>=df1['Low'])&(df2['Loc']<=df1['High'])
df2.loc[mask, 'Type'] = df1.loc[mask, 'Type']

Sortie :

enter image description here

Si l'exigence est de vérifier chaque valeur de 'Chr' dans le cadre de données de l'échantillon avec TOUTES les lignes du cadre de données de la classification, df1 qui correspondent à la 'Chr' alors c'est un peu plus compliqué et je peux mettre à jour cette réponse en conséquence, mais je pense que la solution de @enke gère ce cas correctement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X