Панды: новый столбец с использованием данных из нескольких других файлов - PullRequest
2 голосов
/ 24 сентября 2019

Я хотел бы добавить новый столбец в pandas dataframe df, заполненный данными, находящимися во многих других файлах.

Скажите, что мой df выглядит следующим образом:

Sample   Pos
A        5602
A        3069483
B        51948
C        231

И у меня есть три файла A_depth-file.txt, B_depth-file.txt, C_depth-file.txt, как это (показывает A_depth-file.txt):

Pos          Depth
1            31
2            33
3            31
...          ...
5602         52
...          ...
3069483      40

В желаемом выводе df будет новый столбец Depth следующим образом:

Sample   Pos        Depth
A        5602       52
A        3069483    40
B        51948      32
C        231        47

У меня есть метод, который работает, но заполнение df 712 строками занимает около 20 минут, поиск в файлах ~ 4 миллиона строк (= позиции).Кто-нибудь знает лучше / быстрее , чтобы сделать это?

Код, который я использую сейчас:

import pandas as pd
from io import StringIO

with open("mydf.txt") as f:
    next(f)
    List=[]
    for line in f:
        df = pd.read_fwf(StringIO(line), header=None)
        df.rename(columns = {df.columns[1]: "Pos"}, inplace=True)
        f2basename = df.iloc[:, 0].values[0]
        f2 = f2basename + "_depth-file.txt"
        df2 = pd.read_csv(f2, sep='\t')
        df = pd.merge(df, df2, on="Pos", how="left")
        List.append(df)
df = pd.concat(List, sort=False)

with open("mydf.txt") as f:, чтобы открыть файл, к которомуЯ хочу добавить данные

next(f) для передачи заголовка

List=[], чтобы создать новый пустой массив с именем List

for line in f:, чтобы перейти mydf.txt построчно и читая их с помощью df = pd.read_fwf(StringIO(line), header=None)

df.rename(columns = {df.columns[1]: "Pos"}, inplace=True), чтобы переименовать потерянное имя заголовка для столбца Pos, используется позже при объединении строки с соответствующим файлом f2

f2basename = df.iloc[:, 0].values[0] получение базового имени связанного файла f2 на основе 1-го столбца mydf.txt

f2 = f2basename + "_depth-file.txt" для получения полного ассоциированного файла f2 name

df2 = pd.read_csv(f2, sep='\t') для чтения файла f2

df = pd.merge(df, df2, on="Pos", how="left"), чтобы объединить два файла в столбце Pos, добавив столбец Depth к mydf.txt

List.append(df), добавив измененную строку в массив List

df = pd.concat(List, sort=False) для объединения элементов массива List в кадр данных df


Дополнительные примечания

На самом деле, явозможно, придется искатьch не только три файла, но и несколько сотен.

1 Ответ

2 голосов
/ 24 сентября 2019

Я не проверял время выполнения, но должно быть быстрее, если вы прочитаете файл 'mydf.txt' в кадре данных, также используя read_csv, а затем используете groupby и groupby apply .

Если вы заранее знаете, что у вас есть 3 сэмпла и 3 относительных файла, хранящих глубину, вы можете составить словарь для предварительного чтения и сохранения трех соответствующих фреймов данных и использовать их при необходимости.

df = pd.read_csv('mydf.txt', sep='\s+')
files = {basename : pd.read_csv(basename +  "_depth-file.txt", sep='\s+') for basename in ['A', 'B', 'C']}

res = df.groupby('Sample').apply(lambda x : pd.merge(x, files[x.name], on="Pos", how="left"))

Конечный res будет выглядеть следующим образом:

         Sample      Pos  Depth
Sample                         
A      0      A     5602   52.0
       1      A  3069483   40.0
B      0      B    51948    NaN
C      0      C      231    NaN

Имеются значения NaN, потому что я использую предоставленный образец, и у меня нет файлов для B и C (яиспользуется копия A), поэтому значения отсутствуют.При условии, что ваши файлы содержат 'Depth' для каждого 'Pos', вы не должны получать никаких NaN.

. Чтобы избавиться от мультииндекса, созданного с помощью groupby, вы можете сделать:

res.reset_index(drop=True, inplace=True)

и res становится:

  Sample      Pos  Depth
0      A     5602   52.0
1      A  3069483   40.0
2      B    51948    NaN
3      C      231    NaN

РЕДАКТИРОВАТЬ после комментариев

Поскольку у вас много файлов, вы можете использовать следующее решение: та же идея, но она не требуетчитать все файлы заранее.Каждый файл будет прочитан при необходимости.

def merging_depth(x):
    td = pd.read_csv(x.name + "_depth-file.txt", sep='\s+')
    return pd.merge(x, td, on="Pos", how="left")

res = df.groupby('Sample').apply(merging_depth)

Результат тот же.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...