Самый быстрый способ объединить 2 строки, чередуя строки из второго столбца в первый по строке на всем фрейме данных - PullRequest
2 голосов
/ 03 июля 2019

Я написал функцию (включающую биты и куски, очищенные от переполнения стека), которая будет перемещаться по кадрам данных по строкам, чередуя строки от col-x до col-y, для всех двух пар столбцов x, y во всех строках .

У меня есть рабочее решение. Проблема в том, что он медленно обрабатывает большие фреймы данных.

Есть ли более быстрый путь?

Я пробовал следующую настройку:

# Import modules
import pandas as pd
from itertools import chain, zip_longest

def interleave_strings(string1, string2):
    tuples = zip_longest(string1, string2, fillvalue='')
    string_list = [''.join(item) for item in tuples]
    return ''.join(string_list)

# Create the pandas DataFrame 
data = [['timy', 'toma', 'tama', 'tima', 'tomy', 'tome'], ['nicka', 'nacka', 'nucka', 'necka', 'nomy', 'nome'], ['julia', 'Julia', 'jalia', 'jilia', 'jomy', 'jome']] 
df = pd.DataFrame(data, columns = ['A', 'B', 'C', 'D', 'E', 'F']) 

df

Это нас заводит ...

    timy    toma    tama    tima    tomy    tome
    nicka   nacka   nucka   necka   nomy    nome
    julia   Julia   jalia   jilia   jomy    jome

И это работает, но медленно ...

# new_df

il_df = pd.DataFrame()
for i in range (int(len(df.columns)/2)):
    selection = df.iloc[:,2*i:2*i+2]
    L = []
    for j in range (len(df.index)):
        res = interleave_strings(selection.iloc[j,0], selection.iloc[j,1])

        L.append(res)
        S = pd.Series(L)
    #il_df = pd.concat(D, ignore_index=True)   
    il_df = il_df.append(S, ignore_index=True)

А с

il_df.transpose()

Правильный вывод:

    0           1           2
0   ttiommya    ttaimmaa    ttoommye
1   nniacckkaa  nnuecckkaa  nnoommye
2   jJuulliiaa  jjailliiaa  jjoommye

Ответы [ 2 ]

0 голосов
/ 04 июля 2019

Мы можем сделать это в два этапа. Сначала создайте новый фрейм, содержащий все перестановки (x, y), а затем примените функцию для чередования строк элемента нового фрейма.

  >>>import pandas as pd
  >>>import itertools
  >>>df
  Out[61]: 
         A      B      C      D     E     F
  0   timy   toma   tama   tima  tomy  tome
  1  nicka  nacka  nucka  necka  nomy  nome
  2  julia  Julia  jalia  jilia  jomy  jome

  >>>df_permute = df.apply(lambda x: pd.Series(list(itertools.permutations(x, 2))), axis=1)
  >>>df_permute
  Out[66]: 
                 0               1       ...                  28            29
  0    (timy, toma)    (timy, tama)      ...        (tome, tima)  (tome, tomy)
  1  (nicka, nacka)  (nicka, nucka)      ...       (nome, necka)  (nome, nomy)
  2  (julia, Julia)  (julia, jalia)      ...       (jome, jilia)  (jome, jomy)
  [3 rows x 30 columns]

  >>>def foo(x, y):
  ...  """Interleave string x, and y"""
  ...  return ''.join(p for p in itertools.chain(*izip_longest(x, y)) if p)
  ...

  >>> df_permute.applymap(lambda x: foo(*x))
  Out[68]: 
             0           1           2     ...            27         28        29
  0    ttiommya    ttiammya    ttiimmya    ...      ttoammea   ttoimmea  ttoommey
  1  nniacckkaa  nniucckkaa  nniecckkaa    ...     nnoumceka  nnoemceka  nnoommey
  2  jJuulliiaa  jjualliiaa  jjuilliiaa    ...     jjoamleia  jjoimleia  jjoommey
  [3 rows x 30 columns]
0 голосов
/ 04 июля 2019

Мы можем использовать groupby для каждой пары двух столбцов над axis=1 (читай: ось столбца).

Как и ваше собственное решение, мы используем чередование:

from toolz import interleave

m = [x//2 for x in range(len(df.columns))]

df = df.groupby(m, axis=1).apply(lambda x: [''.join(interleave(t)) for t in zip(x.iloc[:, 0], x.iloc[:, 1])])

df = pd.DataFrame(df.to_numpy().tolist(), columns = df.index).T

выход

            0           1         2
0    ttiommya    ttaimmaa  ttoommye
1  nniacckkaa  nnuecckkaa  nnoommye
2  jJuulliiaa  jjailliiaa  jjoommye

Примечание Если ваша версия для панд <<code>0.24, используйте .values вместо .to_numpy

df = pd.DataFrame(df.values.tolist(), columns = df.index).T
...