通过熊猫解析和编辑csv

时间:2018-11-29 16:21:13

标签: python pandas data-science

我试图解析csv文件中代表高度的所有单元格,并将小数点后的内容四舍五入以匹配列表中的数字(四舍五入到最接近的英寸)。在将我的头撞在墙上几天之后,这就是我能够开始工作的编码:

import math
import pandas as pd

inch = [.0, .08, .16, .25, .33, .41, .50, .58, .66, .75, .83, .91, 1]

df = pd.read_csv("sample_csv.csv")


def to_number(s):
    for index, row in df.iterrows():
        try:
            num = float(s)
            num = math.modf(num)
            num = list(num)
            for i,j in enumerate(inch):
                if num[0] < j:
                    num[0] = inch[i-1]
                    break

                elif num[0] == j:
                    num[0] = inch[i]
                    break
            newnum = num[0] + num[1]
            return newnum
        except ValueError:
            return s


df = df.apply(lambda f : to_number(f[0]), axis=1).fillna('')
with open('new.csv', 'a') as f:
    df.to_csv(f, index=False)

理想情况下,我想让它解析带有n个标题的整个CSV,而忽略所有字符串并舍入浮点数以匹配列表。有没有简单的方法可以通过Pandas实现呢?并且是否有可能(或一个好主意?)让它编辑现有的excel工作簿,而不是创建一个我必须复制/粘贴的新csv?

任何帮助或建议都将不胜感激,因为我对Pandas并不陌生,这真是太该死了!

2 个答案:

答案 0 :(得分:2)

如果包含要解析的数据的样本模拟,帮助会容易得多。根据我的理解,要澄清您未指定的要点

  • 通过“带有 n 个标题的整个CSV,忽略所有字符串并舍入浮点数以匹配列表”,您的意思是带有 k的某些 n 列数据帧数字列,每个数字列均以英寸为单位描述某人的身高。
  • 数字列中的条目以英尺为单位进行度量。
  • 您要忽略非数字列,并将数据转换为6.14 -> 6 feet, 1 inches(我隐式地假设通过“向下舍入”,您需要整数底限; ie 6.14英尺是6英尺,0.14 * 12 = 1.68英寸;这是地板面积还是四舍五入到最接近的整数)。

现在,对于以5.1英尺和6.9英尺均匀采样的英尺为单位的随机高度子集,我们可以执行以下操作:

In [1]: import numpy as np

In [2]: import pandas as pd

In [3]: df = pd.DataFrame(np.random.uniform(5.1, 6.9, size=(10,3)))

In [4]: df
Out[4]:
      0         1         2
0  6.020613  6.315707  5.413499
1  5.942232  6.834540  6.761765
2  5.715405  6.162719  6.363224
3  6.416955  6.511843  5.512515
4  6.472462  5.789654  5.270047
5  6.370964  5.509568  6.113121
6  6.353790  6.466489  5.460961
7  6.526039  5.999284  6.617608
8  6.897215  6.016648  5.681619
9  6.886359  5.988068  5.575993

In [5]: np.fix(df) + np.floor(12*(df - np.fix(df)))/12
Out[5]:
      0         1         2
0  6.000000  6.250000  5.333333
1  5.916667  6.833333  6.750000
2  5.666667  6.083333  6.333333
3  6.416667  6.500000  5.500000
4  6.416667  5.750000  5.250000
5  6.333333  5.500000  6.083333
6  6.333333  6.416667  5.416667
7  6.500000  5.916667  6.583333
8  6.833333  6.000000  5.666667
9  6.833333  5.916667  5.500000

我们正在使用np.fix提取高度值的整数部分。同样,df - np.fix(df)表示乘以12时以英尺或英寸为单位的小数余数。np.floor只是将其截断为下面的最接近的英寸,最后除以12所得的测量单位从英寸到英尺

您可以将np.floor更改为np.round,以获得四舍五入到最接近英寸的答案,而不是四舍五入到先前的整个英寸。最后,您可以指定输出的精度,以坚持要求从列表中选择小数部分。

In [6]: (np.fix(df) + np.round(12*(df - np.fix(df)))/12).round(2)
Out[6]:
  0     1     2
0  6.58  5.25  6.33
1  5.17  6.42  5.67
2  6.42  5.83  6.33
3  5.92  5.67  6.33
4  6.83  5.25  6.58
5  5.83  5.50  6.92
6  6.83  6.58  6.25
7  5.83  5.33  6.50
8  5.25  6.00  6.83
9  6.42  5.33  5.08

答案 1 :(得分:0)

添加其他答案以解决字符串问题:

# Break the dataframe with a string
df = pd.DataFrame(np.random.uniform(5.1, 6.9, size=(10,3)))
df.ix[0,0] = 'str'

# Find out which things can be cast to numerics and put NaNs everywhere else
df_safe = df.apply(pd.to_numeric, axis=0, errors="coerce")
df_safe = (np.fix(df_safe) + np.round(12*(df_safe - np.fix(df_safe)))/12).round(2)

# Replace all the NaNs with the original data
df_safe[df_safe.isnull()] = df[df_safe.isnull()]

df_safe应该是您想要的。尽管名称如此,但这并不是特别安全,并且可能存在边缘条件,这将是一个问题。