python pandas numpy

python - dividir una columna numérica de seis dígitos en columnas separadas con un dígito



pandas numpy (8)

¡Conviértelo primero en una cuerda!

Además, se incluye un zfill por si no todos los números son de 6 dígitos

dat = [list(map(int, str(x).zfill(6))) for x in df.Number] d = pd.DataFrame(dat, df.index).rename(columns=lambda x: f''x{x + 1}'') df.join(d) Number x1 x2 x3 x4 x5 x6 0 654321 6 5 4 3 2 1 1 223344 2 2 3 3 4 4

Detalles

Esto obtiene los dígitos

dat = [list(map(int, str(x).zfill(6))) for x in df.Number] dat [[6, 5, 4, 3, 2, 1], [2, 2, 3, 3, 4, 4]]

Esto crea un nuevo marco de datos con el mismo índice que df Y renombra las columnas para tener una ''x'' al frente y comenzar con ''x1'' y no ''x0''

d = pd.DataFrame(dat, df.index).rename(columns=lambda x: f''x{x + 1}'') d x1 x2 x3 x4 x5 x6 0 6 5 4 3 2 1 1 2 2 3 3 4 4

¿Cómo puedo usar pandas o numpy separar una columna de 6 dígitos enteros en 6 columnas con un dígito cada una?

import pandas as pd import numpy as np df = pd.Series(range(123456,123465)) df = pd.DataFrame(df) df.head()

lo que tengo es como este a continuación

Number 654321 223344

El resultado deseado debe ser como este a continuación.

Number | x1 | x2 | x3 | x4 | x5 | x6 | 654321 | 6 | 5 | 4 | 3 | 2 | 1 | 223344 | 2 | 2 | 3 | 3 | 4 | 4 |


MCVE

Aquí hay una sugerencia simple:

import pandas as pd # MCVE dataframe: df = pd.DataFrame([123456, 456789, 135797, 123, 123456789], columns=[''number'']) def digit(x, n): """Return the n-th digit of integer in base 10""" return (x // 10**n) % 10 def digitize(df, key, n): """Extract n less significant digits from an integer in base 10""" for i in range(n): df[''x%d'' % i] = digit(df[key], n-i-1) # Apply function on dataframe (inplace): digitize(df, ''number'', 6)

Para el marco de datos de prueba, devuelve:

number x0 x1 x2 x3 x4 x5 0 123456 1 2 3 4 5 6 1 456789 4 5 6 7 8 9 2 135797 1 3 5 7 9 7 3 123 0 0 0 1 2 3 4 123456789 4 5 6 7 8 9

Observaciones

Este método evita la necesidad de convertir en string y luego volver a int a int .

Se basa en aritmética de enteros modulares, debajo de los detalles de las operaciones:

10**3 # int: 1000 (integer power) 54321 // 10**3 # int: 54 (quotient of integer division) (54321 // 10**3) % 10 # int: 4 (remainder of integer division, modulo)

Por último, pero no menos importante, es seguro y exacto para un número menor de n dígitos o mayor que (observe que devuelve los n dígitos menos significativos en el último caso).


Manera simple de evitar:

>>> df number 0 123456 1 456789 2 135797

Primero convierta la columna en cadena

>>> df[''number''] = df[''number''].astype(str)

Cree las nuevas columnas usando indexación de cadenas

>>> df[''x1''] = df[''number''].str[0] >>> df[''x2''] = df[''number''].str[1] >>> df[''x3''] = df[''number''].str[2] >>> df[''x4''] = df[''number''].str[3] >>> df[''x5''] = df[''number''].str[4] >>> df[''x6''] = df[''number''].str[5] >>> df number x1 x2 x3 x4 x5 x6 0 123456 1 2 3 4 5 6 1 456789 4 5 6 7 8 9 2 135797 1 3 5 7 9 7 >>> df.drop(''number'', axis=1, inplace=True) >>> df x1 x2 x3 x4 x5 x6 0 1 2 3 4 5 6 1 4 5 6 7 8 9 2 1 3 5 7 9 7

@ otro truco con str.split()

>>> df = df[''number''].str.split(''(/d{1})'', expand=True).add_prefix(''x'').drop(columns=[''x0'', ''x2'', ''x4'', ''x6'', ''x8'', ''x10'', ''x12'']) >>> df x1 x3 x5 x7 x9 x11 0 1 2 3 4 5 6 1 4 5 6 7 8 9 2 1 3 5 7 9 7 >>> df.rename(columns={''x3'':''x2'', ''x5'':''x3'', ''x7'':''x4'', ''x9'':''x5'', ''x11'':''x6''}) x1 x2 x3 x4 x5 x6 0 1 2 3 4 5 6 1 4 5 6 7 8 9 2 1 3 5 7 9 7

O

>>> df = df[''number''].str.split(r''(/d{1})'', expand=True).T.replace('''', np.nan).dropna().T >>> df 1 3 5 7 9 11 0 1 2 3 4 5 6 1 4 5 6 7 8 9 2 1 3 5 7 9 7 >>> df.rename(columns={1:''x1'', 3:''x2'', 5:''x3'', 7:''x4'', 9:''x5'', 11:''x6''}) x1 x2 x3 x4 x5 x6 0 1 2 3 4 5 6 1 4 5 6 7 8 9 2 1 3 5 7 9 7


Podrías usar np.unravel_index

df = pd.DataFrame({''Number'': [654321,223344]}) def split_digits(df): # get data as numpy array numbers = df[''Number''].to_numpy() # extract digits digits = np.unravel_index(numbers, 6*(10,)) # create column headers columns = [''Number'', *(f''x{i}'' for i in "123456")] # build and return new data frame return pd.DataFrame(np.stack([numbers, *digits], axis=1), columns=columns, index=df.index) split_digits(df) # Number x1 x2 x3 x4 x5 x6 # 0 654321 6 5 4 3 2 1 # 1 223344 2 2 3 3 4 4 timeit(lambda:split_digits(df),number=1000) # 0.3550272472202778

Gracias @ GZ0 por algunos consejos sobre pandas .


Realmente me gustó la respuesta de @ user3483203. Creo que .str.findall podría funcionar con cualquier número de dígitos:

df = pd.DataFrame({ ''Number'' : [65432178888, 22334474343] }) u = df[''Number''].astype(str).str.findall(r''(/w)'') df.join(pd.DataFrame(list(u)).rename(columns=lambda c: f''x{c+1}'')).apply(pd.to_numeric)

Number x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 0 65432178888 6 5 4 3 2 1 7 8 8 8 8 1 22334474343 2 2 3 3 4 4 7 4 3 4 3


Si bien las soluciones basadas en cadenas son más simples y probablemente lo suficientemente buenas en la mayoría de los casos, puede hacerlo con las matemáticas que, si tiene un gran conjunto de datos, pueden marcar una diferencia significativa en la velocidad.

import numpy as np import pandas as pd df = pd.DataFrame({''Number'': [654321, 223344]}) num_cols = int(np.log10(df[''Number''].max() - 1)) + 1 vals = (df[''Number''].values[:, np.newaxis] // (10 ** np.arange(num_cols - 1, -1, -1))) % 10 df_digits = pd.DataFrame(vals, columns=[f''x{i + 1}'' for i in range(num_cols) df2 = pd.concat([df, df_digits])], axis=1) print(df2) # Number x1 x2 x3 x4 x5 x6 # 0 654321 6 5 4 3 2 1 # 1 223344 2 2 3 3 4 4


Suponiendo que todos los números tienen la misma longitud (tienen el mismo número de dígitos), lo haría de la siguiente manera usando numpy :

import numpy as np a = np.array([[654321],[223344]]) str_a = a.astype(str) out = np.apply_along_axis(lambda x:list(x[0]),1,str_a) print(out)

Salida:

[[''6'' ''5'' ''4'' ''3'' ''2'' ''1''] [''2'' ''2'' ''3'' ''3'' ''4'' ''4'']]

Tenga en cuenta que out es actualmente np.array de str s, puede convertirlo en int si es necesario.


Un poco de diversión con vistas, suponiendo que cada número tenga 6 dígitos:

u = df[[''Number'']].to_numpy().astype(''U6'').view(''U1'').astype(int) df.join(pd.DataFrame(u).rename(columns=lambda c: f''x{c+1}''))

Number x1 x2 x3 x4 x5 x6 0 654321 6 5 4 3 2 1 1 223344 2 2 3 3 4 4