簡體   English   中英

將六位數字列拆分為一個數字的分隔列

[英]split a six digits number column into separated columns with one digit

如何使用pandas或numpy將一列6位整數分成6列,每列一位?

import pandas as pd
import numpy as np

df = pd.Series(range(123456,123465))

df = pd.DataFrame(df)


df.head()

我所擁有的就像下面的這個

Number
654321
223344

期望的結果應該如下所示。

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

MCVE

這是一個簡單的建議:

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)

對於試用數據框,它返回:

      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

意見

此方法避免了轉換為string然后再次轉換為int

它依賴於模塊化整數運算,操作細節如下:

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)

最后但並非最不重要的是,對於短於n位或大於的數字,它是故障安全且准確的(注意它在后一種情況下返回n較低有效數字)。

一些有趣的觀點,假設每個數字有6位數:


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

你可以使用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

感謝@ GZ0的一些pandas提示。

先把它變成一個字符串!

此外,還包括一個zfill ,以防萬一並非所有數字都是6位數

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

細節

這得到數字

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]]

這將創建具有相同指數作為一個新的數據幀df 並將其重命名列有一個'x'在前面,並與開始'x1' ,而不是'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

雖然基於字符串的解決方案更簡單,並且在大多數情況下可能已經足夠好了,但您可以使用數學執行此操作,如果您擁有大數據集,則可以在速度方面產生顯着差異。

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

假設所有數字都具有相同的長度(具有相同的位數),我會按照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)

輸出:

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

請注意, out當前是strnp.array ,如果需要,可以將其轉換為int

我真的很喜歡@ user3483203的回答。 我認為.str.findall可以使用任意數量的數字:

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

簡單的方法:

>>> df
   number
0  123456
1  456789
2  135797

首先將列轉換為字符串

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

使用字符串索引創建新列

>>> 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

使用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

要么

>>> 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM