Сортировка фреймов данных, созданных гипотезой, когда кортежи строк имеют разные типы данных

Я хочу создавать фреймы данных, где End больше, чем Start.

Это я делаю с:

from hypothesis.extra.pandas import columns, data_frames, column
import hypothesis.strategies as st

positions = st.integers(min_value=0, max_value=int(1e7))
strands = st.sampled_from("+ -".split())
data_frames(columns=columns(["Start", "End"], dtype=int),
            rows=st.tuples(positions, positions).map(sorted)).example()

который дает

     Start      End
0   589492  6620613
1  5990807  8083222
2   252458  8368032
3  1575938  5763895
4  4689113  9133040
5  7439297  8646668
6   838051  1886133

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

data_frames(columns=columns(["Start", "End", "Strands"], dtype=int),
            rows=st.tuples(positions, positions, strands).map(sorted)).example()

Выдает ошибку

TypeError: '<' not supported between instances of 'str' and 'int'

Это связано с сортировкой кортежей как int, так и strs. Как это исправить?

Я могу спросить гипотезу о создании фрейма данных с pos, pos, strand_int, где strand_int либо 0, либо 1, и преобразовать это в «-» или «+» в тесте, но это выглядит неприятно.


person The Unfun Cat    schedule 31.05.2018    source источник


Ответы (2)


Лучший способ

better_dfs_min = data_frames(index=range_indexes(min_size=better_df_minsize),
                             columns=[column("Chromosome", chromosomes_small),
                                      column("Start", elements=small_lengths),
                                      column("End", elements=small_lengths),
                                      column("Strand", strands)])


@st.composite()
def dfs_min(draw):
    df = draw(better_dfs_min)
    df.loc[:, "End"] += df.Start
    return df

@given(df=dfs_min())
def test_me(df):
    print(df)
    assert 0

Первая попытка:

from hypothesis.extra.pandas import columns, data_frames, column
import hypothesis.strategies as st

def mysort(tp):

    key = [-1, tp[1], tp[2], int(1e10)]

    return [x for _, x in sorted(zip(key, tp))]

positions = st.integers(min_value=0, max_value=int(1e7))
strands = st.sampled_from("+ -".split())
chromosomes = st.sampled_from(elements=["chr{}".format(str(e)) for e in list(range(23)) + "X Y M".split()])

data_frames(columns=columns(["Chromosome", "Start", "End", "Strand"], dtype=int), rows=st.tuples(chromosomes, positions, positions, strands).map(mysort)).example()

Результат:

  Chromosome    Start      End Strand
0      chr13  5660600  6171569      -
1       chrY  3987154  5435816      +
2      chr11  4659655  4956997      +
3      chr14   239357  8566407      +
4       chr3  3200488  9337489      +
5       chr8   304886  1078020      +

Должен быть способ сделать это лучше, чем реализовать свою собственную сортировку ... Моя сортировка зависит от целых чисел в Start и End, которые находятся в диапазоне от 0 до int (1e10) - 1, что кажется неприятным.

person The Unfun Cat    schedule 31.05.2018

Изменять!

Сделайте первую строку вашего теста df.End += df.Start, и конец всегда будет больше, чем start (при условии, что целые положительные числа). Если у вас есть более конкретные ограничения по размеру, опишите end в Гипотезе как желаемое различие, а затем используйте этот трюк.

Вы также можете написать собственную стратегию, используя декоратор @st.composite, который делает это встроенным. ИМО, это того стоит, только если вы используете это для нескольких тестов, но это вопрос стиля, а не содержания.

person Zac Hatfield-Dodds    schedule 01.06.2018
comment
Но стоит ли описывать тестовые данные в тестах? Это кажется таким же хакерским, как и мое решение. Тем не менее, проголосовать за. - person The Unfun Cat; 01.06.2018
comment
Вы также можете написать собственную стратегию, используя декоратор @st.composite, который делает это встроенным. ИМО, это того стоит, только если вы используете это для нескольких тестов, но это вопрос стиля, а не содержания. - person Zac Hatfield-Dodds; 10.06.2018