фильтрация панд по частичным строковым значениям по ряду столбцов

1

Недавно я начал работать с пандами, и я наткнулся на (вероятно, тривиальную) проблему, которую я не могу решить. Чтобы сделать это в чистом сценарии Python, я действительно хочу его в пандах. Вот мой вопрос новобранец.

Имея блок данных ниже:

 ID Sample1 quality1    Sample2 quality2    Sample3 quality3
ID1 val str1,str2,str3@num  val str1,str2,str3@num  val str1,str2,str3@num
ID2 val str4,str5,str63@num val str4,str5,st63@num  val str4,str5,str63@num
ID3 val str1,str2,str3@num  val str1,str1,str3@num  val str4,str2,str3@num
ID4 val str1,str2,str3@num  val str2,str2,str3@num  val str1,str2,str3@num
ID5 val str4,str5,str63@num val str4,str5,st63@num  val str4,str5,str63@num

Я хочу написать функцию, чтобы сохранить только строки, которые имеют минимально необходимое количество показателей качества по n столбцам. На самом деле важна только первая часть строки, поэтому сначала выберите только первую часть строки:

 ID Sample1 quality1    Sample2 quality2    Sample3 quality3
ID1 val str1    val str1    val str1
ID2 val str4    val str4    val str4
ID3 val str1    val str1    val str4
ID4 val str1    val str2    val str1
ID5 val str4    val str3    val str4

Предположим, что я хочу сохранить строки с минимальным счетом "str4" в двух столбцах, я бы, вероятно, вычислил процент по столбцам:

 ID Sample1 quality1    Sample2 quality2    Sample3 quality3
ID2 val str4    val str4    val str4
ID5 val str4    val str3    val str4

Вот как я начал играть с ним, чтобы знать, где все происходит, но я все еще не могу собрать вещи вместе:

for i,rows in enumerate(table_test.values):
    min_val = "str4"
    scores = rows[2::2]
    lists = np.ndarray.tolist(scores)
    for list in lists:
        first_str = list.split(",")
        print(i, first_str[0])

Спасибо за мысли и/или помощь!

Теги:
pandas
filtering

1 ответ

1
Лучший ответ

Используйте boolean indexing для фильтрации с булевой маской:

min_val = "str4"
df = df[df.filter(like='quality').apply(lambda x: x.str.startswith(min_val)).sum(axis=1) >= 2]
print (df)
    ID Sample1             quality1 Sample2            quality2 Sample3  \
1  ID2     val  str4,str5,str63@num     val  str4,str5,st63@num     val   
4  ID5     val  str4,str5,str63@num     val  str4,str5,st63@num     val   

              quality3  
1  str4,str5,str63@num  
4  str4,str5,str63@num  

Или же:

min_val = "str4"
df = df[df.filter(like='quality').applymap(lambda x: x.startswith(min_val)).sum(axis=1) >= 2]
print (df)
    ID Sample1             quality1 Sample2            quality2 Sample3  \
1  ID2     val  str4,str5,str63@num     val  str4,str5,st63@num     val   
4  ID5     val  str4,str5,str63@num     val  str4,str5,st63@num     val   

              quality3  
1  str4,str5,str63@num  
4  str4,str5,str63@num  

Объяснение:

Сначала filter все столбцы с строкой quality:

print (df.filter(like='quality'))
              quality1            quality2             quality3
0   str1,str2,str3@num  str1,str2,str3@num   str1,str2,str3@num
1  str4,str5,str63@num  str4,str5,st63@num  str4,str5,str63@num
2   str1,str2,str3@num  str1,str1,str3@num   str4,str2,str3@num
3   str1,str2,str3@num  str2,str2,str3@num   str1,str2,str3@num
4  str4,str5,str63@num  str4,str5,st63@num  str4,str5,str63@num

Сравните все столбцы с помощью startswith для boolean DataFrame:

print (df.filter(like='quality').apply(lambda x: x.str.startswith(min_val)))
   quality1  quality2  quality3
0     False     False     False
1      True      True      True
2     False     False      True
3     False     False     False
4      True      True      True

Count True значения по sum - True - это процессы, такие как 1 с:

print (df.filter(like='quality').apply(lambda x: x.str.startswith(min_val)).sum(axis=1))
0    0
1    3
2    1
3    0
4    3
dtype: int64

Сравнить по treshold:

print (df.filter(like='quality').apply(lambda x: x.str.startswith(min_val)).sum(axis=1) >=2)
0    False
1     True
2    False
3    False
4     True
dtype: bool

Если хотите также разделять столбцы quality сначала split все столбцы quality и назначать обратно:

min_val = "str4"
cols = df.filter(like='quality').columns

df[cols] = df[cols].apply(lambda x: x.str.split(',').str[0])
#another solution
#df[cols] = df[cols].applymap(lambda x: x.split(',')[0])
print (df)
    ID Sample1 quality1 Sample2 quality2 Sample3 quality3
0  ID1     val     str1     val     str1     val     str1
1  ID2     val     str4     val     str4     val     str4
2  ID3     val     str1     val     str1     val     str4
3  ID4     val     str1     val     str2     val     str1
4  ID5     val     str4     val     str4     val     str4

Затем сравните с помощью min_val для логического DataFrame и фильтруйте так же, как и раньше:

df = df[(df[cols] == min_val).sum(axis=1) >=2]
print (df)
    ID Sample1 quality1 Sample2 quality2 Sample3 quality3
1  ID2     val     str4     val     str4     val     str4
4  ID5     val     str4     val     str4     val     str4
  • 0
    Фантастика, большое спасибо!
  • 0
    @sbajew - Добро пожаловать! Если мой ответ был полезным, не забудьте принять его - нажмите на флажок рядом с ответом, чтобы переключить его с серого на заполненный. Спасибо.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню