Я хотел бы работать с кадром данных pandas, чтобы получить странный, но желаемый выходной фрейм данных. Для каждой строки я бы хотел, чтобы любые значения 0,0 были заменены пустой строкой (''), а все значения 1,0 заменены значением индекса. Любое заданное значение в строке может быть только 1,0 или 0,0.
Вот некоторые примеры данных:
# starting df
df = pd.DataFrame.from_dict({'A':[1.0,0.0,0.0],'B':[1.0,1.0,0.0],'C':[0.0,1.0,1.0]})
df.index=['x','y','z']
print(df)
Как выглядит ввод df:
A B C
x 1.0 1.0 0.0
y 0.0 1.0 1.0
z 0.0 0.0 1.0
Как бы я хотел, чтобы вывод df выглядел так:
A B C
x x x
y y y
z z
Пока у меня есть этот довольно неэффективный, но, казалось бы, рабочий код:
for idx in df.index:
df.loc[idx] = df.loc[idx].map(str).replace('1.0',str(idx))
df.loc[idx] = df.loc[idx].map(str).replace('0.0','')
Может ли кто-нибудь предложить эффективный способ сделать это?
Реальный фрейм данных, с которым я буду работать, имеет форму (4548, 2044), а значения всегда будут плавающими (1,0 или 0,0), как в примере. Я манипулирую данными usher_barcodes.csv из «raw.githubusercontent.com/andersen-lab/Freyja/main/freyja/data/…» в формат, требуемый другим конвейером, где заголовки столбцов являются именами родословных, а значения мутации (взято из указателя). Заголовки столбцов и значения индексов, вероятно, будут разными каждый раз, когда мне нужно запустить этот код, потому что назначения происхождения постоянно меняются.
Спасибо!
Значения фрейма данных всегда будут с плавающей запятой (1,0 или 0,0), как в примере. Я манипулирую данными usher_barcodes.csv из «raw.githubusercontent.com/andersen-lab/Freyja/main/freyja/data/…» в формат, требуемый другим конвейером, где заголовки столбцов являются родословными имена и значения являются мутациями (взятыми из индекса).
Frustrated_bioinformatician: хорошо, пожалуйста, отредактируйте этот контекст в вопросе. Я рекомендую вам не заменять одно значение на (строковое) значение индекса, покажите нам следующее вычисление, давайте выясним, как получить доступ к значениям индекса (например, посмотрите на df.to_records()). В конечном счете, я предполагаю, что он используется только в каком-то строковом формате; но есть и другие способы реализовать это, поэтому, вероятно, лучше хранить их как единицы/нули.
Спасибо за ваши предложения. Хорошо это или плохо, конвейер принимает в качестве входных данных файл CSV, где каждый столбец содержит диагностические мутации для каждой интересующей линии (заголовки столбцов). По своей природе не все столбцы имеют одинаковое количество значений, и формат 1.0/0.0 не будет принят. Вот как выглядит лист мутаций тестового ввода: raw.githubusercontent.com/BIMSBbioinfo/pigx_sars-cov-2/main/…
Вы можете просто сделать:
for idx, row in df.iterrows():
df.loc[idx] = ['' if val == 0 else idx for val in row]
Который дает:
A B C
x x x
y y y
z z
Используйте numpy.where с преобразованием индекса вещания в массив numpy:
df = pd.DataFrame(np.where(df.eq(1),
df.index.to_numpy()[:, None],
''),
index = df.index,
columns = df.columns)
print(df)
A B C
x x x
y y y
z z
Производительность с данными по размеру (4548,2044):
np.random.seed(2023)
df = pd.DataFrame(np.random.choice([0.0,1.0], size=(4548,2044))).add_prefix('c')
df.index = df.index.astype(str) + 'r'
# print (df)
In [87]: %timeit df.eq(1).mul(df.index, axis=0)
684 ms ± 36.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [90]: %timeit pd.DataFrame(np.where(df.eq(1),df.index.to_numpy()[:, None],''),index = df.index, columns = df.columns)
449 ms ± 26.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Воспользуйтесь тем, что 1*'x' -> 'x' и 0*'x' -> '':
out = df.eq(1).mul(df.index, axis=0)
NB. eq(1) преобразует число с плавающей запятой в логическое, поскольку True эквивалентно 1. Вы также можете использовать astype(int), если у вас есть только 0./1..
Выход:
A B C
x x x
y y y
z z
Хорошо, но почему? Какую более широкую проблему вы решаете? Что представляет собой фрейм данных 4548x2044? Продажи? Генетика? И являются ли ваши значения dataframe логическими, плавающими или строковыми? Не сообщая нам контекст, это проблема XY